File indexing completed on 2024-12-22 05:35:33

0001 <?php
0002 
0003 /**
0004  * elFinder driver for local filesystem.
0005  *
0006  * @author Dmitry (dio) Levashov
0007  * @author Troex Nevelin
0008  **/
0009 class elFinderVolumeLocalFileSystem extends elFinderVolumeDriver {
0010   
0011   /**
0012    * Driver id
0013    * Must be started from letter and contains [a-z0-9]
0014    * Used as part of volume id
0015    *
0016    * @var string
0017    **/
0018   protected $driverId = 'l';
0019   
0020   /**
0021    * Required to count total archive files size
0022    *
0023    * @var int
0024    **/
0025   protected $archiveSize = 0;
0026   
0027   /**
0028    * Constructor
0029    * Extend options with required fields
0030    *
0031    * @return void
0032    * @author Dmitry (dio) Levashov
0033    **/
0034   public function __construct() {
0035     $this->options['alias']    = '';              // alias to replace root dir name
0036     $this->options['dirMode']  = 0755;            // new dirs mode
0037     $this->options['fileMode'] = 0644;            // new files mode
0038     $this->options['quarantine'] = '.quarantine';  // quarantine folder name - required to check archive (must be hidden)
0039     $this->options['maxArcFilesSize'] = 0;        // max allowed archive files size (0 - no limit)
0040   }
0041   
0042   /*********************************************************************/
0043   /*                        INIT AND CONFIGURE                         */
0044   /*********************************************************************/
0045   
0046   /**
0047    * Configure after successfull mount.
0048    *
0049    * @return void
0050    * @author Dmitry (dio) Levashov
0051    **/
0052   protected function configure() {
0053     $this->aroot = realpath($this->root);
0054     $root = $this->stat($this->root);
0055     
0056     if ($this->options['quarantine']) {
0057       $this->attributes[] = array(
0058         'pattern' => '~^'.preg_quote(DIRECTORY_SEPARATOR.$this->options['quarantine']).'$~',
0059         'read'    => false,
0060         'write'   => false,
0061         'locked'  => true,
0062         'hidden'  => true
0063       );
0064     }
0065     
0066     // chek thumbnails path
0067     if ($this->options['tmbPath']) {
0068       $this->options['tmbPath'] = strpos($this->options['tmbPath'], DIRECTORY_SEPARATOR) === false
0069         // tmb path set as dirname under root dir
0070         ? $this->root.DIRECTORY_SEPARATOR.$this->options['tmbPath']
0071         // tmb path as full path
0072         : $this->_normpath($this->options['tmbPath']);
0073     }
0074 
0075     parent::configure();
0076     
0077     // if no thumbnails url - try detect it
0078     if ($root['read'] && !$this->tmbURL && $this->URL) {
0079       if (strpos($this->tmbPath, $this->root) === 0) {
0080         $this->tmbURL = $this->URL.str_replace(DIRECTORY_SEPARATOR, '/', substr($this->tmbPath, strlen($this->root)+1));
0081         if (preg_match("|[^/?&=]$|", $this->tmbURL)) {
0082           $this->tmbURL .= '/';
0083         }
0084       }
0085     }
0086 
0087     // check quarantine dir
0088     if (!empty($this->options['quarantine'])) {
0089       $this->quarantine = $this->root.DIRECTORY_SEPARATOR.$this->options['quarantine'];
0090       if ((!is_dir($this->quarantine) && !$this->_mkdir($this->root, $this->options['quarantine'])) || !is_writable($this->quarantine)) {
0091         $this->archivers['extract'] = array();
0092         $this->disabled[] = 'extract';
0093       }
0094     } else {
0095       $this->archivers['extract'] = array();
0096       $this->disabled[] = 'extract';
0097     }
0098     
0099   }
0100   
0101   /*********************************************************************/
0102   /*                               FS API                              */
0103   /*********************************************************************/
0104 
0105   /*********************** paths/urls *************************/
0106   
0107   /**
0108    * Return parent directory path
0109    *
0110    * @param  string  $path  file path
0111    * @return string
0112    * @author Dmitry (dio) Levashov
0113    **/
0114   protected function _dirname($path) {
0115     return dirname($path);
0116   }
0117 
0118   /**
0119    * Return file name
0120    *
0121    * @param  string  $path  file path
0122    * @return string
0123    * @author Dmitry (dio) Levashov
0124    **/
0125   protected function _basename($path) {
0126     return basename($path);
0127   }
0128 
0129   /**
0130    * Join dir name and file name and retur full path
0131    *
0132    * @param  string  $dir
0133    * @param  string  $name
0134    * @return string
0135    * @author Dmitry (dio) Levashov
0136    **/
0137   protected function _joinPath($dir, $name) {
0138     return $dir.DIRECTORY_SEPARATOR.$name;
0139   }
0140   
0141   /**
0142    * Return normalized path, this works the same as os.path.normpath() in Python
0143    *
0144    * @param  string  $path  path
0145    * @return string
0146    * @author Troex Nevelin
0147    **/
0148   protected function _normpath($path) {
0149     if (empty($path)) {
0150       return '.';
0151     }
0152 
0153     if (strpos($path, '/') === 0) {
0154       $initial_slashes = true;
0155     } else {
0156       $initial_slashes = false;
0157     }
0158       
0159     if (($initial_slashes) 
0160     && (strpos($path, '//') === 0) 
0161     && (strpos($path, '///') === false)) {
0162       $initial_slashes = 2;
0163     }
0164       
0165     $initial_slashes = (int) $initial_slashes;
0166 
0167     $comps = explode('/', $path);
0168     $new_comps = array();
0169     foreach ($comps as $comp) {
0170       if (in_array($comp, array('', '.'))) {
0171         continue;
0172       }
0173         
0174       if (($comp != '..') 
0175       || (!$initial_slashes && !$new_comps) 
0176       || ($new_comps && (end($new_comps) == '..'))) {
0177         array_push($new_comps, $comp);
0178       } elseif ($new_comps) {
0179         array_pop($new_comps);
0180       }
0181     }
0182     $comps = $new_comps;
0183     $path = implode('/', $comps);
0184     if ($initial_slashes) {
0185       $path = str_repeat('/', $initial_slashes) . $path;
0186     }
0187     
0188     return $path ? $path : '.';
0189   }
0190   
0191   /**
0192    * Return file path related to root dir
0193    *
0194    * @param  string  $path  file path
0195    * @return string
0196    * @author Dmitry (dio) Levashov
0197    **/
0198   protected function _relpath($path) {
0199     return $path == $this->root ? '' : substr($path, strlen($this->root)+1);
0200   }
0201   
0202   /**
0203    * Convert path related to root dir into real path
0204    *
0205    * @param  string  $path  file path
0206    * @return string
0207    * @author Dmitry (dio) Levashov
0208    **/
0209   protected function _abspath($path) {
0210     return $path == DIRECTORY_SEPARATOR ? $this->root : $this->root.DIRECTORY_SEPARATOR.$path;
0211   }
0212   
0213   /**
0214    * Return fake path started from root dir
0215    *
0216    * @param  string  $path  file path
0217    * @return string
0218    * @author Dmitry (dio) Levashov
0219    **/
0220   protected function _path($path) {
0221     return $this->rootName.($path == $this->root ? '' : $this->separator.$this->_relpath($path));
0222   }
0223   
0224   /**
0225    * Return true if $path is children of $parent
0226    *
0227    * @param  string  $path    path to check
0228    * @param  string  $parent  parent path
0229    * @return bool
0230    * @author Dmitry (dio) Levashov
0231    **/
0232   protected function _inpath($path, $parent) {
0233     return $path == $parent || strpos($path, $parent.DIRECTORY_SEPARATOR) === 0;
0234   }
0235   
0236   
0237   
0238   /***************** file stat ********************/
0239 
0240   /**
0241    * Return stat for given path.
0242    * Stat contains following fields:
0243    * - (int)    size    file size in b. required
0244    * - (int)    ts      file modification time in unix time. required
0245    * - (string) mime    mimetype. required for folders, others - optionally
0246    * - (bool)   read    read permissions. required
0247    * - (bool)   write   write permissions. required
0248    * - (bool)   locked  is object locked. optionally
0249    * - (bool)   hidden  is object hidden. optionally
0250    * - (string) alias   for symlinks - link target path relative to root path. optionally
0251    * - (string) target  for symlinks - link target path. optionally
0252    *
0253    * If file does not exists - returns empty array or false.
0254    *
0255    * @param  string  $path    file path 
0256    * @return array|false
0257    * @author Dmitry (dio) Levashov
0258    **/
0259   protected function _stat($path) {
0260     $stat = array();
0261 
0262     if (!file_exists($path)) {
0263       return $stat;
0264     }
0265 
0266     if ($path != $this->root && is_link($path)) {
0267       if (($target = $this->readlink($path)) == false 
0268       || $target == $path) {
0269         $stat['mime']  = 'symlink-broken';
0270         $stat['read']  = false;
0271         $stat['write'] = false;
0272         $stat['size']  = 0;
0273         return $stat;
0274       }
0275       $stat['alias']  = $this->_path($target);
0276       $stat['target'] = $target;
0277       $path  = $target;
0278       $lstat = lstat($path);
0279       $size  = $lstat['size'];
0280     } else {
0281       $size = @filesize($path);
0282     }
0283     
0284     $dir = is_dir($path);
0285     
0286     $stat['mime']  = $dir ? 'directory' : $this->mimetype($path);
0287     $stat['ts']    = filemtime($path);
0288     $stat['read']  = is_readable($path);
0289     $stat['write'] = is_writable($path);
0290     if ($stat['read']) {
0291       $stat['size'] = $dir ? 0 : $size;
0292     }
0293     
0294     return $stat;
0295   }
0296   
0297 
0298   /**
0299    * Return true if path is dir and has at least one childs directory
0300    *
0301    * @param  string  $path  dir path
0302    * @return bool
0303    * @author Dmitry (dio) Levashov
0304    **/
0305   protected function _subdirs($path) {
0306 
0307     if (($dir = dir($path))) {
0308       $dir = dir($path);
0309       while (($entry = $dir->read()) !== false) {
0310         $p = $dir->path.DIRECTORY_SEPARATOR.$entry;
0311         if ($entry != '.' && $entry != '..' && is_dir($p) && !$this->attr($p, 'hidden')) {
0312           $dir->close();
0313           return true;
0314         }
0315       }
0316       $dir->close();
0317     }
0318     return false;
0319   }
0320   
0321   /**
0322    * Return object width and height
0323    * Ususaly used for images, but can be realize for video etc...
0324    *
0325    * @param  string  $path  file path
0326    * @param  string  $mime  file mime type
0327    * @return string
0328    * @author Dmitry (dio) Levashov
0329    **/
0330   protected function _dimensions($path, $mime) {
0331     clearstatcache();
0332     return strpos($mime, 'image') === 0 && ($s = @getimagesize($path)) !== false 
0333       ? $s[0].'x'.$s[1] 
0334       : false;
0335   }
0336   /******************** file/dir content *********************/
0337   
0338   /**
0339    * Return symlink target file
0340    *
0341    * @param  string  $path  link path
0342    * @return string
0343    * @author Dmitry (dio) Levashov
0344    **/
0345   protected function readlink($path) {
0346     if (!($target = @readlink($path))) {
0347       return false;
0348     }
0349     
0350     if (substr($target, 0, 1) != DIRECTORY_SEPARATOR) {
0351       $target = dirname($path).DIRECTORY_SEPARATOR.$target;
0352     }
0353     
0354     $atarget = realpath($target);
0355     
0356     if (!$atarget) {
0357       return false;
0358     }
0359     
0360     $root  = $this->root;
0361     $aroot = $this->aroot;
0362 
0363     if ($this->_inpath($atarget, $this->aroot)) {
0364       return $this->_normpath($this->root.DIRECTORY_SEPARATOR.substr($atarget, strlen($this->aroot)+1));
0365     }
0366 
0367     return false;
0368   }
0369     
0370   /**
0371    * Return files list in directory.
0372    *
0373    * @param  string  $path  dir path
0374    * @return array
0375    * @author Dmitry (dio) Levashov
0376    **/
0377   protected function _scandir($path) {
0378     $files = array();
0379     
0380     foreach (scandir($path) as $name) {
0381       if ($name != '.' && $name != '..') {
0382         $files[] = $path.DIRECTORY_SEPARATOR.$name;
0383       }
0384     }
0385     return $files;
0386   }
0387     
0388   /**
0389    * Open file and return file pointer
0390    *
0391    * @param  string  $path  file path
0392    * @param  bool    $write open file for writing
0393    * @return resource|false
0394    * @author Dmitry (dio) Levashov
0395    **/
0396   protected function _fopen($path, $mode='rb') {
0397     return @fopen($path, 'r');
0398   }
0399   
0400   /**
0401    * Close opened file
0402    *
0403    * @param  resource  $fp  file pointer
0404    * @return bool
0405    * @author Dmitry (dio) Levashov
0406    **/
0407   protected function _fclose($fp, $path='') {
0408     return @fclose($fp);
0409   }
0410   
0411   /********************  file/dir manipulations *************************/
0412   
0413   /**
0414    * Create dir and return created dir path or false on failed
0415    *
0416    * @param  string  $path  parent dir path
0417    * @param string  $name  new directory name
0418    * @return string|bool
0419    * @author Dmitry (dio) Levashov
0420    **/
0421   protected function _mkdir($path, $name) {
0422     $path = $path.DIRECTORY_SEPARATOR.$name;
0423 
0424     if (@mkdir($path)) {
0425       @chmod($path, $this->options['dirMode']);
0426       return $path;
0427     }
0428 
0429     return false;
0430   }
0431   
0432   /**
0433    * Create file and return it's path or false on failed
0434    *
0435    * @param  string  $path  parent dir path
0436    * @param string  $name  new file name
0437    * @return string|bool
0438    * @author Dmitry (dio) Levashov
0439    **/
0440   protected function _mkfile($path, $name) {
0441     $path = $path.DIRECTORY_SEPARATOR.$name;
0442     
0443     if (($fp = @fopen($path, 'w'))) {
0444       @fclose($fp);
0445       @chmod($path, $this->options['fileMode']);
0446       return $path;
0447     }
0448     return false;
0449   }
0450   
0451   /**
0452    * Create symlink
0453    *
0454    * @param  string  $source     file to link to
0455    * @param  string  $targetDir  folder to create link in
0456    * @param  string  $name       symlink name
0457    * @return bool
0458    * @author Dmitry (dio) Levashov
0459    **/
0460   protected function _symlink($source, $targetDir, $name) {
0461     return @symlink($source, $targetDir.DIRECTORY_SEPARATOR.$name);
0462   }
0463   
0464   /**
0465    * Copy file into another file
0466    *
0467    * @param  string  $source     source file path
0468    * @param  string  $targetDir  target directory path
0469    * @param  string  $name       new file name
0470    * @return bool
0471    * @author Dmitry (dio) Levashov
0472    **/
0473   protected function _copy($source, $targetDir, $name) {
0474     return copy($source, $targetDir.DIRECTORY_SEPARATOR.$name);
0475   }
0476   
0477   /**
0478    * Move file into another parent dir.
0479    * Return new file path or false.
0480    *
0481    * @param  string  $source  source file path
0482    * @param  string  $target  target dir path
0483    * @param  string  $name    file name
0484    * @return string|bool
0485    * @author Dmitry (dio) Levashov
0486    **/
0487   protected function _move($source, $targetDir, $name) {
0488     $target = $targetDir.DIRECTORY_SEPARATOR.$name;
0489     return @rename($source, $target) ? $target : false;
0490   }
0491     
0492   /**
0493    * Remove file
0494    *
0495    * @param  string  $path  file path
0496    * @return bool
0497    * @author Dmitry (dio) Levashov
0498    **/
0499   protected function _unlink($path) {
0500     return @unlink($path);
0501   }
0502 
0503   /**
0504    * Remove dir
0505    *
0506    * @param  string  $path  dir path
0507    * @return bool
0508    * @author Dmitry (dio) Levashov
0509    **/
0510   protected function _rmdir($path) {
0511     return @rmdir($path);
0512   }
0513   
0514   /**
0515    * Create new file and write into it from file pointer.
0516    * Return new file path or false on error.
0517    *
0518    * @param  resource  $fp   file pointer
0519    * @param  string    $dir  target dir path
0520    * @param  string    $name file name
0521    * @return bool|string
0522    * @author Dmitry (dio) Levashov
0523    **/
0524   protected function _save($fp, $dir, $name, $mime, $w, $h) {
0525     $path = $dir.DIRECTORY_SEPARATOR.$name;
0526 
0527     if (!($target = @fopen($path, 'wb'))) {
0528       return false;
0529     }
0530 
0531     while (!feof($fp)) {
0532       fwrite($target, fread($fp, 8192));
0533     }
0534     fclose($target);
0535     @chmod($path, $this->options['fileMode']);
0536     clearstatcache();
0537     return $path;
0538   }
0539   
0540   /**
0541    * Get file contents
0542    *
0543    * @param  string  $path  file path
0544    * @return string|false
0545    * @author Dmitry (dio) Levashov
0546    **/
0547   protected function _getContents($path) {
0548     return file_get_contents($path);
0549   }
0550   
0551   /**
0552    * Write a string to a file
0553    *
0554    * @param  string  $path     file path
0555    * @param  string  $content  new file content
0556    * @return bool
0557    * @author Dmitry (dio) Levashov
0558    **/
0559   protected function _filePutContents($path, $content) {
0560     if (@file_put_contents($path, $content, LOCK_EX) !== false) {
0561       clearstatcache();
0562       return true;
0563     }
0564     return false;
0565   }
0566 
0567   /**
0568    * Detect available archivers
0569    *
0570    * @return void
0571    **/
0572   protected function _checkArchivers() {
0573     if (!function_exists('exec')) {
0574       $this->options['archivers'] = $this->options['archive'] = array();
0575       return;
0576     }
0577     $arcs = array(
0578       'create'  => array(),
0579       'extract' => array()
0580       );
0581     
0582     //exec('tar --version', $o, $ctar);
0583     $this->procExec('tar --version', $o, $ctar);
0584 
0585     if ($ctar == 0) {
0586       $arcs['create']['application/x-tar']  = array('cmd' => 'tar', 'argc' => '-cf', 'ext' => 'tar');
0587       $arcs['extract']['application/x-tar'] = array('cmd' => 'tar', 'argc' => '-xf', 'ext' => 'tar');
0588       //$test = exec('gzip --version', $o, $c);
0589       unset($o);
0590       $test = $this->procExec('gzip --version', $o, $c);
0591 
0592       if ($c == 0) {
0593         $arcs['create']['application/x-gzip']  = array('cmd' => 'tar', 'argc' => '-czf', 'ext' => 'tgz');
0594         $arcs['extract']['application/x-gzip'] = array('cmd' => 'tar', 'argc' => '-xzf', 'ext' => 'tgz');
0595       }
0596       unset($o);
0597       //$test = exec('bzip2 --version', $o, $c);
0598       $test = $this->procExec('bzip2 --version', $o, $c);
0599       if ($c == 0) {
0600         $arcs['create']['application/x-bzip2']  = array('cmd' => 'tar', 'argc' => '-cjf', 'ext' => 'tbz');
0601         $arcs['extract']['application/x-bzip2'] = array('cmd' => 'tar', 'argc' => '-xjf', 'ext' => 'tbz');
0602       }
0603     }
0604     unset($o);
0605     //exec('zip --version', $o, $c);
0606     $this->procExec('zip -v', $o, $c);
0607     if ($c == 0) {
0608       $arcs['create']['application/zip']  = array('cmd' => 'zip', 'argc' => '-r9', 'ext' => 'zip');
0609     }
0610     unset($o);
0611     $this->procExec('unzip --help', $o, $c);
0612     if ($c == 0) {
0613       $arcs['extract']['application/zip'] = array('cmd' => 'unzip', 'argc' => '',  'ext' => 'zip');
0614     } 
0615     unset($o);
0616     //exec('rar --version', $o, $c);
0617     $this->procExec('rar --version', $o, $c);
0618     if ($c == 0 || $c == 7) {
0619       $arcs['create']['application/x-rar']  = array('cmd' => 'rar', 'argc' => 'a -inul', 'ext' => 'rar');
0620       $arcs['extract']['application/x-rar'] = array('cmd' => 'rar', 'argc' => 'x -y',    'ext' => 'rar');
0621     } else {
0622       unset($o);
0623       //$test = exec('unrar', $o, $c);
0624       $test = $this->procExec('unrar', $o, $c);
0625       if ($c==0 || $c == 7) {
0626         $arcs['extract']['application/x-rar'] = array('cmd' => 'unrar', 'argc' => 'x -y', 'ext' => 'rar');
0627       }
0628     }
0629     unset($o);
0630     //exec('7za --help', $o, $c);
0631     $this->procExec('7za --help', $o, $c);
0632     if ($c == 0) {
0633       $arcs['create']['application/x-7z-compressed']  = array('cmd' => '7za', 'argc' => 'a', 'ext' => '7z');
0634       $arcs['extract']['application/x-7z-compressed'] = array('cmd' => '7za', 'argc' => 'e -y', 'ext' => '7z');
0635       
0636       if (empty($arcs['create']['application/x-gzip'])) {
0637         $arcs['create']['application/x-gzip'] = array('cmd' => '7za', 'argc' => 'a -tgzip', 'ext' => 'tar.gz');
0638       }
0639       if (empty($arcs['extract']['application/x-gzip'])) {
0640         $arcs['extract']['application/x-gzip'] = array('cmd' => '7za', 'argc' => 'e -tgzip -y', 'ext' => 'tar.gz');
0641       }
0642       if (empty($arcs['create']['application/x-bzip2'])) {
0643         $arcs['create']['application/x-bzip2'] = array('cmd' => '7za', 'argc' => 'a -tbzip2', 'ext' => 'tar.bz');
0644       }
0645       if (empty($arcs['extract']['application/x-bzip2'])) {
0646         $arcs['extract']['application/x-bzip2'] = array('cmd' => '7za', 'argc' => 'a -tbzip2 -y', 'ext' => 'tar.bz');
0647       }
0648       if (empty($arcs['create']['application/zip'])) {
0649         $arcs['create']['application/zip'] = array('cmd' => '7za', 'argc' => 'a -tzip -l', 'ext' => 'zip');
0650       }
0651       if (empty($arcs['extract']['application/zip'])) {
0652         $arcs['extract']['application/zip'] = array('cmd' => '7za', 'argc' => 'e -tzip -y', 'ext' => 'zip');
0653       }
0654       if (empty($arcs['create']['application/x-tar'])) {
0655         $arcs['create']['application/x-tar'] = array('cmd' => '7za', 'argc' => 'a -ttar -l', 'ext' => 'tar');
0656       }
0657       if (empty($arcs['extract']['application/x-tar'])) {
0658         $arcs['extract']['application/x-tar'] = array('cmd' => '7za', 'argc' => 'e -ttar -y', 'ext' => 'tar');
0659       }
0660     }
0661     
0662     $this->archivers = $arcs;
0663   }
0664 
0665   /**
0666    * Unpack archive
0667    *
0668    * @param  string  $path  archive path
0669    * @param  array   $arc   archiver command and arguments (same as in $this->archivers)
0670    * @return void
0671    * @author Dmitry (dio) Levashov
0672    * @author Alexey Sukhotin
0673    **/
0674   protected function _unpack($path, $arc) {
0675     $cwd = getcwd();
0676     $dir = $this->_dirname($path);
0677     chdir($dir);
0678     $cmd = $arc['cmd'].' '.$arc['argc'].' '.escapeshellarg($this->_basename($path));
0679     $this->procExec($cmd, $o, $c);
0680     chdir($cwd);
0681   }
0682 
0683   /**
0684    * Recursive symlinks search
0685    *
0686    * @param  string  $path  file/dir path
0687    * @return bool
0688    * @author Dmitry (dio) Levashov
0689    **/
0690   protected function _findSymlinks($path) {
0691     if (is_link($path)) {
0692       return true;
0693     }
0694     
0695     if (is_dir($path)) {
0696       foreach (scandir($path) as $name) {
0697         if ($name != '.' && $name != '..') {
0698           $p = $path.DIRECTORY_SEPARATOR.$name;
0699           if (is_link($p)) {
0700             return true;
0701           }
0702           if (is_dir($p) && $this->_findSymlinks($p)) {
0703             return true;
0704           } elseif (is_file($p)) {
0705             $this->archiveSize += filesize($p);
0706           }
0707         }
0708       }
0709     } else {
0710       $this->archiveSize += filesize($path);
0711     }
0712     
0713     return false;
0714   }
0715 
0716   /**
0717    * Extract files from archive
0718    *
0719    * @param  string  $path  archive path
0720    * @param  array   $arc   archiver command and arguments (same as in $this->archivers)
0721    * @return true
0722    * @author Dmitry (dio) Levashov, 
0723    * @author Alexey Sukhotin
0724    **/
0725   protected function _extract($path, $arc) {
0726     
0727     if ($this->quarantine) {
0728       $dir     = $this->quarantine.DIRECTORY_SEPARATOR.str_replace(' ', '_', microtime()).basename($path);
0729       $archive = $dir.DIRECTORY_SEPARATOR.basename($path);
0730       
0731       if (!@mkdir($dir)) {
0732         return false;
0733       }
0734       
0735       chmod($dir, 0777);
0736       
0737       // copy in quarantine
0738       if (!copy($path, $archive)) {
0739         return false;
0740       }
0741       
0742       // extract in quarantine
0743       $this->_unpack($archive, $arc);
0744       @unlink($archive);
0745       
0746       // get files list
0747       $ls = array();
0748       foreach (scandir($dir) as $i => $name) {
0749         if ($name != '.' && $name != '..') {
0750           $ls[] = $name;
0751         }
0752       }
0753       
0754       // no files - extract error ?
0755       if (empty($ls)) {
0756         return false;
0757       }
0758       
0759       $this->archiveSize = 0;
0760       
0761       // find symlinks
0762       $symlinks = $this->_findSymlinks($dir);
0763       // remove arc copy
0764       $this->remove($dir);
0765       
0766       if ($symlinks) {
0767         return $this->setError(elFinder::ERROR_ARC_SYMLINKS);
0768       }
0769 
0770       // check max files size
0771       if ($this->options['maxArcFilesSize'] > 0 && $this->options['maxArcFilesSize'] < $this->archiveSize) {
0772         return $this->setError(elFinder::ERROR_ARC_MAXSIZE);
0773       }
0774       
0775       
0776       
0777       // archive contains one item - extract in archive dir
0778       if (count($ls) == 1) {
0779         $this->_unpack($path, $arc);
0780         $result = dirname($path).DIRECTORY_SEPARATOR.$ls[0];
0781         
0782 
0783       } else {
0784         // for several files - create new directory
0785         // create unique name for directory
0786         $name = basename($path);
0787         if (preg_match('/\.((tar\.(gz|bz|bz2|z|lzo))|cpio\.gz|ps\.gz|xcf\.(gz|bz2)|[a-z0-9]{1,4})$/i', $name, $m)) {
0788           $name = substr($name, 0,  strlen($name)-strlen($m[0]));
0789         }
0790         $test = dirname($path).DIRECTORY_SEPARATOR.$name;
0791         if (file_exists($test) || is_link($test)) {
0792           $name = $this->uniqueName(dirname($path), $name, '-', false);
0793         }
0794         
0795         $result  = dirname($path).DIRECTORY_SEPARATOR.$name;
0796         $archive = $result.DIRECTORY_SEPARATOR.basename($path);
0797 
0798         if (!$this->_mkdir(dirname($path), $name) || !copy($path, $archive)) {
0799           return false;
0800         }
0801         
0802         $this->_unpack($archive, $arc);
0803         @unlink($archive);
0804       }
0805       
0806       return file_exists($result) ? $result : false;
0807     }
0808   }
0809   
0810   /**
0811    * Create archive and return its path
0812    *
0813    * @param  string  $dir    target dir
0814    * @param  array   $files  files names list
0815    * @param  string  $name   archive name
0816    * @param  array   $arc    archiver options
0817    * @return string|bool
0818    * @author Dmitry (dio) Levashov, 
0819    * @author Alexey Sukhotin
0820    **/
0821   protected function _archive($dir, $files, $name, $arc) {
0822     $cwd = getcwd();
0823     chdir($dir);
0824     
0825     $files = array_map('escapeshellarg', $files);
0826     
0827     $cmd = $arc['cmd'].' '.$arc['argc'].' '.escapeshellarg($name).' '.implode(' ', $files);
0828     $this->procExec($cmd, $o, $c);
0829     chdir($cwd);
0830 
0831     $path = $dir.DIRECTORY_SEPARATOR.$name;
0832     return file_exists($path) ? $path : false;
0833   }
0834   
0835 } // END class