PageRenderTime 45ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/common/libraries/plugin/pear/System.php

https://bitbucket.org/cbenelug/chamilo
PHP | 712 lines | 465 code | 20 blank | 227 comment | 92 complexity | 078f628739aa0141ae6a923abe2b26c0 MD5 | raw file
Possible License(s): GPL-3.0, MIT, GPL-2.0, BSD-3-Clause, LGPL-2.1, LGPL-3.0
  1. <?php
  2. /**
  3. * File/Directory manipulation
  4. *
  5. * PHP versions 4 and 5
  6. *
  7. * LICENSE: This source file is subject to version 3.0 of the PHP license
  8. * that is available through the world-wide-web at the following URI:
  9. * http://www.php.net/license/3_0.txt. If you did not receive a copy of
  10. * the PHP License and are unable to obtain it through the web, please
  11. * send a note to license@php.net so we can mail you a copy immediately.
  12. *
  13. * @category pear
  14. * @package System
  15. * @author Tomas V.V.Cox <cox@idecnet.com>
  16. * @copyright 1997-2008 The PHP Group
  17. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  18. * @version CVS: $Id: System.php 137 2009-11-09 13:24:37Z vanpouckesven $
  19. * @link http://pear.php.net/package/PEAR
  20. * @since File available since Release 0.1
  21. */
  22. /**
  23. * base class
  24. */
  25. require_once 'PEAR.php';
  26. require_once 'Console/Getopt.php';
  27. $GLOBALS['_System_temp_files'] = array();
  28. /**
  29. * System offers cross plattform compatible system functions
  30. *
  31. * Static functions for different operations. Should work under
  32. * Unix and Windows. The names and usage has been taken from its respectively
  33. * GNU commands. The functions will return (bool) false on error and will
  34. * trigger the error with the PHP trigger_error() function (you can silence
  35. * the error by prefixing a '@' sign after the function call, but this
  36. * is not recommended practice. Instead use an error handler with
  37. * {@link set_error_handler()}).
  38. *
  39. * Documentation on this class you can find in:
  40. * http://pear.php.net/manual/
  41. *
  42. * Example usage:
  43. * if (!@System::rm('-r file1 dir1')) {
  44. * print "could not delete file1 or dir1";
  45. * }
  46. *
  47. * In case you need to to pass file names with spaces,
  48. * pass the params as an array:
  49. *
  50. * System::rm(array('-r', $file1, $dir1));
  51. *
  52. * @category pear
  53. * @package System
  54. * @author Tomas V.V. Cox <cox@idecnet.com>
  55. * @copyright 1997-2006 The PHP Group
  56. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  57. * @version Release: 1.7.2
  58. * @link http://pear.php.net/package/PEAR
  59. * @since Class available since Release 0.1
  60. * @static
  61. */
  62. class System
  63. {
  64. /**
  65. * returns the commandline arguments of a function
  66. *
  67. * @param string $argv the commandline
  68. * @param string $short_options the allowed option short-tags
  69. * @param string $long_options the allowed option long-tags
  70. * @return array the given options and there values
  71. * @static
  72. * @access private
  73. */
  74. function _parseArgs($argv, $short_options, $long_options = null)
  75. {
  76. if (! is_array($argv) && $argv !== null)
  77. {
  78. $argv = preg_split('/\s+/', $argv, - 1, PREG_SPLIT_NO_EMPTY);
  79. }
  80. return Console_Getopt :: getopt2($argv, $short_options);
  81. }
  82. /**
  83. * Output errors with PHP trigger_error(). You can silence the errors
  84. * with prefixing a "@" sign to the function call: @System::mkdir(..);
  85. *
  86. * @param mixed $error a PEAR error or a string with the error message
  87. * @return bool false
  88. * @static
  89. * @access private
  90. */
  91. function raiseError($error)
  92. {
  93. if (PEAR :: isError($error))
  94. {
  95. $error = $error->getMessage();
  96. }
  97. trigger_error($error, E_USER_WARNING);
  98. return false;
  99. }
  100. /**
  101. * Creates a nested array representing the structure of a directory
  102. *
  103. * System::_dirToStruct('dir1', 0) =>
  104. * Array
  105. * (
  106. * [dirs] => Array
  107. * (
  108. * [0] => dir1
  109. * )
  110. *
  111. * [files] => Array
  112. * (
  113. * [0] => dir1/file2
  114. * [1] => dir1/file3
  115. * )
  116. * )
  117. * @param string $sPath Name of the directory
  118. * @param integer $maxinst max. deep of the lookup
  119. * @param integer $aktinst starting deep of the lookup
  120. * @param bool $silent if true, do not emit errors.
  121. * @return array the structure of the dir
  122. * @static
  123. * @access private
  124. */
  125. function _dirToStruct($sPath, $maxinst, $aktinst = 0, $silent = false)
  126. {
  127. $struct = array('dirs' => array(), 'files' => array());
  128. if (($dir = @opendir($sPath)) === false)
  129. {
  130. if (! $silent)
  131. {
  132. System :: raiseError("Could not open dir $sPath");
  133. }
  134. return $struct; // XXX could not open error
  135. }
  136. $struct['dirs'][] = $sPath = realpath($sPath); // XXX don't add if '.' or '..' ?
  137. $list = array();
  138. while (false !== ($file = readdir($dir)))
  139. {
  140. if ($file != '.' && $file != '..')
  141. {
  142. $list[] = $file;
  143. }
  144. }
  145. closedir($dir);
  146. sort($list);
  147. if ($aktinst < $maxinst || $maxinst == 0)
  148. {
  149. foreach ($list as $val)
  150. {
  151. $path = $sPath . DIRECTORY_SEPARATOR . $val;
  152. if (is_dir($path) && ! is_link($path))
  153. {
  154. $tmp = System :: _dirToStruct($path, $maxinst, $aktinst + 1, $silent);
  155. $struct = array_merge_recursive($tmp, $struct);
  156. }
  157. else
  158. {
  159. $struct['files'][] = $path;
  160. }
  161. }
  162. }
  163. return $struct;
  164. }
  165. /**
  166. * Creates a nested array representing the structure of a directory and files
  167. *
  168. * @param array $files Array listing files and dirs
  169. * @return array
  170. * @static
  171. * @see System::_dirToStruct()
  172. */
  173. function _multipleToStruct($files)
  174. {
  175. $struct = array('dirs' => array(), 'files' => array());
  176. settype($files, 'array');
  177. foreach ($files as $file)
  178. {
  179. if (is_dir($file) && ! is_link($file))
  180. {
  181. $tmp = System :: _dirToStruct($file, 0);
  182. $struct = array_merge_recursive($tmp, $struct);
  183. }
  184. else
  185. {
  186. $struct['files'][] = $file;
  187. }
  188. }
  189. return $struct;
  190. }
  191. /**
  192. * The rm command for removing files.
  193. * Supports multiple files and dirs and also recursive deletes
  194. *
  195. * @param string $args the arguments for rm
  196. * @return mixed PEAR_Error or true for success
  197. * @static
  198. * @access public
  199. */
  200. function rm($args)
  201. {
  202. $opts = System :: _parseArgs($args, 'rf'); // "f" does nothing but I like it :-)
  203. if (PEAR :: isError($opts))
  204. {
  205. return System :: raiseError($opts);
  206. }
  207. foreach ($opts[0] as $opt)
  208. {
  209. if ($opt[0] == 'r')
  210. {
  211. $do_recursive = true;
  212. }
  213. }
  214. $ret = true;
  215. if (isset($do_recursive))
  216. {
  217. $struct = System :: _multipleToStruct($opts[1]);
  218. foreach ($struct['files'] as $file)
  219. {
  220. if (! @unlink($file))
  221. {
  222. $ret = false;
  223. }
  224. }
  225. foreach ($struct['dirs'] as $dir)
  226. {
  227. if (! @rmdir($dir))
  228. {
  229. $ret = false;
  230. }
  231. }
  232. }
  233. else
  234. {
  235. foreach ($opts[1] as $file)
  236. {
  237. $delete = (is_dir($file)) ? 'rmdir' : 'unlink';
  238. if (! @$delete($file))
  239. {
  240. $ret = false;
  241. }
  242. }
  243. }
  244. return $ret;
  245. }
  246. /**
  247. * Make directories.
  248. *
  249. * The -p option will create parent directories
  250. * @param string $args the name of the director(y|ies) to create
  251. * @return bool True for success
  252. * @static
  253. * @access public
  254. */
  255. function mkDir($args)
  256. {
  257. $opts = System :: _parseArgs($args, 'pm:');
  258. if (PEAR :: isError($opts))
  259. {
  260. return System :: raiseError($opts);
  261. }
  262. $mode = 0777; // default mode
  263. foreach ($opts[0] as $opt)
  264. {
  265. if ($opt[0] == 'p')
  266. {
  267. $create_parents = true;
  268. }
  269. elseif ($opt[0] == 'm')
  270. {
  271. // if the mode is clearly an octal number (starts with 0)
  272. // convert it to decimal
  273. if (strlen($opt[1]) && $opt[1]{0} == '0')
  274. {
  275. $opt[1] = octdec($opt[1]);
  276. }
  277. else
  278. {
  279. // convert to int
  280. $opt[1] += 0;
  281. }
  282. $mode = $opt[1];
  283. }
  284. }
  285. $ret = true;
  286. if (isset($create_parents))
  287. {
  288. foreach ($opts[1] as $dir)
  289. {
  290. $dirstack = array();
  291. while ((! file_exists($dir) || ! is_dir($dir)) && $dir != DIRECTORY_SEPARATOR)
  292. {
  293. array_unshift($dirstack, $dir);
  294. $dir = dirname($dir);
  295. }
  296. while ($newdir = array_shift($dirstack))
  297. {
  298. if (! is_writeable(dirname($newdir)))
  299. {
  300. $ret = false;
  301. break;
  302. }
  303. if (! mkdir($newdir, $mode))
  304. {
  305. $ret = false;
  306. }
  307. }
  308. }
  309. }
  310. else
  311. {
  312. foreach ($opts[1] as $dir)
  313. {
  314. if ((@file_exists($dir) || ! is_dir($dir)) && ! mkdir($dir, $mode))
  315. {
  316. $ret = false;
  317. }
  318. }
  319. }
  320. return $ret;
  321. }
  322. /**
  323. * Concatenate files
  324. *
  325. * Usage:
  326. * 1) $var = System::cat('sample.txt test.txt');
  327. * 2) System::cat('sample.txt test.txt > final.txt');
  328. * 3) System::cat('sample.txt test.txt >> final.txt');
  329. *
  330. * Note: as the class use fopen, urls should work also (test that)
  331. *
  332. * @param string $args the arguments
  333. * @return boolean true on success
  334. * @static
  335. * @access public
  336. */
  337. function &cat($args)
  338. {
  339. $ret = null;
  340. $files = array();
  341. if (! is_array($args))
  342. {
  343. $args = preg_split('/\s+/', $args, - 1, PREG_SPLIT_NO_EMPTY);
  344. }
  345. $count_args = count($args);
  346. for($i = 0; $i < $count_args; $i ++)
  347. {
  348. if ($args[$i] == '>')
  349. {
  350. $mode = 'wb';
  351. $outputfile = $args[$i + 1];
  352. break;
  353. }
  354. elseif ($args[$i] == '>>')
  355. {
  356. $mode = 'ab+';
  357. $outputfile = $args[$i + 1];
  358. break;
  359. }
  360. else
  361. {
  362. $files[] = $args[$i];
  363. }
  364. }
  365. $outputfd = false;
  366. if (isset($mode))
  367. {
  368. if (! $outputfd = fopen($outputfile, $mode))
  369. {
  370. $err = System :: raiseError("Could not open $outputfile");
  371. return $err;
  372. }
  373. $ret = true;
  374. }
  375. foreach ($files as $file)
  376. {
  377. if (! $fd = fopen($file, 'r'))
  378. {
  379. System :: raiseError("Could not open $file");
  380. continue;
  381. }
  382. while ($cont = fread($fd, 2048))
  383. {
  384. if (is_resource($outputfd))
  385. {
  386. fwrite($outputfd, $cont);
  387. }
  388. else
  389. {
  390. $ret .= $cont;
  391. }
  392. }
  393. fclose($fd);
  394. }
  395. if (is_resource($outputfd))
  396. {
  397. fclose($outputfd);
  398. }
  399. return $ret;
  400. }
  401. /**
  402. * Creates temporary files or directories. This function will remove
  403. * the created files when the scripts finish its execution.
  404. *
  405. * Usage:
  406. * 1) $tempfile = System::mktemp("prefix");
  407. * 2) $tempdir = System::mktemp("-d prefix");
  408. * 3) $tempfile = System::mktemp();
  409. * 4) $tempfile = System::mktemp("-t /var/tmp prefix");
  410. *
  411. * prefix -> The string that will be prepended to the temp name
  412. * (defaults to "tmp").
  413. * -d -> A temporary dir will be created instead of a file.
  414. * -t -> The target dir where the temporary (file|dir) will be created. If
  415. * this param is missing by default the env vars TMP on Windows or
  416. * TMPDIR in Unix will be used. If these vars are also missing
  417. * c:\windows\temp or /tmp will be used.
  418. *
  419. * @param string $args The arguments
  420. * @return mixed the full path of the created (file|dir) or false
  421. * @see System::tmpdir()
  422. * @static
  423. * @access public
  424. */
  425. function mktemp($args = null)
  426. {
  427. static $first_time = true;
  428. $opts = System :: _parseArgs($args, 't:d');
  429. if (PEAR :: isError($opts))
  430. {
  431. return System :: raiseError($opts);
  432. }
  433. foreach ($opts[0] as $opt)
  434. {
  435. if ($opt[0] == 'd')
  436. {
  437. $tmp_is_dir = true;
  438. }
  439. elseif ($opt[0] == 't')
  440. {
  441. $tmpdir = $opt[1];
  442. }
  443. }
  444. $prefix = (isset($opts[1][0])) ? $opts[1][0] : 'tmp';
  445. if (! isset($tmpdir))
  446. {
  447. $tmpdir = System :: tmpdir();
  448. }
  449. if (! System :: mkDir(array('-p', $tmpdir)))
  450. {
  451. return false;
  452. }
  453. $tmp = tempnam($tmpdir, $prefix);
  454. if (isset($tmp_is_dir))
  455. {
  456. unlink($tmp); // be careful possible race condition here
  457. if (! mkdir($tmp, 0700))
  458. {
  459. return System :: raiseError("Unable to create temporary directory $tmpdir");
  460. }
  461. }
  462. $GLOBALS['_System_temp_files'][] = $tmp;
  463. if ($first_time)
  464. {
  465. PEAR :: registerShutdownFunc(array('System', '_removeTmpFiles'));
  466. $first_time = false;
  467. }
  468. return $tmp;
  469. }
  470. /**
  471. * Remove temporary files created my mkTemp. This function is executed
  472. * at script shutdown time
  473. *
  474. * @static
  475. * @access private
  476. */
  477. function _removeTmpFiles()
  478. {
  479. if (count($GLOBALS['_System_temp_files']))
  480. {
  481. $delete = $GLOBALS['_System_temp_files'];
  482. array_unshift($delete, '-r');
  483. System :: rm($delete);
  484. $GLOBALS['_System_temp_files'] = array();
  485. }
  486. }
  487. /**
  488. * Get the path of the temporal directory set in the system
  489. * by looking in its environments variables.
  490. * Note: php.ini-recommended removes the "E" from the variables_order setting,
  491. * making unavaible the $_ENV array, that s why we do tests with _ENV
  492. *
  493. * @static
  494. * @return string The temporary directory on the system
  495. */
  496. function tmpdir()
  497. {
  498. if (OS_WINDOWS)
  499. {
  500. if ($var = isset($_ENV['TMP']) ? $_ENV['TMP'] : getenv('TMP'))
  501. {
  502. return $var;
  503. }
  504. if ($var = isset($_ENV['TEMP']) ? $_ENV['TEMP'] : getenv('TEMP'))
  505. {
  506. return $var;
  507. }
  508. if ($var = isset($_ENV['USERPROFILE']) ? $_ENV['USERPROFILE'] : getenv('USERPROFILE'))
  509. {
  510. return $var;
  511. }
  512. if ($var = isset($_ENV['windir']) ? $_ENV['windir'] : getenv('windir'))
  513. {
  514. return $var;
  515. }
  516. return getenv('SystemRoot') . '\temp';
  517. }
  518. if ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR'))
  519. {
  520. return $var;
  521. }
  522. return realpath('/tmp');
  523. }
  524. /**
  525. * The "which" command (show the full path of a command)
  526. *
  527. * @param string $program The command to search for
  528. * @param mixed $fallback Value to return if $program is not found
  529. *
  530. * @return mixed A string with the full path or false if not found
  531. * @static
  532. * @author Stig Bakken <ssb@php.net>
  533. */
  534. function which($program, $fallback = false)
  535. {
  536. // enforce API
  537. if (! is_string($program) || '' == $program)
  538. {
  539. return $fallback;
  540. }
  541. // full path given
  542. if (basename($program) != $program)
  543. {
  544. $path_elements[] = dirname($program);
  545. $program = basename($program);
  546. }
  547. else
  548. {
  549. // Honor safe mode
  550. if (! ini_get('safe_mode') || ! $path = ini_get('safe_mode_exec_dir'))
  551. {
  552. $path = getenv('PATH');
  553. if (! $path)
  554. {
  555. $path = getenv('Path'); // some OSes are just stupid enough to do this
  556. }
  557. }
  558. $path_elements = explode(PATH_SEPARATOR, $path);
  559. }
  560. if (OS_WINDOWS)
  561. {
  562. $exe_suffixes = getenv('PATHEXT') ? explode(PATH_SEPARATOR, getenv('PATHEXT')) : array('.exe', '.bat',
  563. '.cmd', '.com');
  564. // allow passing a command.exe param
  565. if (strpos($program, '.') !== false)
  566. {
  567. array_unshift($exe_suffixes, '');
  568. }
  569. // is_executable() is not available on windows for PHP4
  570. $pear_is_executable = (function_exists('is_executable')) ? 'is_executable' : 'is_file';
  571. }
  572. else
  573. {
  574. $exe_suffixes = array('');
  575. $pear_is_executable = 'is_executable';
  576. }
  577. foreach ($exe_suffixes as $suff)
  578. {
  579. foreach ($path_elements as $dir)
  580. {
  581. $file = $dir . DIRECTORY_SEPARATOR . $program . $suff;
  582. if (@$pear_is_executable($file))
  583. {
  584. return $file;
  585. }
  586. }
  587. }
  588. return $fallback;
  589. }
  590. /**
  591. * The "find" command
  592. *
  593. * Usage:
  594. *
  595. * System::find($dir);
  596. * System::find("$dir -type d");
  597. * System::find("$dir -type f");
  598. * System::find("$dir -name *.php");
  599. * System::find("$dir -name *.php -name *.htm*");
  600. * System::find("$dir -maxdepth 1");
  601. *
  602. * Params implmented:
  603. * $dir -> Start the search at this directory
  604. * -type d -> return only directories
  605. * -type f -> return only files
  606. * -maxdepth <n> -> max depth of recursion
  607. * -name <pattern> -> search pattern (bash style). Multiple -name param allowed
  608. *
  609. * @param mixed Either array or string with the command line
  610. * @return array Array of found files
  611. * @static
  612. *
  613. */
  614. function find($args)
  615. {
  616. if (! is_array($args))
  617. {
  618. $args = preg_split('/\s+/', $args, - 1, PREG_SPLIT_NO_EMPTY);
  619. }
  620. $dir = realpath(array_shift($args));
  621. if (! $dir)
  622. {
  623. return array();
  624. }
  625. $patterns = array();
  626. $depth = 0;
  627. $do_files = $do_dirs = true;
  628. $args_count = count($args);
  629. for($i = 0; $i < $args_count; $i ++)
  630. {
  631. switch ($args[$i])
  632. {
  633. case '-type' :
  634. if (in_array($args[$i + 1], array('d', 'f')))
  635. {
  636. if ($args[$i + 1] == 'd')
  637. {
  638. $do_files = false;
  639. }
  640. else
  641. {
  642. $do_dirs = false;
  643. }
  644. }
  645. $i ++;
  646. break;
  647. case '-name' :
  648. $name = preg_quote($args[$i + 1], '#');
  649. // our magic characters ? and * have just been escaped,
  650. // so now we change the escaped versions to PCRE operators
  651. $name = strtr($name, array('\?' => '.', '\*' => '.*'));
  652. $patterns[] = '(' . $name . ')';
  653. $i ++;
  654. break;
  655. case '-maxdepth' :
  656. $depth = $args[$i + 1];
  657. break;
  658. }
  659. }
  660. $path = System :: _dirToStruct($dir, $depth, 0, true);
  661. if ($do_files && $do_dirs)
  662. {
  663. $files = array_merge($path['files'], $path['dirs']);
  664. }
  665. elseif ($do_dirs)
  666. {
  667. $files = $path['dirs'];
  668. }
  669. else
  670. {
  671. $files = $path['files'];
  672. }
  673. if (count($patterns))
  674. {
  675. $dsq = preg_quote(DIRECTORY_SEPARATOR, '#');
  676. $pattern = '#(^|' . $dsq . ')' . implode('|', $patterns) . '($|' . $dsq . ')#';
  677. $ret = array();
  678. $files_count = count($files);
  679. for($i = 0; $i < $files_count; $i ++)
  680. {
  681. // only search in the part of the file below the current directory
  682. $filepart = basename($files[$i]);
  683. if (preg_match($pattern, $filepart))
  684. {
  685. $ret[] = $files[$i];
  686. }
  687. }
  688. return $ret;
  689. }
  690. return $files;
  691. }
  692. }