'', // path to root directory 'URL' => '', // root directory URL 'rootAlias' => 'Home', // display this instead of root directory name 'disabled' => array(), // list of not allowed commands 'dotFiles' => false, // display dot files 'dirSize' => true, // count total directories sizes 'fileMode' => 0666, // new files mode 'dirMode' => 0777, // new folders mode 'mimeDetect' => 'auto', // files mimetypes detection method (finfo, mime_content_type, linux (file -ib), bsd (file -Ib), internal (by extensions)) 'uploadAllow' => array(), // mimetypes which allowed to upload 'uploadDeny' => array(), // mimetypes which not allowed to upload 'uploadOrder' => 'deny,allow', // order to proccess uploadAllow and uploadAllow options 'imgLib' => 'auto', // image manipulation library (imagick, mogrify, gd) 'tmbDir' => '.tmb', // directory name for image thumbnails. Set to "" to avoid thumbnails generation 'tmbCleanProb' => 1, // how frequiently clean thumbnails dir (0 - never, 200 - every init request) 'tmbAtOnce' => 5, // number of thumbnails to generate per request 'tmbSize' => 48, // images thumbnails size (px) 'tmbCrop' => true, // crop thumbnails (true - crop, false - scale image to fit thumbnail size) 'tmbBgColor' => '#ffffff', // thumbnail background color 'fileURL' => true, // display file URL in "get info" 'dateFormat' => 'j M Y H:i', // file modification date format 'logger' => null, // object logger 'aclObj' => null, // acl object (not implemented yet) 'aclRole' => 'user', // role for acl 'defaults' => array( // default permisions 'read' => true, 'write' => true, 'rm' => true ), 'perms' => array(), // individual folders/files permisions 'debug' => false, // send debug to client 'archiveMimes' => array(), // allowed archive's mimetypes to create. Leave empty for all available types. 'archivers' => array() // info about archivers to use. See example below. Leave empty for auto detect // 'archivers' => array( // 'create' => array( // 'application/x-gzip' => array( // 'cmd' => 'tar', // 'argc' => '-czf', // 'ext' => 'tar.gz' // ) // ), // 'extract' => array( // 'application/x-gzip' => array( // 'cmd' => 'tar', // 'argc' => '-xzf', // 'ext' => 'tar.gz' // ), // 'application/x-bzip2' => array( // 'cmd' => 'tar', // 'argc' => '-xjf', // 'ext' => 'tar.bz' // ) // ) // ) ); /** * mapping $_GET['cmd]/$_POST['cmd] to class methods * * @var array **/ protected $_commands = array( 'open' => '_open', 'reload' => '_reload', 'mkdir' => '_mkdir', 'mkfile' => '_mkfile', 'rename' => '_rename', 'upload' => '_upload', 'paste' => '_paste', 'rm' => '_rm', 'duplicate' => '_duplicate', 'read' => '_fread', 'edit' => '_edit', 'archive' => '_archive', 'extract' => '_extract', 'resize' => '_resize', 'tmb' => '_thumbnails', 'ping' => '_ping' ); /** * List of commands to log * * @var string **/ public $_loggedCommands = array('mkdir', 'mkfile', 'rename', 'upload', 'paste', 'rm', 'duplicate', 'edit', 'resize'); /** * Context to log command * * @var string **/ protected $_logContext = array(); /** * extensions/mimetypes for _mimetypeDetect = 'internal' * * @var array **/ protected $_mimeTypes = array( //applications 'ai' => 'application/postscript', 'eps' => 'application/postscript', 'exe' => 'application/octet-stream', 'doc' => 'application/vnd.ms-word', 'xls' => 'application/vnd.ms-excel', 'ppt' => 'application/vnd.ms-powerpoint', 'pps' => 'application/vnd.ms-powerpoint', 'pdf' => 'application/pdf', 'xml' => 'application/xml', 'odt' => 'application/vnd.oasis.opendocument.text', 'swf' => 'application/x-shockwave-flash', // archives 'gz' => 'application/x-gzip', 'tgz' => 'application/x-gzip', 'bz' => 'application/x-bzip2', 'bz2' => 'application/x-bzip2', 'tbz' => 'application/x-bzip2', 'zip' => 'application/zip', 'rar' => 'application/x-rar', 'tar' => 'application/x-tar', '7z' => 'application/x-7z-compressed', // texts 'txt' => 'text/plain', 'php' => 'text/x-php', 'html' => 'text/html', 'htm' => 'text/html', 'js' => 'text/javascript', 'css' => 'text/css', 'rtf' => 'text/rtf', 'rtfd' => 'text/rtfd', 'py' => 'text/x-python', 'java' => 'text/x-java-source', 'rb' => 'text/x-ruby', 'sh' => 'text/x-shellscript', 'pl' => 'text/x-perl', 'sql' => 'text/x-sql', // images 'bmp' => 'image/x-ms-bmp', 'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'gif' => 'image/gif', 'png' => 'image/png', 'tif' => 'image/tiff', 'tiff' => 'image/tiff', 'tga' => 'image/x-targa', 'psd' => 'image/vnd.adobe.photoshop', //audio 'mp3' => 'audio/mpeg', 'mid' => 'audio/midi', 'ogg' => 'audio/ogg', 'mp4a' => 'audio/mp4', 'wav' => 'audio/wav', 'wma' => 'audio/x-ms-wma', // video 'avi' => 'video/x-msvideo', 'dv' => 'video/x-dv', 'mp4' => 'video/mp4', 'mpeg' => 'video/mpeg', 'mpg' => 'video/mpeg', 'mov' => 'video/quicktime', 'wm' => 'video/x-ms-wmv', 'flv' => 'video/x-flv', 'mkv' => 'video/x-matroska' ); /** * undocumented class variable * * @var string **/ protected $_time = 0; /** * Additional data about error * * @var array **/ protected $_errorData = array(); /** * undocumented class variable * * @var string **/ protected $_fakeRoot = ''; /** * Command result to send to client * * @var array **/ protected $_result = array(); /** * undocumented class variable * * @var string **/ protected $_today = 0; /** * undocumented class variable * * @var string **/ protected $_yesterday = 0; /** * constructor * * @param array object options * @return void **/ public function __construct($options=array()) { foreach ($this->_options as $k=>$v) { if (isset($options[$k])) { $this->_options[$k] = is_array($this->_options[$k]) ? array_merge($this->_options[$k], $options[$k]) : $options[$k]; } } if (substr($this->_options['root'], -1) == DIRECTORY_SEPARATOR) { $this->_options['root'] = substr($this->_options['root'], 0, -1); } $this->_time = $this->_options['debug'] ? $this->_utime() : 0; $this->_fakeRoot = !$this->_options['rootAlias'] ? $this->_options['root'] : dirname($this->_options['root']).DIRECTORY_SEPARATOR.$this->_options['rootAlias']; if (!empty($this->_options['disabled'])) { $no = array('open', 'reload', 'tmb', 'ping'); foreach ($this->_options['disabled'] as $k => $c) { if (!isset($this->_commands[$c]) || in_array($c, $no)) { unset($this->_options['disabled'][$k]); } else { unset($this->_commands[$c]); } } } if ($this->_options['tmbDir']) { $tmbDir = $this->_options['root'].DIRECTORY_SEPARATOR.$this->_options['tmbDir']; $this->_options['tmbDir'] = is_dir($tmbDir) || @mkdir($tmbDir, $this->_options['dirMode']) ? $tmbDir : ''; } if ($this->_options['tmbDir']) { if (!in_array($this->_options['imgLib'], array('imagick', 'mogrify', 'gd'))) { $this->_options['imgLib'] = $this->_getImgLib(); } } $this->_today = mktime(0,0,0, date('m'), date('d'), date('Y')); $this->_yesterday = $this->_today-86400; } /** * Proccess client request and output json * * @return void **/ public function run() { if (!function_exists('json_encode')) { exit('{"error":"PHP JSON module not installed"}'); } if (empty($this->_options['root']) || !is_dir($this->_options['root'])) { exit(json_encode(array('error' => 'Invalid backend configuration'))); } if (!$this->_isAllowed($this->_options['root'], 'read')) { exit(json_encode(array('error' => 'Access denied'))); } $cmd = ''; if (!empty($_POST['cmd'])) { $cmd = trim($_POST['cmd']); } elseif (!empty($_GET['cmd'])) { $cmd = trim($_GET['cmd']); } if (!$cmd && $_SERVER["REQUEST_METHOD"] == 'POST') { header("Content-Type: text/html"); $this->_result['error'] = 'Data exceeds the maximum allowed size'; exit(json_encode($this->_result)); } if ($cmd && (empty($this->_commands[$cmd]) || !method_exists($this, $this->_commands[$cmd]))) { exit(json_encode(array('error' => 'Unknown command'))); } if (isset($_GET['init'])) { $ts = $this->_utime(); $this->_result['disabled'] = array_values($this->_options['disabled']); $this->_result['params'] = array( 'dotFiles' => $this->_options['dotFiles'], 'uplMaxSize' => ini_get('upload_max_filesize'), 'archives' => array(), 'extract' => array(), 'url' => $this->_options['fileURL'] ? $this->_options['URL'] : '' ); if (isset($this->_commands['archive']) || isset($this->_commands['extract'])) { $this->_checkArchivers(); if (isset($this->_commands['archive'])) { $this->_result['params']['archives'] = $this->_options['archiveMimes']; } if (isset($this->_commands['extract'])) { $this->_result['params']['extract'] = array_keys($this->_options['archivers']['extract']); } } // clean thumbnails dir if ($this->_options['tmbDir']) { srand((double) microtime() * 1000000); if (rand(1, 200) <= $this->_options['tmbCleanProb']) { $ts2 = $this->_utime(); $ls = scandir($this->_options['tmbDir']); for ($i=0, $s = count($ls); $i < $s; $i++) { if ('.' != $ls[$i] && '..' != $ls[$i]) { @unlink($this->_options['tmbDir'].DIRECTORY_SEPARATOR.$ls[$i]); } } } } } if ($this->_options['debug']) { $this->_result['debug'] = array( 'time' => $this->_utime() - $this->_time, 'mimeDetect' => $this->_options['mimeDetect'], 'imgLib' => $this->_options['imgLib'] ); if ($this->_options['dirSize']) { $this->_result['debug']['dirSize'] = true; $this->_result['debug']['du'] = @$this->_options['du']; } } if ($cmd) { $this->{$this->_commands[$cmd]}(); } else { $this->_open(); } header("Content-Type: ".($cmd == 'upload' ? 'text/html' : 'application/json')); header("Connection: close"); echo json_encode($this->_result); if (!empty($this->_options['logger']) && in_array($cmd, $this->_loggedCommands)) { $this->_options['logger']->log($cmd, empty($this->_result['error']), $this->_logContext, !empty($this->_result['error']) ? $this->_result['error'] : '', !empty($this->_result['errorData']) ? $this->_result['errorData'] : array()); } exit(); } /************************************************************/ /** elFinder commands **/ /************************************************************/ /** * Return current dir content to client or output file content to browser * * @return void **/ protected function _open() { if (isset($_GET['current'])) { // read file if (empty($_GET['current']) || empty($_GET['target']) || false == ($dir = $this->_findDir(trim($_GET['current']))) || false == ($file = $this->_find(trim($_GET['target']), $dir)) || is_dir($file) ) { header('HTTP/1.x 404 Not Found'); exit('File not found'); } if (!$this->_isAllowed($dir, 'read') || !$this->_isAllowed($file, 'read')) { header('HTTP/1.x 403 Access Denied'); exit('Access denied'); } if (filetype($file) == 'link') { $file = $this->_readlink($file); if (!$file || is_dir($file)) { header('HTTP/1.x 404 Not Found'); exit('File not found'); } if (!$this->_isAllowed(dirname($file), 'read') || !$this->_isAllowed($file, 'read')) { header('HTTP/1.x 403 Access Denied'); exit('Access denied'); } } $mime = $this->_mimetype($file); $parts = explode('/', $mime); $disp = $parts[0] == 'image' || $parts[0] == 'text' ? 'inline' : 'attachments'; header("Content-Type: ".$mime); header("Content-Disposition: ".$disp."; filename=".basename($file)); header("Content-Location: ".str_replace($this->_options['root'], '', $file)); header('Content-Transfer-Encoding: binary'); header("Content-Length: ".filesize($file)); header("Connection: close"); readfile($file); exit(); } else { // enter directory $path = $this->_options['root']; if (!empty($_GET['target'])) { if (false == ($p = $this->_findDir(trim($_GET['target'])))) { if (!isset($_GET['init'])) { $this->_result['error'] = 'Invalid parameters'; } } elseif (!$this->_isAllowed($p, 'read')) { if (!isset($_GET['init'])) { $this->_result['error'] = 'Access denied'; } } else { $path = $p; } } $this->_content($path, isset($_GET['tree'])); } } /** * Rename file/folder * * @return void **/ protected function _rename() { if (empty($_GET['current']) || empty($_GET['target']) || false == ($dir = $this->_findDir(trim($_GET['current']))) || false == ($target = $this->_find(trim($_GET['target']), $dir)) ) { $this->_result['error'] = 'File not found'; } elseif (false == ($name = $this->_checkName($_GET['name'])) ) { $this->_result['error'] = 'Invalid name'; } elseif (!$this->_isAllowed($dir, 'write')) { $this->_result['error'] = 'Access denied'; } elseif (file_exists($dir.DIRECTORY_SEPARATOR.$name)) { $this->_result['error'] = 'File or folder with the same name already exists'; } elseif (!rename($target, $dir.DIRECTORY_SEPARATOR.$name)) { $this->_result['error'] = 'Unable to rename file'; } else { $this->_rmTmb($target); $this->_logContext['from'] = $target; $this->_logContext['to'] = $dir.DIRECTORY_SEPARATOR.$name; $this->_result['select'] = array($this->_hash($dir.DIRECTORY_SEPARATOR.$name)); $this->_content($dir, is_dir($dir.DIRECTORY_SEPARATOR.$name)); } } /** * Create new folder * * @return void **/ protected function _mkdir() { if (empty($_GET['current']) || false == ($dir = $this->_findDir(trim($_GET['current'])))) { return $this->_result['error'] = 'Invalid parameters'; } $this->_logContext['dir'] = $dir.DIRECTORY_SEPARATOR.$_GET['name']; if (!$this->_isAllowed($dir, 'write')) { $this->_result['error'] = 'Access denied'; } elseif (false == ($name = $this->_checkName($_GET['name'])) ) { $this->_result['error'] = 'Invalid name'; } elseif (file_exists($dir.DIRECTORY_SEPARATOR.$name)) { $this->_result['error'] = 'File or folder with the same name already exists'; } elseif (!@mkdir($dir.DIRECTORY_SEPARATOR.$name, $this->_options['dirMode'])) { $this->_result['error'] = 'Unable to create folder'; } else { $this->_logContext['dir'] = $dir.DIRECTORY_SEPARATOR.$name; $this->_result['select'] = array($this->_hash($dir.DIRECTORY_SEPARATOR.$name)); $this->_content($dir, true); } } /** * Create new empty file * * @return void **/ protected function _mkfile() { if (empty($_GET['current']) || false == ($dir = $this->_findDir(trim($_GET['current'])))) { return $this->_result['error'] = 'Invalid parameters'; } $this->_logContext['file'] = $dir.DIRECTORY_SEPARATOR.$_GET['name']; if (!$this->_isAllowed($dir, 'write')) { $this->_result['error'] = 'Access denied'; } elseif (false == ($name = $this->_checkName($_GET['name'])) ) { $this->_result['error'] = 'Invalid name'; } elseif (file_exists($dir.DIRECTORY_SEPARATOR.$name)) { $this->_result['error'] = 'File or folder with the same name already exists'; } else { $f = $dir.DIRECTORY_SEPARATOR.$name; $this->_logContext['file'] = $f; if (false != ($fp = @fopen($f, 'wb'))) { fwrite($fp, ""); fclose($fp); $this->_result['select'] = array($this->_hash($dir.DIRECTORY_SEPARATOR.$name)); $this->_content($dir); } else { $this->_result['error'] = 'Unable to create file'; } } } /** * Remove files/folders * * @return void **/ protected function _rm() { if (empty($_GET['current']) || false == ($dir = $this->_findDir(trim($_GET['current']))) || (empty($_GET['targets']) || !is_array($_GET['targets']))) { return $this->_result['error'] = 'Invalid parameters'; } $this->_logContext['targets'] = array(); foreach ($_GET['targets'] as $hash) { if (false != ($f = $this->_find($hash, $dir))) { $this->_remove($f); $this->_logContext['targets'][] = $f; } } if (!empty($this->_result['errorData'])) { $this->_result['error'] = 'Unable to remove file'; } $this->_content($dir, true); } /** * Upload files * * @return void **/ protected function _upload() { if (empty($_POST['current']) || false == ($dir = $this->_findDir(trim($_POST['current'])))) { return $this->_result['error'] = 'Invalid parameters'; } if (!$this->_isAllowed($dir, 'write')) { return $this->_result['error'] = 'Access denied'; } if (empty($_FILES['upload'])) { return $this->_result['error'] = 'No file to upload'; } $this->_logContext['upload'] = array(); $this->_result['select'] = array(); $total = 0; for ($i=0, $s = count($_FILES['upload']['name']); $i < $s; $i++) { if (!empty($_FILES['upload']['name'][$i])) { $total++; $this->_logContext['upload'][] = $_FILES['upload']['name'][$i]; if ($_FILES['upload']['error'][$i] > 0) { $error = 'Unable to upload file'; switch ($_FILES['upload']['error'][$i]) { case UPLOAD_ERR_INI_SIZE: case UPLOAD_ERR_FORM_SIZE: $error = 'File exceeds the maximum allowed filesize'; break; case UPLOAD_ERR_EXTENSION: $error = 'Not allowed file type'; break; } $this->_errorData($_FILES['upload']['name'][$i], $error); } elseif (false == ($name = $this->_checkName($_FILES['upload']['name'][$i]))) { $this->_errorData($_FILES['upload']['name'][$i], 'Invalid name'); } elseif (!$this->_isUploadAllow($_FILES['upload']['name'][$i], $_FILES['upload']['tmp_name'][$i])) { $this->_errorData($_FILES['upload']['name'][$i], 'Not allowed file type'); } else { $name = $this->_checkName($_FILES['upload']['name'][$i]); $file = $dir.DIRECTORY_SEPARATOR.$name; if (!@move_uploaded_file($_FILES['upload']['tmp_name'][$i], $file)) { $this->_errorData($_FILES['upload']['name'][$i], 'Unable to save uploaded file'); } else { @chmod($file, $this->_options['fileMode']); $this->_result['select'][] = $this->_hash($file); } } } } $errCnt = !empty($this->_result['errorData']) ? count($this->_result['errorData']) : 0; if ($errCnt == $total) { $this->_result['error'] = 'Unable to upload files'; } else { if ($errCnt>0) { $this->_result['error'] = 'Some files was not uploaded'; } $this->_content($dir); } } /** * Copy/move files/folders * * @return void **/ protected function _paste() { if (empty($_GET['current']) || false == ($current = $this->_findDir(trim($_GET['current']))) || empty($_GET['src']) || false == ($src = $this->_findDir(trim($_GET['src']))) || empty($_GET['dst']) || false == ($dst = $this->_findDir(trim($_GET['dst']))) || empty($_GET['targets']) || !is_array($_GET['targets']) ) { return $this->_result['error'] = 'Invalid parameters'; } $cut = !empty($_GET['cut']); $this->_logContext['src'] = array(); $this->_logContext['dest'] = $dst; $this->_logContext['cut'] = $cut; if (!$this->_isAllowed($dst, 'write') || !$this->_isAllowed($src, 'read')) { return $this->_result['error'] = 'Access denied'; } foreach ($_GET['targets'] as $hash) { if (false == ($f = $this->_find($hash, $src))) { return $this->_result['error'] = 'File not found' && $this->_content($current, true); } $this->_logContext['src'][] = $f; $_dst = $dst.DIRECTORY_SEPARATOR.basename($f); if (0 === strpos($dst, $f)) { return $this->_result['error'] = 'Unable to copy into itself' && $this->_content($current, true); } elseif (file_exists($_dst)) { return $this->_result['error'] = 'File or folder with the same name already exists' && $this->_content($current, true); } elseif ($cut && !$this->_isAllowed($f, 'rm')) { return $this->_result['error'] = 'Access denied' && $this->_content($current, true); } if ($cut) { if (!@rename($f, $_dst)) { return $this->_result['error'] = 'Unable to move files' && $this->_content($current, true); } elseif (!is_dir($f)) { $this->_rmTmb($f); } } elseif (!$this->_copy($f, $_dst)) { return $this->_result['error'] = 'Unable to copy files' && $this->_content($current, true); } } $this->_content($current, true); } /** * Create file/folder copy with suffix - "copy" * * @return void **/ protected function _duplicate() { if (empty($_GET['current']) || false == ($current = $this->_findDir(trim($_GET['current']))) || empty($_GET['target']) || false == ($target = $this->_find(trim($_GET['target']), $current)) ) { return $this->_result['error'] = 'Invalid parameters'; } $this->_logContext['target'] = $target; if (!$this->_isAllowed($current, 'write') || !$this->_isAllowed($target, 'read')) { return $this->_result['error'] = 'Access denied'; } $dup = $this->_uniqueName($target); if (!$this->_copy($target, $dup)) { return $this->_result['error'] = 'Unable to create file copy'; } $this->_result['select'] = array($this->_hash($dup)); $this->_content($current, is_dir($target)); } /** * Resize image * * @return void **/ protected function _resize() { if (empty($_GET['current']) || false == ($current = $this->_findDir(trim($_GET['current']))) || empty($_GET['target']) || false == ($target = $this->_find(trim($_GET['target']), $current)) || empty($_GET['width']) || 0 >= ($width = intval($_GET['width'])) || empty($_GET['height']) || 0 >= ($height = intval($_GET['height'])) ) { return $this->_result['error'] = 'Invalid parameters'; } $this->_logContext = array( 'target' => $target, 'width' => $width, 'height' => $height ); if (!$this->_isAllowed($target, 'write')) { return $this->_result['error'] = 'Access denied'; } if (0 !== strpos($this->_mimetype($target), 'image')) { return $this->_result['error'] = 'File is not an image'; } if (!$this->_resizeImg($target, $width, $height)) { return $this->_result['error'] = 'Unable to resize image'; } $this->_result['select'] = array($this->_hash($target)); $this->_content($current); } /** * Create images thumbnails * * @return void **/ protected function _thumbnails() { if (!empty($this->_options['tmbDir']) && !empty($_GET['current']) && false != ($current = $this->_findDir(trim($_GET['current'])))) { $this->_result['current'] = $this->_hash($current); $this->_result['images'] = array(); $ls = scandir($current); $cnt = 0; $max = $this->_options['tmbAtOnce'] > 0 ? intval($this->_options['tmbAtOnce']) : 5; for ($i=0; $i < count($ls); $i++) { if ($this->_isAccepted($ls[$i])) { $path = $current.DIRECTORY_SEPARATOR.$ls[$i]; if (is_readable($path) && $this->_canCreateTmb($this->_mimetype($path))) { $tmb = $this->_tmbPath($path); if (!file_exists($tmb)) { if ($cnt>=$max) { return $this->_result['tmb'] = true; } elseif ($this->_tmb($path, $tmb)) { $this->_result['images'][$this->_hash($path)] = $this->_path2url($tmb); $cnt++; } } } } } } } /** * Return file content to client * * @return void **/ protected function _fread() { if (empty($_GET['current']) || false == ($current = $this->_findDir(trim($_GET['current']))) || empty($_GET['target']) || false == ($target = $this->_find(trim($_GET['target']), $current)) ) { return $this->_result['error'] = 'Invalid parameters'; } if (!$this->_isAllowed($target, 'read')) { return $this->_result['error'] = 'Access denied'; } $this->_result['content'] = @file_get_contents($target); } /** * Save data into text file. * * @return void **/ protected function _edit() { if (empty($_POST['current']) || false == ($current = $this->_findDir(trim($_POST['current']))) || empty($_POST['target']) || false == ($target = $this->_find(trim($_POST['target']), $current)) || !isset($_POST['content']) ) { return $this->_result['error'] = 'Invalid parameters'; } $this->_logContext['target'] = $target; if (!$this->_isAllowed($target, 'write')) { return $this->_result['error'] = 'Access denied'; } if (false === file_put_contents($target, trim($_POST['content']))) { return $this->_result['error'] = 'Unable to write to file'; } $this->_result['target'] = $this->_info($target); // $this->_result['select'] = array($this->_hash($target)); } /** * Create archive of selected type * * @return void **/ protected function _archive() { $this->_checkArchivers(); if (empty($this->_options['archivers']['create']) || empty($_GET['type']) || empty($this->_options['archivers']['create'][$_GET['type']]) || !in_array($_GET['type'], $this->_options['archiveMimes'])) { return $this->_result['error'] = 'Invalid parameters'; } if (empty($_GET['current']) || empty($_GET['targets']) || !is_array($_GET['targets']) || false == ($dir = $this->_findDir(trim($_GET['current']))) || !$this->_isAllowed($dir, 'write') ) { return $this->_result['error'] = 'Invalid parameters'; } $files = array(); $argc = ''; foreach ($_GET['targets'] as $hash) { if (false == ($f = $this->_find($hash, $dir))) { return $this->_result['error'] = 'File not found'; } $files[] = $f; $argc .= escapeshellarg(basename($f)).' '; } $arc = $this->_options['archivers']['create'][$_GET['type']]; $name = count($files) == 1 ? basename($files[0]) : $_GET['name']; $name = basename($this->_uniqueName($name.'.'.$arc['ext'], '')); $cwd = getcwd(); chdir($dir); $cmd = $arc['cmd'].' '.$arc['argc'].' '.escapeshellarg($name).' '.$argc; exec($cmd, $o, $c); chdir($cwd); if (file_exists($dir.DIRECTORY_SEPARATOR.$name)) { $this->_content($dir); $this->_result['select'] = array($this->_hash($dir.DIRECTORY_SEPARATOR.$name)); } else { $this->_result['error'] = 'Unable to create archive'; } } /** * Extract files from archive * * @return void **/ protected function _extract() { if (empty($_GET['current']) || false == ($current = $this->_findDir(trim($_GET['current']))) || empty($_GET['target']) || false == ($file = $this->_find(trim($_GET['target']), $current)) || !$this->_isAllowed($current, 'write') ) { return $this->_result['error'] = 'Invalid parameters'; } $this->_checkArchivers(); $mime = $this->_mimetype($file); if (empty($this->_options['archivers']['extract'][$mime])) { return $this->_result['error'] = 'Invalid parameters'; } $cwd = getcwd(); $arc = $this->_options['archivers']['extract'][$mime]; $cmd = $arc['cmd'].' '.$arc['argc'].' '.escapeshellarg(basename($file)); chdir(dirname($file)); exec($cmd, $o, $c); chdir($cwd); if ($c == 0) { $this->_content($current, true); } else { $this->_result['error'] = 'Unable to extract files from archive'; } } /** * Send header Connection: close. Required by safari to fix bug http://www.webmasterworld.com/macintosh_webmaster/3300569.htm * * @return void **/ protected function _ping() { exit(header("Connection: close")); } /************************************************************/ /** "content" methods **/ /************************************************************/ /** * Set current dir info, content and [dirs tree] * * @param string $path current dir path * @param bool $tree set dirs tree? * @return void **/ protected function _content($path, $tree=false) { $this->_cwd($path); $this->_cdc($path); if ($tree) { $this->_result['tree'] = $this->_tree($this->_options['root']); } } /** * Set current dir info * * @param string $path current dir path * @return void **/ protected function _cwd($path) { $rel = $this->_options['rootAlias'] ? $this->_options['rootAlias'] : basename($this->_options['root']); if ($path == $this->_options['root']) { $name = $rel; } else { $name = basename($path); $rel .= DIRECTORY_SEPARATOR.substr($path, strlen($this->_options['root'])+1); } $this->_result['cwd'] = array( 'hash' => $this->_hash($path), 'name' => $name, 'mime' => 'directory', 'rel' => $rel, 'size' => 0, 'date' => date($this->_options['dateFormat'], filemtime($path)), 'read' => true, 'write' => $this->_isAllowed($path, 'write'), 'rm' => $path == $this->_options['root'] ? false : $this->_isAllowed($path, 'rm') ); } /** * Set current dir content * * @param string $path current dir path * @return void **/ protected function _cdc($path) { $dirs = $files = array(); $ls = scandir($path); for ($i=0; $i < count($ls); $i++) { if ($this->_isAccepted($ls[$i])) { $info = $this->_info($path.DIRECTORY_SEPARATOR.$ls[$i]); if ($info['mime'] == 'directory') { $dirs[] = $info; } else { $files[] = $info; } } } $this->_result['cdc'] = array_merge($dirs, $files); } /** * Return file/folder info * * @param string $path file path * @return array **/ protected function _info($path) { $type = filetype($path); $stat = $type == 'link' ? lstat($path) : stat($path); if ($stat['mtime'] > $this->_today) { $d = 'Today '.date('H:i', $stat['mtime']); } elseif ($stat['mtime'] > $this->_yesterday) { $d = 'Yesterday '.date('H:i', $stat['mtime']); } else { $d = date($this->_options['dateFormat'], $stat['mtime']); } $info = array( 'name' => htmlspecialchars(basename($path)), 'hash' => $this->_hash($path), 'mime' => $type == 'dir' ? 'directory' : $this->_mimetype($path), 'date' => $d, 'size' => $type == 'dir' ? $this->_dirSize($path) : $stat['size'], 'read' => $this->_isAllowed($path, 'read'), 'write' => $this->_isAllowed($path, 'write'), 'rm' => $this->_isAllowed($path, 'rm'), ); if ($type == 'link') { if (false == ($lpath = $this->_readlink($path))) { $info['mime'] = 'symlink-broken'; return $info; } if (is_dir($lpath)) { $info['mime'] = 'directory'; } else { $info['parent'] = $this->_hash(dirname($lpath)); $info['mime'] = $this->_mimetype($lpath); } $info['link'] = $this->_hash($lpath); $info['linkTo'] = ($this->_options['rootAlias'] ? $this->_options['rootAlias'] : basename($this->_options['root'])).substr($lpath, strlen($this->_options['root'])); $info['read'] = $this->_isAllowed($lpath, 'read'); $info['write'] = $this->_isAllowed($lpath, 'write'); $info['rm'] = $this->_isAllowed($lpath, 'rm'); } else { $lpath = ''; } if ($info['mime'] != 'directory') { if ($this->_options['fileURL'] && $info['read']) { $info['url'] = $this->_path2url($lpath ? $lpath : $path); } if (0 === ($p = strpos($info['mime'], 'image'))) { if (false != ($s = getimagesize($path))) { $info['dim'] = $s[0].'x'.$s[1]; } if ($info['read']) { $info['resize'] = isset($info['dim']) && $this->_canCreateTmb($info['mime']); $tmb = $this->_tmbPath($path); if (file_exists($tmb)) { $info['tmb'] = $this->_path2url($tmb); } elseif ($info['resize']) { $this->_result['tmb'] = true; } } } } return $info; } /** * Return directory tree (multidimensional array) * * @param string $path directory path * @return array **/ protected function _tree($path) { $dir = array( 'hash' => $this->_hash($path), 'name' => $path == $this->_options['root'] && $this->_options['rootAlias'] ? $this->_options['rootAlias'] : basename($path), 'read' => $this->_isAllowed($path, 'read'), 'write' => $this->_isAllowed($path, 'write'), 'dirs' => array() ); if ($dir['read'] && (false != ($ls = scandir($path)))) { for ($i=0; $i < count($ls); $i++) { $p = $path.DIRECTORY_SEPARATOR.$ls[$i]; if ($this->_isAccepted($ls[$i]) && is_dir($p) && !is_link($p)) { $dir['dirs'][] = $this->_tree($p); } } } return $dir; } /************************************************************/ /** fs methods **/ /************************************************************/ /** * Return name for duplicated file/folder or new archive * * @param string $f file/folder name * @param string $suffix file name suffix * @return string **/ protected function _uniqueName($f, $suffix=' copy') { $dir = dirname($f); $name = basename($f); $ext = ''; if (!is_dir($f)) { if (preg_match('/\.(tar\.gz|tar\.bz|tar\.bz2|[a-z0-9]{1,4})$/i', $name, $m)) { $ext = '.'.$m[1]; $name = substr($name, 0, strlen($name)-strlen($m[0])); } } if (preg_match('/('.$suffix.')(\d*)$/i', $name, $m)) { $i = (int)$m[2]; $name = substr($name, 0, strlen($name)-strlen($m[2])); } else { $name .= $suffix; $i = 0; $n = $dir.DIRECTORY_SEPARATOR.$name.$ext; if (!file_exists($n)) { return $n; } } while ($i++ <= 10000) { $n = $dir.DIRECTORY_SEPARATOR.$name.$i.$ext; if (!file_exists($n)) { return $n; } } return $dir.DIRECTORY_SEPARATOR.$name.md5($f).$ext; } /** * Remove file or folder (recursively) * * @param string $path fole/folder path * @return void **/ protected function _remove($path) { if (!$this->_isAllowed($path, 'rm')) { return $this->_errorData($path, 'Access denied'); } if (!is_dir($path)) { if (!@unlink($path)) { $this->_errorData($path, 'Unable to remove file'); } else { $this->_rmTmb($path); } } else { $ls = scandir($path); for ($i=0; $i < count($ls); $i++) { if ('.' != $ls[$i] && '..' != $ls[$i]) { $this->_remove($path.DIRECTORY_SEPARATOR.$ls[$i]); } } if (!@rmdir($path)) { return $this->_errorData($path, 'Unable to remove file'); } } return true; } /** * Copy file/folder (recursively) * * @param string $src file/folder to copy * @param string $trg destination name * @return bool **/ protected function _copy($src, $trg) { if (!$this->_isAllowed($src, 'read')) { return $this->_errorData($src, 'Access denied'); } $dir = dirname($trg); if (!$this->_isAllowed($dir, 'write')) { return $this->_errorData($dir, 'Access denied'); } if (file_exists($trg)) { return $this->_errorData($src, 'File or folder with the same name already exists'); } if (!is_dir($src)) { if (!@copy($src, $trg)) { return $this->_errorData($src, 'Unable to copy files'); } @chmod($trg, $this->_options['fileMode']); } else { if (!@mkdir($trg, $this->_options['dirMode'])) { return $this->_errorData($src, 'Unable to copy files'); } $ls = scandir($src); for ($i=0; $i < count($ls); $i++) { if ('.' != $ls[$i] && '..' != $ls[$i]) { $_src = $src.DIRECTORY_SEPARATOR.$ls[$i]; $_trg = $trg.DIRECTORY_SEPARATOR.$ls[$i]; if (is_dir($_src)) { if (!$this->_copy($_src, $_trg)) { return $this->_errorData($_src, 'Unable to copy files'); } } else { if (!@copy($_src, $_trg)) { return $this->_errorData($_src, 'Unable to copy files'); } @chmod($_trg, $this->_options['fileMode']); } } } } return true; } /** * Check new file name for invalid simbols. Return name if valid * * @return string $n file name * @return string **/ protected function _checkName($n) { $n = strip_tags(trim($n)); if (!$this->_options['dotFiles'] && '.' == substr($n, 0, 1)) { return false; } return preg_match('|^[^\\/\<\>:]+$|', $n) ? $n : false; } /** * Find folder by hash in required folder and subfolders * * @param string $hash folder hash * @param string $path folder path to search in * @return string **/ protected function _findDir($hash, $path='') { if (!$path) { $path = $this->_options['root']; if ($this->_hash($path) == $hash) { return $path; } } if (false != ($ls = scandir($path))) { for ($i=0; $i < count($ls); $i++) { $p = $path.DIRECTORY_SEPARATOR.$ls[$i]; if (is_link($p)) { $link = $this->_readlink($p); //$this->_result['debug']['findDir_'.$p] = 'link to '.$link; } if ($this->_isAccepted($ls[$i]) && is_dir($p) && (!is_link($p))) { if ($this->_hash($p) == $hash || false != ($p = $this->_findDir($hash, $p))) { return $p; } } } } } /** * Find file/folder by hash in required folder * * @param string $hash file/folder hash * @param string $path folder path to search in **/ protected function _find($hash, $path) { if (false != ($ls = scandir($path))) { for ($i=0; $i < count($ls); $i++) { if ($this->_isAccepted($ls[$i])) { $p = $path.DIRECTORY_SEPARATOR.$ls[$i]; if ($this->_hash($p) == $hash) { return $p; } } } } } /** * Return path of file on which link point to, if exists in root directory * * @param string $path symlink path * @return string **/ protected function _readlink($path) { $target = readlink($path); if ('/' != substr($target, 0, 1)) { $target = dirname($path).DIRECTORY_SEPARATOR.$target; } $target = $this->_normpath($target); $root = $this->_normpath($this->_options['root']); return $target && file_exists($target) && 0 === strpos($target, $root) ? $target : false; } /** * Count total directory size if this allowed in options * * @param string $path directory path * @return int **/ protected function _dirSize($path) { $size = 0; if (!$this->_options['dirSize'] || !$this->_isAllowed($path, 'read')) { return filesize($path); } if (!isset($this->_options['du'])) { $this->_options['du'] = function_exists('exec') ? exec('du -h '.escapeshellarg(__FILE__), $o, $s) > 0 && $s == 0 : false; } if ($this->_options['du']) { $size = intval(exec('du -k '.escapeshellarg($path)))*1024; } else { $ls = scandir($path); for ($i=0; $i < count($ls); $i++) { if ($this->_isAccepted($ls[$i])) { $p = $path.DIRECTORY_SEPARATOR.$ls[$i]; $size += filetype($p) == 'dir' && $this->_isAllowed($p, 'read') ? $this->_dirSize($p) : filesize($p); } } } return $size; } /** * Return file mimetype * * @param string $path file path * @return string **/ protected function _mimetype($path) { if (empty($this->_options['mimeDetect']) || $this->_options['mimeDetect'] == 'auto') { $this->_options['mimeDetect'] = $this->_getMimeDetect(); } switch ($this->_options['mimeDetect']) { case 'finfo': if (empty($this->_finfo)) { $this->_finfo = finfo_open(FILEINFO_MIME); } $type = @finfo_file($this->_finfo, $path); break; case 'php': $type = mime_content_type($path); break; case 'linux': $type = exec('file -ib '.escapeshellarg($path)); break; case 'bsd': $type = exec('file -Ib '.escapeshellarg($path)); break; default: $pinfo = pathinfo($path); $ext = isset($pinfo['extension']) ? strtolower($pinfo['extension']) : ''; $type = isset($this->_mimeTypes[$ext]) ? $this->_mimeTypes[$ext] : 'unknown;'; } $type = explode(';', $type); if ($this->_options['mimeDetect'] != 'internal' && $type[0] == 'application/octet-stream') { $pinfo = pathinfo($path); $ext = isset($pinfo['extension']) ? strtolower($pinfo['extension']) : ''; if (!empty($ext) && !empty($this->_mimeTypes[$ext])) { $type[0] = $this->_mimeTypes[$ext]; } } return $type[0]; } /************************************************************/ /** image manipulation **/ /************************************************************/ /** * Create image thumbnail * * @param string $img image file * @param string $tmb thumbnail name * @return bool **/ protected function _tmb($img, $tmb) { if (false == ($s = getimagesize($img))) { return false; } $tmbSize = $this->_options['tmbSize']; if ($this->_options['tmbCrop'] == false) { /* Calculating image scale width and height */ $xscale = $s[0] / $tmbSize; $yscale = $s[1] / $tmbSize; if ($yscale > $xscale) { $newwidth = round($s[0] * (1 / $yscale)); $newheight = round($s[1] * (1 / $yscale)); } else { $newwidth = round($s[0] * (1 / $xscale)); $newheight = round($s[1] * (1 / $xscale)); } /* Keeping original dimensions if image fitting into thumbnail without scale */ if ($s[0] <= $tmbSize && $s[1] <= $tmbSize) { $newwidth = $s[0]; $newheight = $s[1]; } /* Calculating coordinates for aligning thumbnail */ $align_y = ceil(($tmbSize - $newheight) / 2); $align_x = ceil(($tmbSize - $newwidth) / 2); } switch ($this->_options['imgLib']) { case 'imagick': try { $_img = new imagick($img); } catch (Exception $e) { return false; } $_img->contrastImage(1); if ($this->_options['tmbCrop'] == false) { $img1 = new Imagick(); $img1->newImage($tmbSize, $tmbSize, new ImagickPixel($this->_options['tmbBgColor'])); $img1->setImageFormat('png'); $_img->resizeImage($newwidth, $newheight, NULL, true); $img1->compositeImage( $_img, imagick::COMPOSITE_OVER, $align_x, $align_y ); return $img1->writeImage($tmb); } else { return $_img->cropThumbnailImage($tmbSize, $tmbSize) && $_img->writeImage($tmb); } break; case 'mogrify': if (@copy($img, $tmb)) { list($x, $y, $size) = $this->_cropPos($s[0], $s[1]); // exec('mogrify -crop '.$size.'x'.$size.'+'.$x.'+'.$y.' -scale '.$tmbSize.'x'.$tmbSize.'! '.escapeshellarg($tmb), $o, $c); $mogrifyArgs = 'mogrify -resize ' . $tmbSize . 'x' . $tmbSize; if ($this->_options['tmbCrop'] == false) { $mogrifyArgs .= ' -gravity center -background "' . $this->_options['tmbBgColor'] . '" -extent ' . $tmbSize . 'x' . $tmbSize; } if ($this->_options['tmbCrop'] == false) { $mogrifyArgs .= ' ' . escapeshellarg($tmb); } exec($mogrifyArgs, $o, $c); if (file_exists($tmb)) { return true; } elseif ($c == 0) { // find tmb for psd and animated gif $mime = $this->_mimetype($img); if ($mime == 'image/vnd.adobe.photoshop' || $mime = 'image/gif') { $pinfo = pathinfo($tmb); $test = $pinfo['dirname'].DIRECTORY_SEPARATOR.$pinfo['filename'].'-0.'.$pinfo['extension']; if (file_exists($test)) { return rename($test, $tmb); } } } } break; case 'gd': if ($s['mime'] == 'image/jpeg') { $_img = imagecreatefromjpeg($img); } elseif ($s['mime'] == 'image/png') { $_img = imagecreatefrompng($img); } elseif ($s['mime'] == 'image/gif') { $_img = imagecreatefromgif($img); } if (!$_img || false == ($_tmb = imagecreatetruecolor($tmbSize, $tmbSize))) { return false; } if ($this->_options['tmbCrop'] == false) { list($r,$g,$b) = sscanf($this->_options['tmbBgColor'], "#%02x%02x%02x"); imagefill($_tmb, 0, 0, imagecolorallocate($_tmb, $r, $g, $b)); if (!imagecopyresampled($_tmb, $_img, $align_x, $align_y, 0, 0, $newwidth, $newheight, $s[0], $s[1])) { return false; } } else { list($x, $y, $size) = $this->_cropPos($s[0], $s[1]); if (!imagecopyresampled($_tmb, $_img, 0, 0, $x, $y, $tmbSize, $tmbSize, $size, $size)) { return false; } } $r = imagepng($_tmb, $tmb, 7); imagedestroy($_img); imagedestroy($_tmb); return $r; break; } } /** * Remove image thumbnail * * @param string $img image file * @return void **/ protected function _rmTmb($img) { if ($this->_options['tmbDir'] && false != ($tmb = $this->_tmbPath($img)) && file_exists($tmb)) { @unlink($tmb); } } /** * Return x/y coord for crop image thumbnail * * @param int $w image width * @param int $h image height * @return array **/ protected function _cropPos($w, $h) { $x = $y = 0; $size = min($w, $h); if ($w > $h) { $x = ceil(($w - $h)/2); } else { $y = ceil(($h - $w)/2); } return array($x, $y, $size); } /** * Resize image * * @param string $img image path * @param int $w image width * @param int $h image height * @return bool **/ protected function _resizeImg($img, $w, $h) { if (false == ($s = getimagesize($img))) { return false; } switch ($this->_options['imgLib']) { case 'imagick': if (false != ($_img = new imagick($img))) { return $_img->cropThumbnailImage($w, $h) && $_img->writeImage($img); } break; case 'mogrify': exec('mogrify -scale '.$w.'x'.$h.'! '.escapeshellarg($img), $o, $c); return 0 == $c; break; case 'gd': if ($s['mime'] == 'image/jpeg') { $_img = imagecreatefromjpeg($img); } elseif ($s['mime'] = 'image/png') { $_img = imagecreatefrompng($img); } elseif ($s['mime'] = 'image/gif') { $_img = imagecreatefromgif($img); } if (!$_img || false == ($_out = imagecreatetruecolor($w, $h))) { return false; } if (!imagecopyresampled($_out, $_img, 0, 0, 0, 0, $w, $h, $s[0], $s[1])) { return false; } if ($s['mime'] == 'image/jpeg') { $r = imagejpeg($_out, $img, 100); } else if ($s['mime'] = 'image/png') { $r = imagepng($_out, $img, 7); } else { $r = imagegif($_out, $img, 7); } imagedestroy($_img); imagedestroy($_out); return $r; break; } } /** * Return true if we can create thumbnail for file with this mimetype * * @param string $mime file mimetype * @return bool **/ protected function _canCreateTmb($mime) { if ($this->_options['tmbDir'] && $this->_options['imgLib'] && 0 === strpos($mime, 'image')) { if ('gd' == $this->_options['imgLib']) { return $mime == 'image/jpeg' || $mime == 'image/png' || $mime == 'image/gif'; } return true; } } /** * Return image thumbnail path. For thumbnail return itself * * @param string $path image path * @return string **/ protected function _tmbPath($path) { $tmb = ''; if ($this->_options['tmbDir']) { $tmb = dirname($path) != $this->_options['tmbDir'] ? $this->_options['tmbDir'].DIRECTORY_SEPARATOR.$this->_hash($path).'.png' : $path; } return $tmb; } /************************************************************/ /** access control **/ /************************************************************/ /** * Return true if file's mimetype is allowed for upload * * @param string $name file name * @param string $tmpName uploaded file tmp name * @return bool **/ protected function _isUploadAllow($name, $tmpName) { $allow = false; $deny = false; $mime = $this->_mimetype($this->_options['mimeDetect'] != 'internal' ? $tmpName : $name); if (in_array('all', $this->_options['uploadAllow'])) { $allow = true; } else { foreach ($this->_options['uploadAllow'] as $type) { if (0 === strpos($mime, $type)) { $allow = true; } } } if (in_array('all', $this->_options['uploadDeny'])) { $deny = true; } else { foreach ($this->_options['uploadDeny'] as $type) { if (0 === strpos($mime, $type)) { $deny = true; } } } $this->_result['debug']['_isUploadAllow'][$name] = $mime; if (0 === strpos($this->_options['uploadOrder'], 'allow')) { // ,deny if ($deny == true) { return false; } elseif ($allow == true) { return true; } else { return false; } } else { // deny,allow if ($allow == true) { return true; } elseif ($deny == true) { return false; } else { return true; } } } /** * Return true if file name is not . or .. * If file name begins with . return value according to $this->_options['dotFiles'] * * @param string $file file name * @return bool **/ protected function _isAccepted($file) { if ('.' == $file || '..' == $file) { return false; } if (!$this->_options['dotFiles'] && '.' == substr($file, 0, 1)) { return false; } return true; } /** * Return true if requeired action allowed to file/folder * * @param string $path file/folder path * @param string $action action name (read/write/rm) * @return void **/ protected function _isAllowed($path, $action) { switch ($action) { case 'read': if (!is_readable($path)) { return false; } break; case 'write': if (!is_writable($path)) { return false; } break; case 'rm': if (!is_writable(dirname($path))) { return false; } break; } // if ($this->_options['aclObj']) { // // } $path = substr($path, strlen($this->_options['root'])+1); // echo "$path\n"; foreach ($this->_options['perms'] as $regex => $rules) { if (preg_match($regex, $path)) { if (isset($rules[$action])) { return $rules[$action]; } } } return isset($this->_options['defaults'][$action]) ? $this->_options['defaults'][$action] : false; } /************************************************************/ /** utilites **/ /************************************************************/ /** * Return image manipalation library name * * @return string **/ protected function _getImgLib() { if (extension_loaded('imagick')) { return 'imagick'; } elseif (function_exists('exec')) { exec('mogrify --version', $o, $c); if ($c == 0) { return 'mogrify'; } } return function_exists('gd_info') ? 'gd' : ''; } /** * Return list of available archivers * * @return array **/ protected function _checkArchivers() { if (!function_exists('exec')) { $this->_options['archivers'] = $this->_options['archive'] = array(); return; } $arcs = array( 'create' => array(), 'extract' => array() ); exec('tar --version', $o, $ctar); if ($ctar == 0) { $arcs['create']['application/x-tar'] = array('cmd' => 'tar', 'argc' => '-cf', 'ext' => 'tar'); $arcs['extract']['application/x-tar'] = array('cmd' => 'tar', 'argc' => '-xf', 'ext' => 'tar'); $test = exec('gzip --version', $o, $c); if ($c == 0) { $arcs['create']['application/x-gzip'] = array('cmd' => 'tar', 'argc' => '-czf', 'ext' => 'tgz'); $arcs['extract']['application/x-gzip'] = array('cmd' => 'tar', 'argc' => '-xzf', 'ext' => 'tgz'); } $test = exec('bzip2 --version', $o, $c); if ($c == 0) { $arcs['create']['application/x-bzip2'] = array('cmd' => 'tar', 'argc' => '-cjf', 'ext' => 'tbz'); $arcs['extract']['application/x-bzip2'] = array('cmd' => 'tar', 'argc' => '-xjf', 'ext' => 'tbz'); } } exec('zip --version', $o, $c); if ($c == 0) { $arcs['create']['application/zip'] = array('cmd' => 'zip', 'argc' => '-r9', 'ext' => 'zip'); } exec('unzip --help', $o, $c); if ($c == 0) { $arcs['extract']['application/zip'] = array('cmd' => 'unzip', 'argc' => '', 'ext' => 'zip'); } exec('rar --version', $o, $c); if ($c == 0 || $c == 7) { $arcs['create']['application/x-rar'] = array('cmd' => 'rar', 'argc' => 'a -inul', 'ext' => 'rar'); $arcs['extract']['application/x-rar'] = array('cmd' => 'rar', 'argc' => 'x -y', 'ext' => 'rar'); } else { $test = exec('unrar', $o, $c); if ($c==0 || $c == 7) { $arcs['extract']['application/x-rar'] = array('cmd' => 'unrar', 'argc' => 'x -y', 'ext' => 'rar'); } } exec('7za --help', $o, $c); if ($c == 0) { $arcs['create']['application/x-7z-compressed'] = array('cmd' => '7za', 'argc' => 'a', 'ext' => '7z'); $arcs['extract']['application/x-7z-compressed'] = array('cmd' => '7za', 'argc' => 'e -y', 'ext' => '7z'); if (empty($arcs['create']['application/x-gzip'])) { $arcs['create']['application/x-gzip'] = array('cmd' => '7za', 'argc' => 'a -tgzip', 'ext' => 'tar.gz'); } if (empty($arcs['extract']['application/x-gzip'])) { $arcs['extract']['application/x-gzip'] = array('cmd' => '7za', 'argc' => 'e -tgzip -y', 'ext' => 'tar.gz'); } if (empty($arcs['create']['application/x-bzip2'])) { $arcs['create']['application/x-bzip2'] = array('cmd' => '7za', 'argc' => 'a -tbzip2', 'ext' => 'tar.bz'); } if (empty($arcs['extract']['application/x-bzip2'])) { $arcs['extract']['application/x-bzip2'] = array('cmd' => '7za', 'argc' => 'a -tbzip2 -y', 'ext' => 'tar.bz'); } if (empty($arcs['create']['application/zip'])) { $arcs['create']['application/zip'] = array('cmd' => '7za', 'argc' => 'a -tzip -l', 'ext' => 'zip'); } if (empty($arcs['extract']['application/zip'])) { $arcs['extract']['application/zip'] = array('cmd' => '7za', 'argc' => 'e -tzip -y', 'ext' => 'zip'); } if (empty($arcs['create']['application/x-tar'])) { $arcs['create']['application/x-tar'] = array('cmd' => '7za', 'argc' => 'a -ttar -l', 'ext' => 'tar'); } if (empty($arcs['extract']['application/x-tar'])) { $arcs['extract']['application/x-tar'] = array('cmd' => '7za', 'argc' => 'e -ttar -y', 'ext' => 'tar'); } } $this->_options['archivers'] = $arcs; foreach ($this->_options['archiveMimes'] as $k=>$mime) { if (!isset($this->_options['archivers']['create'][$mime])) { unset($this->_options['archiveMimes'][$k]); } } if (empty($this->_options['archiveMimes'])) { $this->_options['archiveMimes'] = array_keys($this->_options['archivers']['create']); } } /** * Return mimetype detect method name * * @return string **/ protected function _getMimeDetect() { if (class_exists('finfo')) { return 'finfo'; } elseif (function_exists('mime_content_type') && (mime_content_type(__FILE__) == 'text/x-php' || mime_content_type(__FILE__) == 'text/x-c++')) { return 'mime_content_type'; } elseif (function_exists('exec')) { $type = exec('file -ib '.escapeshellarg(__FILE__)); if (0 === strpos($type, 'text/x-php') || 0 === strpos($type, 'text/x-c++')) { return 'linux'; } $type = exec('file -Ib '.escapeshellarg(__FILE__)); if (0 === strpos($type, 'text/x-php') || 0 === strpos($type, 'text/x-c++')) { return 'bsd'; } } return 'internal'; } /** * Return file path hash * * @param string $path * @return string **/ protected function _hash($path) { return md5($path); } /** * Return file URL * * @param string $path * @return string **/ protected function _path2url($path) { $dir = substr(dirname($path), strlen($this->_options['root'])+1); $file = rawurlencode(basename($path)); return $this->_options['URL'].($dir ? str_replace(DIRECTORY_SEPARATOR, '/', $dir).'/' : '').$file; } /** * Return normalized path, this works the same as os.path.normpath() in Python * * @param string $path path * @return string **/ protected function _normpath($path) { if (empty($path)) return '.'; if (strpos($path, '/') === 0) $initial_slashes = true; else $initial_slashes = false; if ( ($initial_slashes) && (strpos($path, '//') === 0) && (strpos($path, '///') === false) ) $initial_slashes = 2; $initial_slashes = (int) $initial_slashes; $comps = explode('/', $path); $new_comps = array(); foreach ($comps as $comp) { if (in_array($comp, array('', '.'))) continue; if ( ($comp != '..') || (!$initial_slashes && !$new_comps) || ($new_comps && (end($new_comps) == '..')) ) array_push($new_comps, $comp); elseif ($new_comps) array_pop($new_comps); } $comps = $new_comps; $path = implode('/', $comps); if ($initial_slashes) $path = str_repeat('/', $initial_slashes) . $path; if ($path) return $path; else return '.'; } /** * Pack error message in $this->_result['errorData'] * * @param string $path path to file * @param string $msg error message * @return bool always false **/ protected function _errorData($path, $msg) { $path = preg_replace('|^'.preg_quote($this->_options['root']).'|', $this->_fakeRoot, $path); if (!isset($this->_result['errorData'])) { $this->_result['errorData'] = array(); } $this->_result['errorData'][$path] = $msg; return false; } protected function _utime() { $time = explode(" ", microtime()); return (double)$time[1] + (double)$time[0]; } }