<?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 */