File indexing completed on 2025-03-09 05:24:41
0001 <?php 0002 0003 /** 0004 * elFinder - file manager for web. 0005 * Core class. 0006 * 0007 * @package elfinder 0008 * @author Dmitry (dio) Levashov 0009 * @author Troex Nevelin 0010 * @author Alexey Sukhotin 0011 **/ 0012 class elFinder { 0013 0014 /** 0015 * API version number 0016 * 0017 * @var string 0018 **/ 0019 protected $version = '2.0'; 0020 0021 /** 0022 * Storages (root dirs) 0023 * 0024 * @var array 0025 **/ 0026 protected $volumes = array(); 0027 0028 /** 0029 * Mounted volumes count 0030 * Required to create unique volume id 0031 * 0032 * @var int 0033 **/ 0034 public static $volumesCnt = 1; 0035 0036 /** 0037 * Default root (storage) 0038 * 0039 * @var elFinderStorageDriver 0040 **/ 0041 protected $default = null; 0042 0043 /** 0044 * Commands and required arguments list 0045 * 0046 * @var array 0047 **/ 0048 protected $commands = array( 0049 'open' => array('target' => false, 'tree' => false, 'init' => false, 'mimes' => false), 0050 'ls' => array('target' => true, 'mimes' => false), 0051 'tree' => array('target' => true), 0052 'parents' => array('target' => true), 0053 'tmb' => array('targets' => true), 0054 'file' => array('target' => true, 'download' => false), 0055 'size' => array('targets' => true), 0056 'mkdir' => array('target' => true, 'name' => true), 0057 'mkfile' => array('target' => true, 'name' => true, 'mimes' => false), 0058 'rm' => array('targets' => true), 0059 'rename' => array('target' => true, 'name' => true, 'mimes' => false), 0060 'duplicate' => array('targets' => true, 'suffix' => false), 0061 'paste' => array('dst' => true, 'targets' => true, 'cut' => false, 'mimes' => false), 0062 'upload' => array('target' => true, 'FILES' => true, 'mimes' => false, 'html' => false), 0063 'get' => array('target' => true), 0064 'put' => array('target' => true, 'content' => '', 'mimes' => false), 0065 'archive' => array('targets' => true, 'type' => true, 'mimes' => false), 0066 'extract' => array('target' => true, 'mimes' => false), 0067 'search' => array('q' => true, 'mimes' => false), 0068 'info' => array('targets' => true), 0069 'dim' => array('target' => true), 0070 'resize' => array('target' => true, 'width' => true, 'height' => true, 'mode' => false, 'x' => false, 'y' => false, 'degree' => false) 0071 ); 0072 0073 /** 0074 * Commands listeners 0075 * 0076 * @var array 0077 **/ 0078 protected $listeners = array(); 0079 0080 /** 0081 * script work time for debug 0082 * 0083 * @var string 0084 **/ 0085 protected $time = 0; 0086 /** 0087 * Is elFinder init correctly? 0088 * 0089 * @var bool 0090 **/ 0091 protected $loaded = false; 0092 /** 0093 * Send debug to client? 0094 * 0095 * @var string 0096 **/ 0097 protected $debug = false; 0098 0099 /** 0100 * undocumented class variable 0101 * 0102 * @var string 0103 **/ 0104 protected $uploadDebug = ''; 0105 0106 /** 0107 * Errors from not mounted volumes 0108 * 0109 * @var array 0110 **/ 0111 public $mountErrors = array(); 0112 0113 // Errors messages 0114 const ERROR_UNKNOWN = 'errUnknown'; 0115 const ERROR_UNKNOWN_CMD = 'errUnknownCmd'; 0116 const ERROR_CONF = 'errConf'; 0117 const ERROR_CONF_NO_JSON = 'errJSON'; 0118 const ERROR_CONF_NO_VOL = 'errNoVolumes'; 0119 const ERROR_INV_PARAMS = 'errCmdParams'; 0120 const ERROR_OPEN = 'errOpen'; 0121 const ERROR_DIR_NOT_FOUND = 'errFolderNotFound'; 0122 const ERROR_FILE_NOT_FOUND = 'errFileNotFound'; // 'File not found.' 0123 const ERROR_TRGDIR_NOT_FOUND = 'errTrgFolderNotFound'; // 'Target folder "$1" not found.' 0124 const ERROR_NOT_DIR = 'errNotFolder'; 0125 const ERROR_NOT_FILE = 'errNotFile'; 0126 const ERROR_PERM_DENIED = 'errPerm'; 0127 const ERROR_LOCKED = 'errLocked'; // '"$1" is locked and can not be renamed, moved or removed.' 0128 const ERROR_EXISTS = 'errExists'; // 'File named "$1" already exists.' 0129 const ERROR_INVALID_NAME = 'errInvName'; // 'Invalid file name.' 0130 const ERROR_MKDIR = 'errMkdir'; 0131 const ERROR_MKFILE = 'errMkfile'; 0132 const ERROR_RENAME = 'errRename'; 0133 const ERROR_COPY = 'errCopy'; 0134 const ERROR_MOVE = 'errMove'; 0135 const ERROR_COPY_FROM = 'errCopyFrom'; 0136 const ERROR_COPY_TO = 'errCopyTo'; 0137 const ERROR_COPY_ITSELF = 'errCopyInItself'; 0138 const ERROR_REPLACE = 'errReplace'; // 'Unable to replace "$1".' 0139 const ERROR_RM = 'errRm'; // 'Unable to remove "$1".' 0140 const ERROR_RM_SRC = 'errRmSrc'; // 'Unable remove source file(s)' 0141 const ERROR_UPLOAD = 'errUpload'; // 'Upload error.' 0142 const ERROR_UPLOAD_FILE = 'errUploadFile'; // 'Unable to upload "$1".' 0143 const ERROR_UPLOAD_NO_FILES = 'errUploadNoFiles'; // 'No files found for upload.' 0144 const ERROR_UPLOAD_TOTAL_SIZE = 'errUploadTotalSize'; // 'Data exceeds the maximum allowed size.' 0145 const ERROR_UPLOAD_FILE_SIZE = 'errUploadFileSize'; // 'File exceeds maximum allowed size.' 0146 const ERROR_UPLOAD_FILE_MIME = 'errUploadMime'; // 'File type not allowed.' 0147 const ERROR_UPLOAD_TRANSFER = 'errUploadTransfer'; // '"$1" transfer error.' 0148 // const ERROR_ACCESS_DENIED = 'errAccess'; 0149 const ERROR_NOT_REPLACE = 'errNotReplace'; // Object "$1" already exists at this location and can not be replaced with object of another type. 0150 const ERROR_SAVE = 'errSave'; 0151 const ERROR_EXTRACT = 'errExtract'; 0152 const ERROR_ARCHIVE = 'errArchive'; 0153 const ERROR_NOT_ARCHIVE = 'errNoArchive'; 0154 const ERROR_ARCHIVE_TYPE = 'errArcType'; 0155 const ERROR_ARC_SYMLINKS = 'errArcSymlinks'; 0156 const ERROR_ARC_MAXSIZE = 'errArcMaxSize'; 0157 const ERROR_RESIZE = 'errResize'; 0158 const ERROR_UNSUPPORT_TYPE = 'errUsupportType'; 0159 const ERROR_NOT_UTF8_CONTENT = 'errNotUTF8Content'; 0160 0161 /** 0162 * Constructor 0163 * 0164 * @param array elFinder and roots configurations 0165 * @return void 0166 * @author Dmitry (dio) Levashov 0167 **/ 0168 public function __construct($opts) { 0169 0170 $this->time = $this->utime(); 0171 $this->debug = (isset($opts['debug']) && $opts['debug'] ? true : false); 0172 0173 setlocale(LC_ALL, !empty($opts['locale']) ? $opts['locale'] : 'en_US.UTF-8'); 0174 0175 // bind events listeners 0176 if (!empty($opts['bind']) && is_array($opts['bind'])) { 0177 foreach ($opts['bind'] as $cmd => $handler) { 0178 $this->bind($cmd, $handler); 0179 } 0180 } 0181 0182 // "mount" volumes 0183 if (isset($opts['roots']) && is_array($opts['roots'])) { 0184 0185 foreach ($opts['roots'] as $i => $o) { 0186 $class = 'elFinderVolume'.(isset($o['driver']) ? $o['driver'] : ''); 0187 0188 if (class_exists($class)) { 0189 $volume = new $class(); 0190 0191 if ($volume->mount($o)) { 0192 // unique volume id (ends on "_") - used as prefix to files hash 0193 $id = $volume->id(); 0194 0195 $this->volumes[$id] = $volume; 0196 if (!$this->default && $volume->isReadable()) { 0197 $this->default = $this->volumes[$id]; 0198 } 0199 } else { 0200 $this->mountErrors[] = 'Driver "'.$class.'" : '.implode(' ', $volume->error()); 0201 } 0202 } else { 0203 $this->mountErrors[] = 'Driver "'.$class.'" does not exists'; 0204 } 0205 } 0206 } 0207 // if at least one redable volume - ii desu >_< 0208 $this->loaded = !empty($this->default); 0209 } 0210 0211 /** 0212 * Return true if fm init correctly 0213 * 0214 * @return bool 0215 * @author Dmitry (dio) Levashov 0216 **/ 0217 public function loaded() { 0218 return $this->loaded; 0219 } 0220 0221 /** 0222 * Return version (api) number 0223 * 0224 * @return string 0225 * @author Dmitry (dio) Levashov 0226 **/ 0227 public function version() { 0228 return $this->version; 0229 } 0230 0231 /** 0232 * Add handler to elFinder command 0233 * 0234 * @param string command name 0235 * @param string|array callback name or array(object, method) 0236 * @return elFinder 0237 * @author Dmitry (dio) Levashov 0238 **/ 0239 public function bind($cmd, $handler) { 0240 $cmds = array_map('trim', explode(' ', $cmd)); 0241 0242 foreach ($cmds as $cmd) { 0243 if ($cmd) { 0244 if (!isset($this->listeners[$cmd])) { 0245 $this->listeners[$cmd] = array(); 0246 } 0247 0248 if ((is_array($handler) && count($handler) == 2 && is_object($handler[0]) && method_exists($handler[0], $handler[1])) 0249 || function_exists($handler)) { 0250 $this->listeners[$cmd][] = $handler; 0251 } 0252 } 0253 } 0254 0255 return $this; 0256 } 0257 0258 /** 0259 * Remove event (command exec) handler 0260 * 0261 * @param string command name 0262 * @param string|array callback name or array(object, method) 0263 * @return elFinder 0264 * @author Dmitry (dio) Levashov 0265 **/ 0266 public function unbind($cmd, $handler) { 0267 if (!empty($this->listeners[$cmd])) { 0268 foreach ($this->listeners[$cmd] as $i => $h) { 0269 if ($h === $handler) { 0270 unset($this->listeners[$cmd][$i]); 0271 return $this; 0272 } 0273 } 0274 } 0275 return $this; 0276 } 0277 0278 /** 0279 * Return true if command exists 0280 * 0281 * @param string command name 0282 * @return bool 0283 * @author Dmitry (dio) Levashov 0284 **/ 0285 public function commandExists($cmd) { 0286 return $this->loaded && isset($this->commands[$cmd]) && method_exists($this, $cmd); 0287 } 0288 0289 /** 0290 * Return command required arguments info 0291 * 0292 * @param string command name 0293 * @return array 0294 * @author Dmitry (dio) Levashov 0295 **/ 0296 public function commandArgsList($cmd) { 0297 return $this->commandExists($cmd) ? $this->commands[$cmd] : array(); 0298 } 0299 0300 /** 0301 * Exec command and return result 0302 * 0303 * @param string $cmd command name 0304 * @param array $args command arguments 0305 * @return array 0306 * @author Dmitry (dio) Levashov 0307 **/ 0308 public function exec($cmd, $args) { 0309 0310 if (!$this->loaded) { 0311 return array('error' => $this->error(self::ERROR_CONF, self::ERROR_CONF_NO_VOL)); 0312 } 0313 0314 if (!$this->commandExists($cmd)) { 0315 return array('error' => $this->error(self::ERROR_UNKNOWN_CMD)); 0316 } 0317 0318 if (!empty($args['mimes']) && is_array($args['mimes'])) { 0319 foreach ($this->volumes as $id => $v) { 0320 $this->volumes[$id]->setMimesFilter($args['mimes']); 0321 } 0322 } 0323 0324 $result = $this->$cmd($args); 0325 0326 if (isset($result['removed'])) { 0327 foreach ($this->volumes as $volume) { 0328 $result['removed'] = array_merge($result['removed'], $volume->removed()); 0329 $volume->resetRemoved(); 0330 } 0331 } 0332 0333 // call handlers for this command 0334 if (!empty($this->listeners[$cmd])) { 0335 foreach ($this->listeners[$cmd] as $handler) { 0336 if ((is_array($handler) && $handler[0]->{$handler[1]}($cmd, $result, $args, $this)) 0337 || (!is_array($handler) && $handler($cmd, $result, $args, $this))) { 0338 // handler return true to force sync client after command completed 0339 $result['sync'] = true; 0340 } 0341 } 0342 } 0343 0344 // replace removed files info with removed files hashes 0345 if (!empty($result['removed'])) { 0346 $removed = array(); 0347 foreach ($result['removed'] as $file) { 0348 $removed[] = $file['hash']; 0349 } 0350 $result['removed'] = array_unique($removed); 0351 } 0352 // remove hidden files and filter files by mimetypes 0353 if (!empty($result['added'])) { 0354 $result['added'] = $this->filter($result['added']); 0355 } 0356 // remove hidden files and filter files by mimetypes 0357 if (!empty($result['changed'])) { 0358 $result['changed'] = $this->filter($result['changed']); 0359 } 0360 0361 if ($this->debug || !empty($args['debug'])) { 0362 $result['debug'] = array( 0363 'connector' => 'php', 0364 'phpver' => PHP_VERSION, 0365 'time' => $this->utime() - $this->time, 0366 'memory' => (function_exists('memory_get_peak_usage') ? ceil(memory_get_peak_usage()/1024).'Kb / ' : '').ceil(memory_get_usage()/1024).'Kb / '.ini_get('memory_limit'), 0367 'upload' => $this->uploadDebug, 0368 'volumes' => array(), 0369 'mountErrors' => $this->mountErrors 0370 ); 0371 0372 foreach ($this->volumes as $id => $volume) { 0373 $result['debug']['volumes'][] = $volume->debug(); 0374 } 0375 } 0376 0377 foreach ($this->volumes as $volume) { 0378 $volume->umount(); 0379 } 0380 0381 return $result; 0382 } 0383 0384 /** 0385 * Return file real path 0386 * 0387 * @param string $hash file hash 0388 * @return string 0389 * @author Dmitry (dio) Levashov 0390 **/ 0391 public function realpath($hash) { 0392 if (($volume = $this->volume($hash)) == false) { 0393 return false; 0394 } 0395 return $volume->realpath($hash); 0396 } 0397 0398 /***************************************************************************/ 0399 /* commands */ 0400 /***************************************************************************/ 0401 0402 /** 0403 * Normalize error messages 0404 * 0405 * @return array 0406 * @author Dmitry (dio) Levashov 0407 **/ 0408 public function error() { 0409 $errors = array(); 0410 0411 foreach (func_get_args() as $msg) { 0412 if (is_array($msg)) { 0413 $errors = array_merge($errors, $msg); 0414 } else { 0415 $errors[] = $msg; 0416 } 0417 } 0418 0419 return count($errors) ? $errors : array(self::ERROR_UNKNOWN); 0420 } 0421 0422 /** 0423 * "Open" directory 0424 * Return array with following elements 0425 * - cwd - opened dir info 0426 * - files - opened dir content [and dirs tree if $args[tree]] 0427 * - api - api version (if $args[init]) 0428 * - uplMaxSize - if $args[init] 0429 * - error - on failed 0430 * 0431 * @param array command arguments 0432 * @return array 0433 * @author Dmitry (dio) Levashov 0434 **/ 0435 protected function open($args) { 0436 $target = $args['target']; 0437 $init = !empty($args['init']); 0438 $tree = !empty($args['tree']); 0439 $volume = $this->volume($target); 0440 $cwd = $volume ? $volume->dir($target, true) : false; 0441 $hash = $init ? 'default folder' : '#'.$target; 0442 0443 // on init request we can get invalid dir hash - 0444 // dir which can not be opened now, but remembered by client, 0445 // so open default dir 0446 if ((!$cwd || !$cwd['read']) && $init) { 0447 $volume = $this->default; 0448 $cwd = $volume->dir($volume->defaultPath(), true); 0449 } 0450 0451 if (!$cwd) { 0452 return array('error' => $this->error(self::ERROR_OPEN, $hash, self::ERROR_DIR_NOT_FOUND)); 0453 } 0454 if (!$cwd['read']) { 0455 return array('error' => $this->error(self::ERROR_OPEN, $hash, self::ERROR_PERM_DENIED)); 0456 } 0457 0458 $files = array(); 0459 0460 // get folders trees 0461 if ($args['tree']) { 0462 foreach ($this->volumes as $id => $v) { 0463 0464 if (($tree = $v->tree('', 0, $cwd['hash'])) != false) { 0465 $files = array_merge($files, $tree); 0466 } 0467 } 0468 } 0469 0470 // get current working directory files list and add to $files if not exists in it 0471 if (($ls = $volume->scandir($cwd['hash'])) === false) { 0472 return array('error' => $this->error(self::ERROR_OPEN, $cwd['name'], $volume->error())); 0473 } 0474 0475 foreach ($ls as $file) { 0476 if (!in_array($file, $files)) { 0477 $files[] = $file; 0478 } 0479 } 0480 0481 $result = array( 0482 'cwd' => $cwd, 0483 'options' => $volume->options($cwd['hash']), 0484 'files' => $files 0485 ); 0486 0487 if (!empty($args['init'])) { 0488 $result['api'] = $this->version; 0489 $result['uplMaxSize'] = ini_get('upload_max_filesize'); 0490 } 0491 0492 return $result; 0493 } 0494 0495 /** 0496 * Return dir files names list 0497 * 0498 * @param array command arguments 0499 * @return array 0500 * @author Dmitry (dio) Levashov 0501 **/ 0502 protected function ls($args) { 0503 $target = $args['target']; 0504 0505 if (($volume = $this->volume($target)) == false 0506 || ($list = $volume->ls($target)) === false) { 0507 return array('error' => $this->error(self::ERROR_OPEN, '#'.$target)); 0508 } 0509 return array('list' => $list); 0510 } 0511 0512 /** 0513 * Return subdirs for required directory 0514 * 0515 * @param array command arguments 0516 * @return array 0517 * @author Dmitry (dio) Levashov 0518 **/ 0519 protected function tree($args) { 0520 $target = $args['target']; 0521 0522 if (($volume = $this->volume($target)) == false 0523 || ($tree = $volume->tree($target)) == false) { 0524 return array('error' => $this->error(self::ERROR_OPEN, '#'.$target)); 0525 } 0526 0527 return array('tree' => $tree); 0528 } 0529 0530 /** 0531 * Return parents dir for required directory 0532 * 0533 * @param array command arguments 0534 * @return array 0535 * @author Dmitry (dio) Levashov 0536 **/ 0537 protected function parents($args) { 0538 $target = $args['target']; 0539 0540 if (($volume = $this->volume($target)) == false 0541 || ($tree = $volume->parents($target)) == false) { 0542 return array('error' => $this->error(self::ERROR_OPEN, '#'.$target)); 0543 } 0544 0545 return array('tree' => $tree); 0546 } 0547 0548 /** 0549 * Return new created thumbnails list 0550 * 0551 * @param array command arguments 0552 * @return array 0553 * @author Dmitry (dio) Levashov 0554 **/ 0555 protected function tmb($args) { 0556 0557 $result = array('images' => array()); 0558 $targets = $args['targets']; 0559 0560 foreach ($targets as $target) { 0561 if (($volume = $this->volume($target)) != false 0562 && (($tmb = $volume->tmb($target)) != false)) { 0563 $result['images'][$target] = $tmb; 0564 } 0565 } 0566 return $result; 0567 } 0568 0569 /** 0570 * Required to output file in browser when volume URL is not set 0571 * Return array contains opened file pointer, root itself and required headers 0572 * 0573 * @param array command arguments 0574 * @return array 0575 * @author Dmitry (dio) Levashov 0576 **/ 0577 protected function file($args) { 0578 $target = $args['target']; 0579 $download = !empty($args['download']); 0580 $h403 = 'HTTP/1.x 403 Access Denied'; 0581 $h404 = 'HTTP/1.x 404 Not Found'; 0582 0583 if (($volume = $this->volume($target)) == false) { 0584 return array('error' => 'File not found', 'header' => $h404, 'raw' => true); 0585 } 0586 0587 if (($file = $volume->file($target)) == false) { 0588 return array('error' => 'File not found', 'header' => $h404, 'raw' => true); 0589 } 0590 0591 if (!$file['read']) { 0592 return array('error' => 'Access denied', 'header' => $h403, 'raw' => true); 0593 } 0594 0595 if (($fp = $volume->open($target)) == false) { 0596 return array('error' => 'File not found', 'header' => $h404, 'raw' => true); 0597 } 0598 0599 if ($download) { 0600 $disp = 'attachment'; 0601 $mime = 'application/octet-stream'; 0602 } else { 0603 $disp = preg_match('/^(image|text)/i', $file['mime']) || $file['mime'] == 'application/x-shockwave-flash' 0604 ? 'inline' 0605 : 'attachment'; 0606 $mime = $file['mime']; 0607 } 0608 0609 $filenameEncoded = rawurlencode($file['name']); 0610 if (strpos($filenameEncoded, '%') === false) { // ASCII only 0611 $filename = 'filename="'.$file['name'].'"'; 0612 } else { 0613 $ua = $_SERVER["HTTP_USER_AGENT"]; 0614 if (preg_match('/MSIE [4-8]/', $ua)) { // IE < 9 do not support RFC 6266 (RFC 2231/RFC 5987) 0615 $filename = 'filename="'.$filenameEncoded.'"'; 0616 } else { // RFC 6266 (RFC 2231/RFC 5987) 0617 $filename = 'filename*=UTF-8\'\''.$filenameEncoded; 0618 } 0619 } 0620 0621 $result = array( 0622 'volume' => $volume, 0623 'pointer' => $fp, 0624 'info' => $file, 0625 'header' => array( 0626 'Content-Type: '.$mime, 0627 'Content-Disposition: '.$disp.'; '.$filename, 0628 'Content-Location: '.$file['name'], 0629 'Content-Transfer-Encoding: binary', 0630 'Content-Length: '.$file['size'], 0631 'Connection: close' 0632 ) 0633 ); 0634 return $result; 0635 } 0636 0637 /** 0638 * Count total files size 0639 * 0640 * @param array command arguments 0641 * @return array 0642 * @author Dmitry (dio) Levashov 0643 **/ 0644 protected function size($args) { 0645 $size = 0; 0646 0647 foreach ($args['targets'] as $target) { 0648 if (($volume = $this->volume($target)) == false 0649 || ($file = $volume->file($target)) == false 0650 || !$file['read']) { 0651 return array('error' => $this->error(self::ERROR_OPEN, '#'.$target)); 0652 } 0653 0654 $size += $volume->size($target); 0655 } 0656 return array('size' => $size); 0657 } 0658 0659 /** 0660 * Create directory 0661 * 0662 * @param array command arguments 0663 * @return array 0664 * @author Dmitry (dio) Levashov 0665 **/ 0666 protected function mkdir($args) { 0667 $target = $args['target']; 0668 $name = $args['name']; 0669 0670 if (($volume = $this->volume($target)) == false) { 0671 return array('error' => $this->error(self::ERROR_MKDIR, $name, self::ERROR_TRGDIR_NOT_FOUND, '#'.$target)); 0672 } 0673 0674 return ($dir = $volume->mkdir($target, $name)) == false 0675 ? array('error' => $this->error(self::ERROR_MKDIR, $name, $volume->error())) 0676 : array('added' => array($dir)); 0677 } 0678 0679 /** 0680 * Create empty file 0681 * 0682 * @param array command arguments 0683 * @return array 0684 * @author Dmitry (dio) Levashov 0685 **/ 0686 protected function mkfile($args) { 0687 $target = $args['target']; 0688 $name = $args['name']; 0689 0690 if (($volume = $this->volume($target)) == false) { 0691 return array('error' => $this->error(self::ERROR_MKFILE, $name, self::ERROR_TRGDIR_NOT_FOUND, '#'.$target)); 0692 } 0693 0694 return ($file = $volume->mkfile($target, $args['name'])) == false 0695 ? array('error' => $this->error(self::ERROR_MKFILE, $name, $volume->error())) 0696 : array('added' => array($file)); 0697 } 0698 0699 /** 0700 * Rename file 0701 * 0702 * @param array $args 0703 * @return array 0704 * @author Dmitry (dio) Levashov 0705 **/ 0706 protected function rename($args) { 0707 $target = $args['target']; 0708 $name = $args['name']; 0709 0710 if (($volume = $this->volume($target)) == false 0711 || ($rm = $volume->file($target)) == false) { 0712 return array('error' => $this->error(self::ERROR_RENAME, '#'.$target, self::ERROR_FILE_NOT_FOUND)); 0713 } 0714 $rm['realpath'] = $volume->realpath($target); 0715 0716 return ($file = $volume->rename($target, $name)) == false 0717 ? array('error' => $this->error(self::ERROR_RENAME, $rm['name'], $volume->error())) 0718 : array('added' => array($file), 'removed' => array($rm)); 0719 } 0720 0721 /** 0722 * Duplicate file - create copy with "copy %d" suffix 0723 * 0724 * @param array $args command arguments 0725 * @return array 0726 * @author Dmitry (dio) Levashov 0727 **/ 0728 protected function duplicate($args) { 0729 $targets = is_array($args['targets']) ? $args['targets'] : array(); 0730 $result = array('added' => array()); 0731 $suffix = empty($args['suffix']) ? 'copy' : $args['suffix']; 0732 0733 foreach ($targets as $target) { 0734 if (($volume = $this->volume($target)) == false 0735 || ($src = $volume->file($target)) == false) { 0736 $result['warning'] = $this->error(self::ERROR_COPY, '#'.$target, self::ERROR_FILE_NOT_FOUND); 0737 break; 0738 } 0739 0740 if (($file = $volume->duplicate($target, $suffix)) == false) { 0741 $result['warning'] = $this->error($volume->error()); 0742 break; 0743 } 0744 0745 $result['added'][] = $file; 0746 } 0747 0748 return $result; 0749 } 0750 0751 /** 0752 * Remove dirs/files 0753 * 0754 * @param array command arguments 0755 * @return array 0756 * @author Dmitry (dio) Levashov 0757 **/ 0758 protected function rm($args) { 0759 $targets = is_array($args['targets']) ? $args['targets'] : array(); 0760 $result = array('removed' => array()); 0761 0762 foreach ($targets as $target) { 0763 if (($volume = $this->volume($target)) == false) { 0764 $result['warning'] = $this->error(self::ERROR_RM, '#'.$target, self::ERROR_FILE_NOT_FOUND); 0765 return $result; 0766 } 0767 if (!$volume->rm($target)) { 0768 $result['warning'] = $this->error($volume->error()); 0769 return $result; 0770 } 0771 } 0772 0773 return $result; 0774 } 0775 0776 /** 0777 * Save uploaded files 0778 * 0779 * @param array 0780 * @return array 0781 * @author Dmitry (dio) Levashov 0782 **/ 0783 protected function upload($args) { 0784 $target = $args['target']; 0785 $volume = $this->volume($target); 0786 $files = isset($args['FILES']['upload']) && is_array($args['FILES']['upload']) ? $args['FILES']['upload'] : array(); 0787 $result = array('added' => array(), 'header' => empty($args['html']) ? false : 'Content-Type: text/html; charset=utf-8'); 0788 0789 if (empty($files)) { 0790 return array('error' => $this->error(self::ERROR_UPLOAD, self::ERROR_UPLOAD_NO_FILES), 'header' => $header); 0791 } 0792 0793 if (!$volume) { 0794 return array('error' => $this->error(self::ERROR_UPLOAD, self::ERROR_TRGDIR_NOT_FOUND, '#'.$target), 'header' => $header); 0795 } 0796 0797 foreach ($files['name'] as $i => $name) { 0798 if (($error = $files['error'][$i]) > 0) { 0799 $result['warning'] = $this->error(self::ERROR_UPLOAD_FILE, $name, $error == UPLOAD_ERR_INI_SIZE || $error == UPLOAD_ERR_FORM_SIZE ? self::ERROR_UPLOAD_FILE_SIZE : self::ERROR_UPLOAD_TRANSFER); 0800 $this->uploadDebug = 'Upload error code: '.$error; 0801 break; 0802 } 0803 0804 $tmpname = $files['tmp_name'][$i]; 0805 0806 if (($fp = fopen($tmpname, 'rb')) == false) { 0807 $result['warning'] = $this->error(self::ERROR_UPLOAD_FILE, $name, self::ERROR_UPLOAD_TRANSFER); 0808 $this->uploadDebug = 'Upload error: unable open tmp file'; 0809 break; 0810 } 0811 0812 if (($file = $volume->upload($fp, $target, $name, $tmpname)) === false) { 0813 $result['warning'] = $this->error(self::ERROR_UPLOAD_FILE, $name, $volume->error()); 0814 fclose($fp); 0815 break; 0816 } 0817 0818 fclose($fp); 0819 $result['added'][] = $file; 0820 } 0821 0822 return $result; 0823 } 0824 0825 /** 0826 * Copy/move files into new destination 0827 * 0828 * @param array command arguments 0829 * @return array 0830 * @author Dmitry (dio) Levashov 0831 **/ 0832 protected function paste($args) { 0833 $dst = $args['dst']; 0834 $targets = is_array($args['targets']) ? $args['targets'] : array(); 0835 $cut = !empty($args['cut']); 0836 $error = $cut ? self::ERROR_MOVE : self::ERROR_COPY; 0837 $result = array('added' => array(), 'removed' => array()); 0838 0839 if (($dstVolume = $this->volume($dst)) == false) { 0840 return array('error' => $this->error($error, '#'.$targets[0], self::ERROR_TRGDIR_NOT_FOUND, '#'.$dst)); 0841 } 0842 0843 foreach ($targets as $target) { 0844 if (($srcVolume = $this->volume($target)) == false) { 0845 $result['warning'] = $this->error($error, '#'.$target, self::ERROR_FILE_NOT_FOUND); 0846 break; 0847 } 0848 0849 if (($file = $dstVolume->paste($srcVolume, $target, $dst, $cut)) == false) { 0850 $result['warning'] = $this->error($dstVolume->error()); 0851 break; 0852 } 0853 0854 $result['added'][] = $file; 0855 } 0856 return $result; 0857 } 0858 0859 /** 0860 * Return file content 0861 * 0862 * @param array $args command arguments 0863 * @return array 0864 * @author Dmitry (dio) Levashov 0865 **/ 0866 protected function get($args) { 0867 $target = $args['target']; 0868 $volume = $this->volume($target); 0869 0870 if (!$volume || ($file = $volume->file($target)) == false) { 0871 return array('error' => $this->error(self::ERROR_OPEN, '#'.$target, self::ERROR_FILE_NOT_FOUND)); 0872 } 0873 0874 if (($content = $volume->getContents($target)) === false) { 0875 return array('error' => $this->error(self::ERROR_OPEN, $volume->path($target), $volume->error())); 0876 } 0877 0878 $json = json_encode($content); 0879 0880 if ($json == 'null' && strlen($json) < strlen($content)) { 0881 return array('error' => $this->error(self::ERROR_NOT_UTF8_CONTENT, $volume->path($target))); 0882 } 0883 0884 return array('content' => $content); 0885 } 0886 0887 /** 0888 * Save content into text file 0889 * 0890 * @return array 0891 * @author Dmitry (dio) Levashov 0892 **/ 0893 protected function put($args) { 0894 $target = $args['target']; 0895 0896 if (($volume = $this->volume($target)) == false 0897 || ($file = $volume->file($target)) == false) { 0898 return array('error' => $this->error(self::ERROR_SAVE, '#'.$target, self::ERROR_FILE_NOT_FOUND)); 0899 } 0900 0901 if (($file = $volume->putContents($target, $args['content'])) == false) { 0902 return array('error' => $this->error(self::ERROR_SAVE, $volume->path($target), $volume->error())); 0903 } 0904 0905 return array('changed' => array($file)); 0906 } 0907 0908 /** 0909 * Extract files from archive 0910 * 0911 * @param array $args command arguments 0912 * @return array 0913 * @author Dmitry (dio) Levashov, 0914 * @author Alexey Sukhotin 0915 **/ 0916 protected function extract($args) { 0917 $target = $args['target']; 0918 $mimes = !empty($args['mimes']) && is_array($args['mimes']) ? $args['mimes'] : array(); 0919 $error = array(self::ERROR_EXTRACT, '#'.$target); 0920 0921 if (($volume = $this->volume($target)) == false 0922 || ($file = $volume->file($target)) == false) { 0923 return array('error' => $this->error(self::ERROR_EXTRACT, '#'.$target, self::ERROR_FILE_NOT_FOUND)); 0924 } 0925 0926 return ($file = $volume->extract($target)) 0927 ? array('added' => array($file)) 0928 : array('error' => $this->error(self::ERROR_EXTRACT, $volume->path($target), $volume->error())); 0929 } 0930 0931 /** 0932 * Create archive 0933 * 0934 * @param array $args command arguments 0935 * @return array 0936 * @author Dmitry (dio) Levashov, 0937 * @author Alexey Sukhotin 0938 **/ 0939 protected function archive($args) { 0940 $type = $args['type']; 0941 $targets = isset($args['targets']) && is_array($args['targets']) ? $args['targets'] : array(); 0942 0943 if (($volume = $this->volume($targets[0])) == false) { 0944 return $this->error(self::ERROR_ARCHIVE, self::ERROR_TRGDIR_NOT_FOUND); 0945 } 0946 0947 return ($file = $volume->archive($targets, $args['type'])) 0948 ? array('added' => array($file)) 0949 : array('error' => $this->error(self::ERROR_ARCHIVE, $volume->error())); 0950 } 0951 0952 /** 0953 * Search files 0954 * 0955 * @param array $args command arguments 0956 * @return array 0957 * @author Dmitry Levashov 0958 **/ 0959 protected function search($args) { 0960 $q = trim($args['q']); 0961 $mimes = !empty($args['mimes']) && is_array($args['mimes']) ? $args['mimes'] : array(); 0962 $result = array(); 0963 0964 foreach ($this->volumes as $volume) { 0965 $result = array_merge($result, $volume->search($q, $mimes)); 0966 } 0967 0968 return array('files' => $result); 0969 } 0970 0971 /** 0972 * Return file info (used by client "places" ui) 0973 * 0974 * @param array $args command arguments 0975 * @return array 0976 * @author Dmitry Levashov 0977 **/ 0978 protected function info($args) { 0979 $files = array(); 0980 0981 foreach ($args['targets'] as $hash) { 0982 if (($volume = $this->volume($hash)) != false 0983 && ($info = $volume->file($hash)) != false) { 0984 $files[] = $info; 0985 } 0986 } 0987 0988 return array('files' => $files); 0989 } 0990 0991 /** 0992 * Return image dimmensions 0993 * 0994 * @param array $args command arguments 0995 * @return array 0996 * @author Dmitry (dio) Levashov 0997 **/ 0998 protected function dim($args) { 0999 $target = $args['target']; 1000 1001 if (($volume = $this->volume($target)) != false) { 1002 $dim = $volume->dimensions($target); 1003 return $dim ? array('dim' => $dim) : array(); 1004 } 1005 return array(); 1006 } 1007 1008 /** 1009 * Resize image 1010 * 1011 * @param array command arguments 1012 * @return array 1013 * @author Dmitry (dio) Levashov 1014 * @author Alexey Sukhotin 1015 **/ 1016 protected function resize($args) { 1017 $target = $args['target']; 1018 $width = $args['width']; 1019 $height = $args['height']; 1020 $x = (int)$args['x']; 1021 $y = (int)$args['y']; 1022 $mode = $args['mode']; 1023 $bg = null; 1024 $degree = (int)$args['degree']; 1025 1026 if (($volume = $this->volume($target)) == false 1027 || ($file = $volume->file($target)) == false) { 1028 return array('error' => $this->error(self::ERROR_RESIZE, '#'.$target, self::ERROR_FILE_NOT_FOUND)); 1029 } 1030 1031 return ($file = $volume->resize($target, $width, $height, $x, $y, $mode, $bg, $degree)) 1032 ? array('changed' => array($file)) 1033 : array('error' => $this->error(self::ERROR_RESIZE, $volume->path($target), $volume->error())); 1034 } 1035 1036 /***************************************************************************/ 1037 /* utils */ 1038 /***************************************************************************/ 1039 1040 /** 1041 * Return root - file's owner 1042 * 1043 * @param string file hash 1044 * @return elFinderStorageDriver 1045 * @author Dmitry (dio) Levashov 1046 **/ 1047 protected function volume($hash) { 1048 foreach ($this->volumes as $id => $v) { 1049 if (strpos(''.$hash, $id) === 0) { 1050 return $this->volumes[$id]; 1051 } 1052 } 1053 return false; 1054 } 1055 1056 /** 1057 * Return files info array 1058 * 1059 * @param array $data one file info or files info 1060 * @return array 1061 * @author Dmitry (dio) Levashov 1062 **/ 1063 protected function toArray($data) { 1064 return isset($data['hash']) || !is_array($data) ? array($data) : $data; 1065 } 1066 1067 /** 1068 * Return fils hashes list 1069 * 1070 * @param array $files files info 1071 * @return array 1072 * @author Dmitry (dio) Levashov 1073 **/ 1074 protected function hashes($files) { 1075 $ret = array(); 1076 foreach ($files as $file) { 1077 $ret[] = $file['hash']; 1078 } 1079 return $ret; 1080 } 1081 1082 /** 1083 * Remove from files list hidden files and files with required mime types 1084 * 1085 * @param array $files files info 1086 * @return array 1087 * @author Dmitry (dio) Levashov 1088 **/ 1089 protected function filter($files) { 1090 foreach ($files as $i => $file) { 1091 if (!empty($file['hidden']) || !$this->default->mimeAccepted($file['mime'])) { 1092 unset($files[$i]); 1093 } 1094 } 1095 return array_merge($files, array()); 1096 } 1097 1098 protected function utime() { 1099 $time = explode(" ", microtime()); 1100 return (double)$time[1] + (double)$time[0]; 1101 } 1102 1103 } // END class