PageRenderTime 50ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/pear/php/System.php

https://github.com/hnw/phpbugs
PHP | 606 lines | 360 code | 19 blank | 227 comment | 102 complexity | 43762dbc126b34e811326bacb76e8609 MD5 | raw file
Possible License(s): LGPL-2.1
  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,v 1.62 2008/01/03 20:26:34 cellog Exp $
  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. $argv = preg_split('/\s+/', $argv, -1, PREG_SPLIT_NO_EMPTY);
  78. }
  79. return Console_Getopt::getopt2($argv, $short_options);
  80. }
  81. /**
  82. * Output errors with PHP trigger_error(). You can silence the errors
  83. * with prefixing a "@" sign to the function call: @System::mkdir(..);
  84. *
  85. * @param mixed $error a PEAR error or a string with the error message
  86. * @return bool false
  87. * @static
  88. * @access private
  89. */
  90. function raiseError($error)
  91. {
  92. if (PEAR::isError($error)) {
  93. $error = $error->getMessage();
  94. }
  95. trigger_error($error, E_USER_WARNING);
  96. return false;
  97. }
  98. /**
  99. * Creates a nested array representing the structure of a directory
  100. *
  101. * System::_dirToStruct('dir1', 0) =>
  102. * Array
  103. * (
  104. * [dirs] => Array
  105. * (
  106. * [0] => dir1
  107. * )
  108. *
  109. * [files] => Array
  110. * (
  111. * [0] => dir1/file2
  112. * [1] => dir1/file3
  113. * )
  114. * )
  115. * @param string $sPath Name of the directory
  116. * @param integer $maxinst max. deep of the lookup
  117. * @param integer $aktinst starting deep of the lookup
  118. * @param bool $silent if true, do not emit errors.
  119. * @return array the structure of the dir
  120. * @static
  121. * @access private
  122. */
  123. function _dirToStruct($sPath, $maxinst, $aktinst = 0, $silent = false)
  124. {
  125. $struct = array('dirs' => array(), 'files' => array());
  126. if (($dir = @opendir($sPath)) === false) {
  127. if (!$silent) {
  128. System::raiseError("Could not open dir $sPath");
  129. }
  130. return $struct; // XXX could not open error
  131. }
  132. $struct['dirs'][] = $sPath = realpath($sPath); // XXX don't add if '.' or '..' ?
  133. $list = array();
  134. while (false !== ($file = readdir($dir))) {
  135. if ($file != '.' && $file != '..') {
  136. $list[] = $file;
  137. }
  138. }
  139. closedir($dir);
  140. sort($list);
  141. if ($aktinst < $maxinst || $maxinst == 0) {
  142. foreach ($list as $val) {
  143. $path = $sPath . DIRECTORY_SEPARATOR . $val;
  144. if (is_dir($path) && !is_link($path)) {
  145. $tmp = System::_dirToStruct($path, $maxinst, $aktinst+1, $silent);
  146. $struct = array_merge_recursive($tmp, $struct);
  147. } else {
  148. $struct['files'][] = $path;
  149. }
  150. }
  151. }
  152. return $struct;
  153. }
  154. /**
  155. * Creates a nested array representing the structure of a directory and files
  156. *
  157. * @param array $files Array listing files and dirs
  158. * @return array
  159. * @static
  160. * @see System::_dirToStruct()
  161. */
  162. function _multipleToStruct($files)
  163. {
  164. $struct = array('dirs' => array(), 'files' => array());
  165. settype($files, 'array');
  166. foreach ($files as $file) {
  167. if (is_dir($file) && !is_link($file)) {
  168. $tmp = System::_dirToStruct($file, 0);
  169. $struct = array_merge_recursive($tmp, $struct);
  170. } else {
  171. $struct['files'][] = $file;
  172. }
  173. }
  174. return $struct;
  175. }
  176. /**
  177. * The rm command for removing files.
  178. * Supports multiple files and dirs and also recursive deletes
  179. *
  180. * @param string $args the arguments for rm
  181. * @return mixed PEAR_Error or true for success
  182. * @static
  183. * @access public
  184. */
  185. function rm($args)
  186. {
  187. $opts = System::_parseArgs($args, 'rf'); // "f" does nothing but I like it :-)
  188. if (PEAR::isError($opts)) {
  189. return System::raiseError($opts);
  190. }
  191. foreach ($opts[0] as $opt) {
  192. if ($opt[0] == 'r') {
  193. $do_recursive = true;
  194. }
  195. }
  196. $ret = true;
  197. if (isset($do_recursive)) {
  198. $struct = System::_multipleToStruct($opts[1]);
  199. foreach ($struct['files'] as $file) {
  200. if (!@unlink($file)) {
  201. $ret = false;
  202. }
  203. }
  204. foreach ($struct['dirs'] as $dir) {
  205. if (!@rmdir($dir)) {
  206. $ret = false;
  207. }
  208. }
  209. } else {
  210. foreach ($opts[1] as $file) {
  211. $delete = (is_dir($file)) ? 'rmdir' : 'unlink';
  212. if (!@$delete($file)) {
  213. $ret = false;
  214. }
  215. }
  216. }
  217. return $ret;
  218. }
  219. /**
  220. * Make directories.
  221. *
  222. * The -p option will create parent directories
  223. * @param string $args the name of the director(y|ies) to create
  224. * @return bool True for success
  225. * @static
  226. * @access public
  227. */
  228. function mkDir($args)
  229. {
  230. $opts = System::_parseArgs($args, 'pm:');
  231. if (PEAR::isError($opts)) {
  232. return System::raiseError($opts);
  233. }
  234. $mode = 0777; // default mode
  235. foreach ($opts[0] as $opt) {
  236. if ($opt[0] == 'p') {
  237. $create_parents = true;
  238. } elseif ($opt[0] == 'm') {
  239. // if the mode is clearly an octal number (starts with 0)
  240. // convert it to decimal
  241. if (strlen($opt[1]) && $opt[1]{0} == '0') {
  242. $opt[1] = octdec($opt[1]);
  243. } else {
  244. // convert to int
  245. $opt[1] += 0;
  246. }
  247. $mode = $opt[1];
  248. }
  249. }
  250. $ret = true;
  251. if (isset($create_parents)) {
  252. foreach ($opts[1] as $dir) {
  253. $dirstack = array();
  254. while ((!file_exists($dir) || !is_dir($dir)) &&
  255. $dir != DIRECTORY_SEPARATOR) {
  256. array_unshift($dirstack, $dir);
  257. $dir = dirname($dir);
  258. }
  259. while ($newdir = array_shift($dirstack)) {
  260. if (!is_writeable(dirname($newdir))) {
  261. $ret = false;
  262. break;
  263. }
  264. if (!mkdir($newdir, $mode)) {
  265. $ret = false;
  266. }
  267. }
  268. }
  269. } else {
  270. foreach($opts[1] as $dir) {
  271. if ((@file_exists($dir) || !is_dir($dir)) && !mkdir($dir, $mode)) {
  272. $ret = false;
  273. }
  274. }
  275. }
  276. return $ret;
  277. }
  278. /**
  279. * Concatenate files
  280. *
  281. * Usage:
  282. * 1) $var = System::cat('sample.txt test.txt');
  283. * 2) System::cat('sample.txt test.txt > final.txt');
  284. * 3) System::cat('sample.txt test.txt >> final.txt');
  285. *
  286. * Note: as the class use fopen, urls should work also (test that)
  287. *
  288. * @param string $args the arguments
  289. * @return boolean true on success
  290. * @static
  291. * @access public
  292. */
  293. function &cat($args)
  294. {
  295. $ret = null;
  296. $files = array();
  297. if (!is_array($args)) {
  298. $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY);
  299. }
  300. $count_args = count($args);
  301. for ($i = 0; $i < $count_args; $i++) {
  302. if ($args[$i] == '>') {
  303. $mode = 'wb';
  304. $outputfile = $args[$i+1];
  305. break;
  306. } elseif ($args[$i] == '>>') {
  307. $mode = 'ab+';
  308. $outputfile = $args[$i+1];
  309. break;
  310. } else {
  311. $files[] = $args[$i];
  312. }
  313. }
  314. $outputfd = false;
  315. if (isset($mode)) {
  316. if (!$outputfd = fopen($outputfile, $mode)) {
  317. $err = System::raiseError("Could not open $outputfile");
  318. return $err;
  319. }
  320. $ret = true;
  321. }
  322. foreach ($files as $file) {
  323. if (!$fd = fopen($file, 'r')) {
  324. System::raiseError("Could not open $file");
  325. continue;
  326. }
  327. while ($cont = fread($fd, 2048)) {
  328. if (is_resource($outputfd)) {
  329. fwrite($outputfd, $cont);
  330. } else {
  331. $ret .= $cont;
  332. }
  333. }
  334. fclose($fd);
  335. }
  336. if (is_resource($outputfd)) {
  337. fclose($outputfd);
  338. }
  339. return $ret;
  340. }
  341. /**
  342. * Creates temporary files or directories. This function will remove
  343. * the created files when the scripts finish its execution.
  344. *
  345. * Usage:
  346. * 1) $tempfile = System::mktemp("prefix");
  347. * 2) $tempdir = System::mktemp("-d prefix");
  348. * 3) $tempfile = System::mktemp();
  349. * 4) $tempfile = System::mktemp("-t /var/tmp prefix");
  350. *
  351. * prefix -> The string that will be prepended to the temp name
  352. * (defaults to "tmp").
  353. * -d -> A temporary dir will be created instead of a file.
  354. * -t -> The target dir where the temporary (file|dir) will be created. If
  355. * this param is missing by default the env vars TMP on Windows or
  356. * TMPDIR in Unix will be used. If these vars are also missing
  357. * c:\windows\temp or /tmp will be used.
  358. *
  359. * @param string $args The arguments
  360. * @return mixed the full path of the created (file|dir) or false
  361. * @see System::tmpdir()
  362. * @static
  363. * @access public
  364. */
  365. function mktemp($args = null)
  366. {
  367. static $first_time = true;
  368. $opts = System::_parseArgs($args, 't:d');
  369. if (PEAR::isError($opts)) {
  370. return System::raiseError($opts);
  371. }
  372. foreach ($opts[0] as $opt) {
  373. if ($opt[0] == 'd') {
  374. $tmp_is_dir = true;
  375. } elseif ($opt[0] == 't') {
  376. $tmpdir = $opt[1];
  377. }
  378. }
  379. $prefix = (isset($opts[1][0])) ? $opts[1][0] : 'tmp';
  380. if (!isset($tmpdir)) {
  381. $tmpdir = System::tmpdir();
  382. }
  383. if (!System::mkDir(array('-p', $tmpdir))) {
  384. return false;
  385. }
  386. $tmp = tempnam($tmpdir, $prefix);
  387. if (isset($tmp_is_dir)) {
  388. unlink($tmp); // be careful possible race condition here
  389. if (!mkdir($tmp, 0700)) {
  390. return System::raiseError("Unable to create temporary directory $tmpdir");
  391. }
  392. }
  393. $GLOBALS['_System_temp_files'][] = $tmp;
  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. }