Location: PHPKode > scripts > Directory Lister > DirectoryLister-2.0.4/resources/DirectoryLister.php
<?php

/**
 * A simple PHP based directory lister that lists the contents
 * of a directory and all it's sub-directories and allows easy
 * navigation of the files within.
 *
 * This software distributed under the MIT License
 * http://www.opensource.org/licenses/mit-license.php
 *
 * More info available at http://www.directorylister.com
 *
 * @author Chris Kankiewicz (http://www.chriskankiewicz.com)
 * @copyright 2012 Chris Kankiewicz
 */
class DirectoryLister {
    
    // Define application version
    const VERSION = '2.0.4';
    
    // Reserve some variables
    protected $_themeName     = NULL;
    protected $_directory     = NULL;
    protected $_appDir        = NULL;
    protected $_appURL        = NULL;
    protected $_config        = NULL;
    protected $_systemMessage = NULL;
    
    
    /**
     * DirectoryLister construct function. Runs on object creation.
     */
    public function __construct() {
        
        // Set class directory constant
        if(!defined('__DIR__')) {
            define('__DIR__', dirname(__FILE__));
        }
        
        // Set application directory
        $this->_appDir = __DIR__;
        
        // Build the application URL
        $this->_appURL = $this->_getAppUrl();
        
        // Load the configuration file
        $configFile = $this->_appDir . '/config.php';
        
        // Set the config array to a global variable
        if (file_exists($configFile)) {
            $this->_config = require_once($configFile);
        } else {
            $this->setSystemMessage('error', '<b>ERROR:</b> Unable to locate application config file');
        }
        
        // Set the theme name
        $this->_themeName = $this->_config['theme_name'];
        
        // Set the directory global variable
        $this->_directory = $this->_setDirecoryPath(@$_GET['dir']);
        
    }
    
    
    /**
     * Creates the directory listing and returns the formatted XHTML
     * 
     * @param string $path Relative path of directory to list
     */
    public function listDirectory($directory = NULL) {
        
        // Set directory varriable if left blank
        if ($directory === NULL) {
            $directory = $this->_directory;
        }
        
        // Get the directory array
        $directoryArray = $this->_readDirectory($directory);

        // Return the array
        return $directoryArray;
    }
    

    /**
     * Description...
     * 
     * @access public
     */
    public function listBreadcrumbs($directory = NULL) {
        
        // Set directory varriable if left blank
        if ($directory === NULL) {
            $directory = $this->_directory;
        }
        
        // Explode the path into an array
        $dirArray = explode('/', $directory);

        // Statically set the Home breadcrumb        
        $breadcrumbsArray[] = array(
            'link' => $this->_appURL,
            'text' => 'Home'
        );
        
        // Generate breadcrumbs
        foreach ($dirArray as $key => $dir) {
            
            if ($dir != '.') {
                
                $dirPath  = NULL;
                
                // Build the directory path
                for ($i = 0; $i <= $key; $i++) {
                    $dirPath = $dirPath . $dirArray[$i] . '/';
                }
                
                // Remove trailing slash
                if(substr($dirPath, -1) == '/') {
                    $dirPath = substr($dirPath, 0, -1);
                }
                
                // Combine the base path and dir path
                $link = $this->_appURL . '?dir=' . urlencode($dirPath);
                
                $breadcrumbsArray[] = array(
                    'link' => $link,
                    'text' => $dir
                );
                
            }
            
        }

        // print_r($breadcrumbsArray); die();
        
        // Return the breadcrumb array
        return $breadcrumbsArray;
    }


    /**
     * Gets path of the listed directory
     * 
     * @return string Pat of the listed directory
     * @acces public
     */
    public function getListedPath() {
        
        // Build the path
        if ($this->_directory == '.') {
            $path = $this->_appURL;
        } else {
            $path = $this->_appURL . $this->_directory;
        }
        
        // Return the path
        return $path;
    }
    
    
    /**
     * Returns the theme name.
     * 
     * @access public
     */
    public function getThemeName() {
        // Return the theme name
        return $this->_config['theme_name'];
    }
    
    /**
     * Returns the path to the chosen theme directory.
     * 
     * @param bool $absolute Wether or not the path returned is absolute (default = false).
     * @access public
     */
    public function getThemePath($absolute = false) {
        if ($absolute) {
            // Set the theme path
            $themePath = $this->_appDir . '/themes/' . $this->_themeName;
        } else {
            // Get relative path to application dir
            $realtivePath = $this->_getRelativePath(getcwd(), $this->_appDir);
            
            // Set the theme path
            $themePath = $realtivePath . '/themes/' . $this->_themeName;
        }
        
        return $themePath;
    }
    
    
    /**
     * Add a message to the system message array
     * 
     * @param string $type The type of message (ie - error, success, notice, etc.)
     * @param string $message The message to be displayed to the user
     * @access public
     */
    public function setSystemMessage($type, $text) {

        // Create empty message array if it doesn't already exist
        if (isset($this->_systemMessage) && !is_array($this->_systemMessage)) {
            $this->_systemMessage = array();
        } 

        // Set the error message
        $this->_systemMessage[] = array(
            'type'  => $type,
            'text'  => $text
        );
        
        return true;
    }
    
    
    /**
     * Get an array of error messages or false when empty.
     * 
     * @return array Array of error messages
     * @access public
     */
    public function getSystemMessages() {
        if (isset($this->_systemMessage) && is_array($this->_systemMessage)) {
            return $this->_systemMessage;
        } else {
            return false;
        }
    }
    
    /**
     * Validates and returns the directory path
     * 
     * @return string Directory path to be listed
     * @access private
     */
    private function _setDirecoryPath($dir) {
        
        // Check for an empty variable
        if (empty($dir) || $dir == '.') {
            return '.';
        }
        
        // Eliminate double slashes
        while (strpos($dir, '//')) {
            $dir = str_replace('//', '/', $dir);
        }
        
        // Remove trailing slash if present
        if(substr($dir, -1, 1) == '/') {
            $dir = substr($dir, 0, -1);
        }
        
        // Verify file path exists and is a directory
        if (!file_exists($dir) || !is_dir($dir)) {
            // Set the error message
            $this->setSystemMessage('error', '<b>ERROR:</b> File path does not exist');
                
            // Return the web root
            return '.';
        }
                    
        // Prevent access to hidden files
        if ($this->_isHidden($dir)) {
            // Set the error message
            $this->setSystemMessage('error', '<b>ERROR:</b> Access denied');
            
            // Set the directory to web root
            return '.';
        }

        // Prevent access to parent folders
        if (strpos($dir, '<') !== false || strpos($dir, '>') !== false 
        || strpos($dir, '..') !== false || strpos($dir, '/') === 0) {
            // Set the error message
            $this->setSystemMessage('error', '<b>ERROR:</b> An invalid path string was deceted');
                
            // Set the directory to web root
            return '.';
        } else {
            // Should stop all URL wrappers (Thanks to Hexatex)
            $directoryPath = $dir;
        }
        
        // Return
        return $directoryPath;
    }
    
    
    /**
     * Loop through directory and return array with file info, including
     * file path, size, modification time, icon and sort order.
     * 
     * @return array An array of the directory contents
     * @access private
     */
    private function _readDirectory($directory, $sort = 'natcase') {
        
        // Initialize array
        $directoryArray = array();
        
        // Get directory contents
        $files = scandir($directory);
        
        // Read files/folders from the directory
        foreach ($files as $file) {
            
            if ($file != '.') {
                
                // Get files relative path
                $relativePath = $directory . '/' . $file;
                
                if (substr($relativePath, 0, 2) == './') {
                    $relativePath = substr($relativePath, 2);
                }
                
                // Get files absolute path
                $realPath = realpath($relativePath);
                
                // Determine file type by extension
                if (is_dir($realPath)) {
                    $iconClass = 'icon-folder';
                    $sort = 1;
                } else {
                    // Get file extension
                    $fileExt = strtolower(pathinfo($realPath, PATHINFO_EXTENSION));
                
                    if (isset($this->_config['file_types'][$fileExt])) {
                        $iconClass = $this->_config['file_types'][$fileExt];
                    } else {
                        $iconClass = $this->_config['file_types']['blank'];
                    }
                    
                    $sort = 2;
                }
                
                if ($file == '..') {
                    
                    if ($this->_directory != '.') {
                        // Get parent directory path
                        $pathArray = explode('/', $relativePath);
                        unset($pathArray[count($pathArray)-1]);
                        unset($pathArray[count($pathArray)-1]);
                        $directoryPath = implode('/', $pathArray);
                        
                        if (!empty($directoryPath)) {
                            $directoryPath = '?dir=' . urlencode($directoryPath);
                        }
                        
                        // Add file info to the array
                        $directoryArray['..'] = array(
                            'file_path'  => $this->_appURL . $directoryPath,
                            'file_size'  => '-',
                            'mod_time'   => date('Y-m-d H:i:s', filemtime($realPath)),
                            'icon_class' => 'icon-up-dir',
                            'sort'       => 0
                        );
                    }
                    
                } elseif (!$this->_isHidden($relativePath)) {
                    
                    // Add all non-hidden files to the array
                    if ($this->_directory != '.' || $file != 'index.php') {
                        
                        // Build the file path
                        if (is_dir($relativePath)) {
                            $filePath = '?dir=' . urlencode($relativePath);
                        } else {
                            $filePath = $relativePath;
                        }
                        
                        // Add the info to the main array
                        $directoryArray[pathinfo($relativePath, PATHINFO_BASENAME)] = array(
                            'file_path'  => $filePath,
                            'file_size'  => is_dir($realPath) ? '-' : round(filesize($realPath) / 1024) . 'KB',
                            'mod_time'   => date('Y-m-d H:i:s', filemtime($realPath)),
                            'icon_class' => $iconClass,
                            'sort'       => $sort
                        );
                    }
                    
                }
            }

        }
 

        // Sort the array
        $sortedArray = $this->_arraySort($directoryArray, $this->_config['list_sort_order']);
        
        // Return the array
        return $sortedArray;

    }


    /**
    * Sorts an array by the provided sort method.
    *
    * @param array $array Array to be sorted
    * @param string $sort Sorting method (acceptable inputs: natsort, natcasesort, etc.)
    * @return array
    * @access private
    */
    private function _arraySort($array, $sortMethod) {
        // Create empty array
        $sortedArray = array();
        
        // Create new array of just the keys and sort it
        $keys = array_keys($array);
        
        switch ($sortMethod) {
            case 'asort':
                asort($keys);
                break;
            case 'arsort':
                arsort($keys);
                break;
            case 'ksort':
                ksort($keys);
                break;
            case 'krsort':
                krsort($keys);
                break;
            case 'natcasesort':
                natcasesort($keys);
                break;
            case 'natsort':
                natsort($keys);
                break;
            case 'shuffle':
                shuffle($keys);
                break;
        }
        
        // Loop through the sorted values and move over the data
        
        if ($this->_config['list_folders_first']) {
            
            foreach ($keys as $key) {
                if ($array[$key]['sort'] == 0) {
                    $sortedArray[$key] = $array[$key];
                }
            }
            
            foreach ($keys as $key) {
                if ($array[$key]['sort'] == 1) {
                    $sortedArray[$key] = $array[$key];
                }
            }
    
            foreach ($keys as $key) {
                if ($array[$key]['sort'] == 2) {
                    $sortedArray[$key] = $array[$key];
                }
            }
            
        } else {
            
            foreach ($keys as $key) {
                if ($array[$key]['sort'] == 0) {
                    $sortedArray[$key] = $array[$key];
                }
            }
            
            foreach ($keys as $key) {
                if ($array[$key]['sort'] > 0) {
                    $sortedArray[$key] = $array[$key];
                }
            }

        }
        
        // Return sorted array
        return $sortedArray;
        
    }
    
    
    /**
     * Determines if a file is supposed to be hidden
     * 
     * @access private
     */
    private function _isHidden($filePath) {
        
        // Define the OS specific directory separator
        if (!defined('DS')) define('DS', DIRECTORY_SEPARATOR);
        
        // Convert the file path to an array
        $pathArray  = explode(DS, $filePath);
        
        // Return true if dotfile and access to dotfiles is prohibited
        if ($this->_config['hide_dot_files']) {
            foreach ($pathArray as $element) {
                if (strlen($element) > 1 && substr($element, 0, 1) == '.') {
                    return true;
                }
            }
        }
        
        // Compare path array to all hidden file paths
        foreach ($this->_config['hidden_files'] as $hiddenPath) {
            
            // Strip trailing slash if present
            if (substr($hiddenPath, -1) == DS) {
                $hiddenPath = substr($hiddenPath, 0, -1);
            }
            
            // Convert the hidden file path to an array
            $hiddenArray = explode(DS, $hiddenPath);
            
            // Calculate intersections between the path and hidden arrays
            $intersect = array_intersect_assoc($pathArray, $hiddenArray);
            
            // Return true if the intersect matches the hidden array
            if ($intersect == $hiddenArray) {
                return true;
            }
            
        }
        
        return false;
        
    }

    /**
     * Builds the root application URL from server variables.
     * 
     * @return string The application URL
     * @access private
     */
    private function _getAppUrl() {
        
        // Get the server protocol
        if (!empty($_SERVER['HTTPS'])) {
            $protocol = 'https://';
        } else {
            $protocol = 'http://';
        }
        
        // Get the server hostname
        $host = $_SERVER['HTTP_HOST'];
        
        // Get the URL path
        $pathParts = pathinfo($_SERVER['PHP_SELF']);
        $path      = $pathParts['dirname'];
        
        // Remove backslash from path (Windows fix)
        if (substr($path, -1) == '\\') {
            $path = substr($path, 0, -1);
        }
        
        // Ensure the path ends with a forward slash
        if (substr($path, -1) != '/') {
            $path = $path . '/';
        }
        
        // Build the application URL
        $appUrl = $protocol . $host . $path;
        
        // Return the URL
        return $appUrl;
    }
    
    /**
      * Compares two paths and returns the relative path from one to the other
     *
     * @param string $fromPath Starting path
     * @param string $toPath Ending path
     * @return string $relativePath Relative path from $fromPath to $toPath
     * @access private
     */
    private function _getRelativePath($fromPath, $toPath) {
        
        // Define the OS specific directory separator
        if (!defined('DS')) define('DS', DIRECTORY_SEPARATOR);
        
        // Remove double slashes from path strings
        $fromPath = str_replace(DS . DS, DS, $fromPath);
        $toPath = str_replace(DS . DS, DS, $toPath);
        
        // Explode working dir and cache dir into arrays
        $fromPathArray = explode(DS, $fromPath);
        $toPathArray = explode(DS, $toPath);
        
        // Remove last fromPath array element if it's empty
        $x = count($fromPathArray) - 1;
        
        if(!trim($fromPathArray[$x])) {
            array_pop($fromPathArray);
        }
        
        // Remove last toPath array element if it's empty
        $x = count($toPathArray) - 1;
        
        if(!trim($toPathArray[$x])) {
            array_pop($toPathArray);
        }
        
        // Get largest array count
        $arrayMax = max(count($fromPathArray), count($toPathArray));
        
        // Set some default variables
        $diffArray = array();
        $samePath = true;
        $key = 1;
        
        // Generate array of the path differences
        while ($key <= $arrayMax) {
            
            // Get to path variable
            $toPath = isset($toPathArray[$key]) ? $toPathArray[$key] : NULL;
            
            // Get from path variable
            $fromPath = isset($fromPathArray[$key]) ? $fromPathArray[$key] : NULL;
            
            if ($toPath !== $fromPath || $samePath !== true) {
                
                // Prepend '..' for every level up that must be traversed
                if (isset($fromPathArray[$key])) {
                    array_unshift($diffArray, '..');
                }
                
                // Append directory name for every directory that must be traversed
                if (isset($toPathArray[$key])) {
                    $diffArray[] = $toPathArray[$key];
                }
                
                // Directory paths have diverged
                $samePath = false;
            }
            
            // Increment key
            $key++;
        }

        // Set the relative thumbnail directory path
        $relativePath = implode('/', $diffArray);
        
        // Return the relative path
        return $relativePath;
        
    }
    
}

?>
Return current item: Directory Lister