Location: PHPKode > scripts > PhpIndex Light > library/PhpIndex/DirectoryBrowser.php
<?php
/**
* Directory browser
*
* $Id: $
*
* $LastChangedBy: $
*
* $LastChangedDate: $
*
* $Rev: $
*
* @author Indiana Jones <hide@address.com>
* @version 1.0
* @copyright 2010 PhpIndex
* @package PhpIndex
*/

class PhpIndex_DirectoryBrowser
{
    /**
     * Request dir name
     *
     * @var string
     */
    private $_requestDirName;

    /**
     * Request full path
     * 
     * @var string
     */
    private $_request;

    /**
     * Files list
     *
     * @var array
     */
    private $_filesList = array();

    /**
     * Directories list
     *
     * @var array
     */
    private $_directoriesList = array();

    /**
     * Allowed sorting methods
     *
     * @var array
     */
    private $_sortMethods = array(
        'date'
    );

    /**
     * Alternate row
     *
     * @var boolean
     */
    private $_alternate = false;

    /**
     * Page title
     *
     * @var string
     */
    private $_pageTitle = '';

    /**
     * Main run method
     *
     * @param string $request
     * @return void
     */
    public function run($request)
    {
        $this->_requestDirName = $request;

        $this->_parseRequest();

        if ($this->_isDirRequest()) {
            $this->_formatDirRequest();
            $this->_displayHeader();
            $this->_listFiles();
            $this->_sortFiles();

            $this->_displayTableHeader();
            $this->_displayDirectories();
            $this->_displayFiles();
            $this->_displayTableFooter();

            $this->_displayFooter();
        } else {
            $this->_downloadFile();
        }
    }

    /**
     * Custom function used to sort files by date
     *
     * @param array $fileA
     * @param array $fileB
     * @return integer
     */
    public static function sortByDate($fileA, $fileB)
    {
        $dateA = $fileA['mtime'];
        $dateB = $fileB['mtime'];

        if ($dateA == $dateB) {
            return 0;
        }
        return ($dateA < $dateB) ? -1 : 1;
    }

    /**
     * Parse request and set the full path
     *
     * @return void
     */
    private function _parseRequest()
    {
        $request = realpath(PhpIndex_Registry::getInstance()->config['base_directory'] . $this->_requestDirName);

        if (is_dir($request)) {
            $request = rtrim($request, '/') . '/';
        }

        $this->_request = $request;
    }

    /**
     * Format directory request
     *
     * @return void
     */
    private function _formatDirRequest()
    {
        $this->_request = rtrim($this->_request, '/\\ ');
        $this->_requestDirName = rtrim($this->_requestDirName, '/\\ ');

        if (!empty($this->_request)) {
            $this->_request .= '/';
        }

        if (!empty($this->_requestDirName)) {
            $this->_requestDirName .= '/';
        }
    }

    /**
     * List files
     *
     * @return void
     */
    private function _listFiles()
    {
        $handle = opendir($this->_request);
        if (!$handle) {
            throw new Exception('Failed to open directory!');
        }

        do {
            $file = readdir($handle);

            // skip files/directories that start with . (dot)
            if (empty($file) || preg_match('/^\./', $file)) {
                continue;
            }

            $this->_addToFilesList($file);
        } while ($file);
            
        closedir($handle);
    }

    /**
     *  Check if is directory request
     *
     * @return boolean
     */
    private function _isDirRequest()
    {
        return is_dir($this->_request);
    }

    /**
     * Add file information to filesList array
     *
     * @param string $fileName
     * @return void
     */
    private function _addToFilesList($fileName)
    {
        // date format from config
        $dateFormat = PhpIndex_Registry::getInstance()->config['date_format'];

        $file = $this->_request . $fileName;

        $fileUrl = $this->_requestDirName . $fileName;

        $isDir = is_dir($file);

        // Time of last modification
        $mtime = filemtime($file);
        // Time of last access.
        $atime = fileatime($file);
        // Time of last status change
        $ctime = filectime($file);

        if ($isDir) {
            $this->_directoriesList[] = array(
                'fileName' => $fileName,
                'fileUrl' => $fileUrl . '/',
                'filePath' => $file,
                'mtime' => $mtime,
                'atime' => $atime,
                'ctime' => $ctime,
                'accessed' => date($dateFormat, $mtime),
                'modified' => date($dateFormat, $atime),
                'created' => date($dateFormat, $ctime),
                'extension' => 'dir',
                'icon' => $this->_getIcon($isDir)
            );

            return null;
        }

        $extension = $this->_getExtension($fileName, $isDir);

        $fileSize = $this->_getFileSize($file, $isDir);

        $fileInfo = array(
            'fileName' => $fileName,
            'fileUrl' => $fileUrl,
            'filePath' => $file,
            'fileSize' => $this->_formatFileSize($fileSize, $isDir),
            'fileSizeBytes' => $fileSize,
            'mtime' => $mtime,
            'atime' => $atime,
            'ctime' => $ctime,
            'accessed' => date($dateFormat, $mtime),
            'modified' => date($dateFormat, $atime),
            'created' => date($dateFormat, $ctime),
            'extension' => $extension,
            'icon' => $this->_getIcon($isDir, $extension)
        );

        $this->_filesList[] = $fileInfo;
    }

    /**
     * Sort files
     *
     * @return void
     */
    private function _sortFiles()
    {
        // sorting method
        $sortMethod = PhpIndex_Registry::getInstance()->config['sort_by'];

        if (!in_array($sortMethod, $this->_sortMethods)) {
            return false;
        }

        switch ($sortMethod) {
            case 'date':
                $filesSorted = array();
                usort($this->_filesList, array(__CLASS__, 'sortByDate'));
                break;
        }
    }

    /**
     * Display files
     *
     * @return void
     */
    private function _displayFiles()
    {
        foreach ($this->_filesList as $file) {
            $this->_displayItem($file);
            $this->_alternate = !$this->_alternate;
        }
    }

    /**
     * Display directories
     *
     * @return void
     */
    private function _displayDirectories()
    {
        foreach ($this->_directoriesList as $directory) {
            $this->_displayItem($directory);
            $this->_alternate = !$this->_alternate;
        }        
    }

    /**
     * Display item (file or directory)
     *
     * @param array $item
     * @return void
     */
    private function _displayItem($item)
    {
        $rootPath = PhpIndex_Registry::getInstance()->config['root_path'];

        echo '<tr class="phpindex_tr';
        if ($this->_alternate) {
            echo '_alternate';
        }
        echo '">';

        echo '<td><img src="' . $rootPath . $this->_getIconFilePath($item['icon'], true) . '" alt="' . $item['extension'] . '" /> ';
        echo '<a href="' . $rootPath . $item['fileUrl'] . '">' . htmlspecialchars($item['fileName']) . '</a></td>';

        $fileSize = '';
        if (isset($item['fileSize'])) {
            $fileSize = $item['fileSize'];
        }

        echo '<td>' . $fileSize . '</td>';
        echo '<td>' . $item['modified'] . '</td>';

        echo '</tr>' . PHP_EOL;
    }

    /**
     * Get extension for a given file
     *
     * @param string $fileName
     * @param boolean $isDir
     * @return string
     */
    private function _getExtension($fileName, $isDir)
    {
        if ($isDir) {
            return 'dir';
        }

        $pathInfo = pathinfo($fileName);
        return strtolower($pathInfo['extension']);
    }

    /**
     * Get icon name for a given file
     *
     * @param boolean $isDir
     * @param string $extension
     * @return string
     */
    private function _getIcon($isDir, $extension = '')
    {
        if ($isDir) {
            return 'dir';
        }


        if (file_exists($this->_getIconFilePath($extension))) {
            return $extension;
        }

        return 'unknown';
    }

    /**
     * Get icon file path
     *
     * @param string $extension
     * @param boolean $webOutput
     * @return string
     */
    private function _getIconFilePath($extension, $webOutput = false)
    {
        $extensionImagesType = PhpIndex_Registry::getInstance()->config['extension_images_type'];

        if ($webOutput) {
            $extensionImagesPath = PhpIndex_Registry::getInstance()->config['extension_images_path_web'];
        } else {
            $extensionImagesPath = PhpIndex_Registry::getInstance()->config['extension_images_path'];
        }

        $iconFilePath = $extensionImagesPath . $extension . '.' . $extensionImagesType;

        return $iconFilePath;
    }

    /**
     * Get file size in bytes
     *
     * @param string $file
     * @param boolean $isDir
     * @return integer
     */
    private function _getFileSize($file, $isDir)
    {
        if ($isDir) {
            return 0;
        }

        return filesize($file);
    }

    /**
     * Format file size for output
     *
     * @param integer $fileSize
     * @param boolean $isDir
     * @return string
     */
    private function _formatFileSize($fileSize, $isDir)
    {
        $friendlyFilesize = PhpIndex_Registry::getInstance()->config['friendly_filesize'];

        $fileSizeOutput = '';

        if ($isDir) {
            return $fileSizeOutput;
        }

        if ($friendlyFilesize) {
            $fileSizeOutput = $this->_friendlyFileSize($fileSize);
        } else {
            $fileSizeOutput = $fileSize . ' bytes';
        }

        return $fileSizeOutput;
    }

    /**
     * Download requested file
     *
     * @return void
     */
    private function _downloadFile()
    {
        require_once(dirname(__FILE__) . '/Download.php');

        $downloadManager = new PhpIndex_Download();
        $downloadManager->download($this->_request);
    }

    /**
     * Display file size in friendly format
     *
     * @param integer $size
     * @return string
     */
    private function _friendlyFileSize($size)
    {
        $bytes = array('KB', 'KB', 'MB', 'GB', 'TB');

        // less than 1 KB, display in bytes
        if ($size < 1024) {
            return $size . ' bytes';
        }

        for ($i = 0; $size >= 1024; $i++) {
            $size /= 1024;
        }

        $formattedSize = ceil($size) . ' ' . $bytes[$i];

        return $formattedSize;
    }

    /**
     * Get the parent of a given directory
     *
     * @param string $directory
     * @return string
     */
    private function _getParentDirectory($directory)
    {
        $parent = dirname($directory);

        $parent = rtrim($parent, '/\\ ');

        if (!empty($parent)) {
            $parent .= '/';
        }

        return $parent;
    }

    /**
     * Display header
     *
     * @return void
     */
    private function _displayHeader()
    {
        // check if we need to use gzip compression
        $useGzip = PhpIndex_Registry::getInstance()->config['use_gzip'];
        if ($useGzip) {
            ob_start('ob_gzhandler');
        }

        $rootPath = PhpIndex_Registry::getInstance()->config['root_path'];

        $this->_pageTitle = $this->_requestDirName;

        if (empty($this->_pageTitle)) {
            $this->_pageTitle = '/';
        }

        echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<link rel="stylesheet" href="' . $rootPath . 'css/stylesheet.css" type="text/css" />
<title>Index of ' . htmlspecialchars($this->_pageTitle) . '</title>
</head>
<body>
<div id="phpindex_container">' . PHP_EOL;
    }

    /**
     * Display footer
     *
     * @return void
     */
    private function _displayFooter()
    {
        echo '
<div id="phpindex_footer">Powered by <a href="http://php.bubble.ro/phpindex/light/">PhpIndexLight v1.0</a></div>
</div>
</body>
</html>';
    }

    /**
     * Display table header
     *
     * @return void
     */
    private function _displayTableHeader()
    {
        $rootPath = PhpIndex_Registry::getInstance()->config['root_path'];

        echo '<h1>Index of ' . htmlspecialchars($this->_pageTitle) . '</h1>' . PHP_EOL;

        echo '<table class="phpindex_table">' . PHP_EOL;

        $parent = $this->_getParentDirectory($this->_requestDirName);

        if (!empty($parent)) {
            echo '<tr class="phpindex_tr">';
            echo '<td colspan="20"><img src="' . $rootPath . $this->_getIconFilePath('back', true) . '" alt="back" /> <a href="' . $rootPath . $parent . '">Parent folder</a></td>';
            echo '</tr>' . PHP_EOL;
        }
    }

    /**
     * Display table footer
     *
     * @return void
     */
    private function _displayTableFooter()
    {
        echo '</table>' . PHP_EOL;
    }
}

/* EOF */
Return current item: PhpIndex Light