PageRenderTime 48ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/community/PEAR/System.php

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