PageRenderTime 40ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/environment/functions/files.php

https://github.com/fb83/Project-Pier
PHP | 650 lines | 506 code | 49 blank | 95 comment | 46 complexity | f63ecd4e15697725d0111e63bd691607 MD5 | raw file
Possible License(s): AGPL-1.0, GPL-2.0, AGPL-3.0, LGPL-2.1, GPL-3.0
  1. <?php
  2. /**
  3. * Check if specific folder is writable
  4. *
  5. * @param string $path
  6. * @return boolean
  7. */
  8. function folder_is_writable($path) {
  9. if (!is_dir($path)) {
  10. return false;
  11. } // if
  12. do {
  13. $test_file = with_slash($path) . sha1(uniqid(rand(), true));
  14. } while (is_file($test_file));
  15. $put = @file_put_contents($test_file, 'test');
  16. if ($put === false) {
  17. return false;
  18. } // if
  19. @unlink($test_file);
  20. return true;
  21. } // folder_is_writable
  22. /**
  23. * Check if specific file is writable
  24. *
  25. * @param string $path
  26. * @return boolean
  27. */
  28. function file_is_writable($path) {
  29. if (!is_file($path)) {
  30. return false;
  31. } // if
  32. $open = @fopen($path, 'a+');
  33. if ($open === false) {
  34. return false;
  35. } // if
  36. @fclose($open);
  37. return true;
  38. } // file_is_writable
  39. /**
  40. * Return specific line of specific file
  41. *
  42. * @access public
  43. * @param string $file
  44. * @param integer $line
  45. * @param midex $default Returned if file or line does not exists
  46. * @return string
  47. */
  48. function get_file_line($file, $line, $default = null) {
  49. if (is_file($file)) {
  50. $lines = file($file);
  51. return isset($file[$line]) ? $file[$line] : $default;
  52. } else {
  53. return $default;
  54. } // if
  55. } // get_file_line
  56. /**
  57. * Return directories
  58. *
  59. * @access public
  60. * @param string $dir
  61. * @param integer $full_path
  62. * @return array
  63. */
  64. function get_dirs($dir, $full_path = true) {
  65. // Check dir...
  66. if (!is_dir($dir)) {
  67. return false;
  68. } // if
  69. // Prepare input data...
  70. $dir = with_slash($dir);
  71. // We have a dir...
  72. if (!is_dir($dir)) {
  73. return null;
  74. } // if
  75. // Open dir and prepare result
  76. $d = dir($dir);
  77. $dirs = array();
  78. // Loop dir entries
  79. while (false !== ($entry = $d->read())) {
  80. // Valid entry?
  81. if (($entry <> '.') && ($entry <> '..')) {
  82. // Get file path...
  83. $path = $dir . $entry;
  84. // Check if we have a valid directory
  85. if (is_dir($path)) {
  86. $dirs[] = $full_path ? $path : $entry;
  87. } // if
  88. } // if
  89. } // while
  90. // Done... close dir...
  91. $d->close();
  92. // And return...
  93. return count($dirs) > 0 ? $dirs : null;
  94. } // get_dirs
  95. /**
  96. * Return the files from specific directory. This function can filter result
  97. * by file extension (accepted param is single extension or array of extensions)
  98. *
  99. * @example get_files($dir, array('doc', 'pdf', 'xst'))
  100. *
  101. * @param string $dir Dir that need to be scaned
  102. * @param mixed $extension Single or multiple file extensions that need to be
  103. * mached. If null no check is performed...
  104. * @param boolean $base_name_only Return only filenames. If this option is set to
  105. * false this function will return full paths.
  106. * @return array
  107. */
  108. function get_files($dir, $extension = null, $base_name_only = false) {
  109. // Check dir...
  110. if (!is_dir($dir)) {
  111. return false;
  112. } // if
  113. // Prepare input data...
  114. $dir = with_slash($dir);
  115. if (!is_null($extension)) {
  116. if (is_array($extension)) {
  117. foreach ($extension as $k => $v) {
  118. $extension[$k] = strtolower($v);
  119. } // foreach
  120. } else {
  121. $extension = strtolower($extension);
  122. } // if
  123. } // if
  124. // We have a dir...
  125. if (!is_dir($dir)) {
  126. return null;
  127. } // if
  128. // Open dir and prepare result
  129. $d = dir($dir);
  130. $files = array();
  131. // Loop dir entries
  132. while (false !== ($entry = $d->read())) {
  133. // Valid entry?
  134. if (($entry <> '.') && ($entry <> '..')) {
  135. // Get file path...
  136. $path = $dir . $entry;
  137. // If we have valid file that do the checks
  138. if (is_file($path)) {
  139. if (is_null($extension)) {
  140. $files[] = $base_name_only ? basename($path) : $path;
  141. } else {
  142. // Match multiple extensions?
  143. if (is_array($extension)) {
  144. // If in array add...
  145. if (in_array( strtolower(get_file_extension($path)), $extension )) {
  146. $files[] = $base_name_only ? basename($path) : $path;
  147. } // if
  148. // Match single extension
  149. } else {
  150. // If extensions match add...
  151. if (strtolower(get_file_extension($path)) == $extension) {
  152. $files[] = $base_name_only ? basename($path) : $path;
  153. } // if
  154. } // if
  155. } // if
  156. } // if
  157. } // if
  158. } // while
  159. // Done... close dir...
  160. $d->close();
  161. // And return...
  162. return count($files) > 0 ? $files : null;
  163. } // get_files
  164. /**
  165. * Return file extension from specific path
  166. *
  167. * @access public
  168. * @param string $path File path
  169. * @param boolean $leading_dot Include leading dot (or not...)
  170. * @return string
  171. */
  172. function get_file_extension($path, $leading_dot = false) {
  173. $filename = basename($path);
  174. $dot_offset = (boolean) $leading_dot ? 0 : 1;
  175. if ( ($pos = strrpos($filename, '.')) !== false ) {
  176. return substr($filename, $pos + $dot_offset, strlen($filename));
  177. } // if
  178. return '';
  179. } // get_file_extension
  180. /**
  181. * Return size of a specific dir in bytes
  182. *
  183. * @access public
  184. * @param string $dir Directory
  185. * @return integer
  186. */
  187. function dir_size($dir) {
  188. $totalsize = 0;
  189. if ($dirstream = @opendir($dir)) {
  190. while (false !== ($filename = readdir($dirstream))) {
  191. if (($filename != ".") && ($filename != "..")) {
  192. $path = with_slash($dir) . $filename;
  193. if (is_file($path)) $totalsize += filesize($path);
  194. if (is_dir($path)) $totalsize += dir_size($path);
  195. } // if
  196. } // while
  197. } // if
  198. closedir($dirstream);
  199. return $totalsize;
  200. } // end func dir_size
  201. /**
  202. * Remove specific directory
  203. *
  204. * @access public
  205. * @param string $dir Directory path
  206. * @return boolean
  207. */
  208. function delete_dir($dir) {
  209. $dh = opendir($dir);
  210. while ($file = readdir($dh)) {
  211. if (($file != ".") && ($file != "..")) {
  212. $fullpath = $dir . "/" . $file;
  213. if (!is_dir($fullpath)) {
  214. unlink($fullpath);
  215. } else {
  216. delete_dir($fullpath);
  217. } // if
  218. } // if
  219. } // while
  220. closedir($dh);
  221. return rmdir($dir) ? true : false;
  222. } // end func delete_dir
  223. /**
  224. * Force creation of all dirs
  225. *
  226. * @access public
  227. * @param void
  228. * @return null
  229. */
  230. function force_mkdir($path, $chmod = null) {
  231. return mkdir($path, $chmod, true);
  232. if (is_dir($path)) {
  233. return true;
  234. } // if
  235. $real_path = str_replace('\\', '/', $path);
  236. $parts = explode('/', $real_path);
  237. $forced_path = '';
  238. foreach ($parts as $part) {
  239. // Skip first on windows
  240. if ($forced_path == '') {
  241. $start = substr(__FILE__, 0, 1) == '/' ? '/' : '';
  242. $forced_path = $start . $part;
  243. } else {
  244. $forced_path .= '/' . $part;
  245. } // if
  246. if (!is_dir($forced_path)) {
  247. if (!is_null($chmod)) {
  248. if (!mkdir($forced_path)) {
  249. return false;
  250. } // if
  251. } else {
  252. if (!mkdir($forced_path, $chmod)) {
  253. return false;
  254. } // if
  255. } // if
  256. } // if
  257. } // foreach
  258. return true;
  259. } // force_mkdir
  260. /**
  261. * This function will return true if $dir_path is empty
  262. *
  263. * @param string $dir_path
  264. * @return boolean
  265. */
  266. function is_dir_empty($dir_path) {
  267. $d = dir($dir_path);
  268. if ($d) {
  269. while (false !== ($entry = $d->read())) {
  270. if (($entry == '.') || ($entry == '..')) {
  271. continue;
  272. } // if
  273. return false;
  274. } // while
  275. } // if
  276. return true;
  277. } // is_dir_empty
  278. /**
  279. * Check if file $in/$desired_filename exists and if it exists save it in
  280. * $in/$desired_filename(x).exteionsion (X is inserted in front of the extension)
  281. *
  282. * @access public
  283. * @param string $in Directory
  284. * @param string $desired_filename
  285. * @return string
  286. */
  287. function get_unique_filename($in, $desired_filename) {
  288. if (!is_dir($in)) {
  289. false;
  290. } // if
  291. $file_path = $in . '/' . $desired_filename;
  292. $counter = 0;
  293. while (is_file($file_path)) {
  294. $counter++;
  295. $file_path = insert_before_file_extension($file_path, '(' . $counter . ')');
  296. } // if
  297. return $file_path;
  298. } // get_unique_filename
  299. /**
  300. * Set something before file extension
  301. *
  302. * @access public
  303. * @param string $in Filename
  304. * @param string $insert Insert this
  305. * @return null
  306. */
  307. function insert_before_file_extension($filename, $insert) {
  308. return str_replace_first('.', '.' . $insert, $filename);
  309. } // insert_before_file_extension
  310. /**
  311. * Forward specific file to the browser. Download can be forced (disposition: attachment) or passed as inline file
  312. *
  313. * @access public
  314. * @param string $path File path
  315. * @param string $type Serve file as this type
  316. * @param string $name If set use this name, else use filename (basename($path))
  317. * @param boolean $force_download Force download (add Disposition => attachement)
  318. * @return boolean
  319. */
  320. function download_file($path, $type = 'application/octet-stream', $name = '', $force_download = false) {
  321. if (!is_readable($path)) {
  322. return false;
  323. } // if
  324. $filename = trim($name) == '' ? basename($path) : trim($name);
  325. return download_contents(file_get_contents($path), $type, $filename, filesize($path), $force_download);
  326. } // download_file
  327. /**
  328. * Use content (from file, from database, other source...) and pass it to the browser as a file
  329. *
  330. * @param string $content
  331. * @param string $type MIME type
  332. * @param string $name File name
  333. * @param integer $size File size
  334. * @param boolean $force_download Send Content-Disposition: attachment to force save dialog
  335. * @return boolean
  336. */
  337. /**
  338. * SAVR 10/20/06 : force file download over SSL for IE
  339. * BIP 09/17/07 : inserted and tested for ProjectPier
  340. * Was:
  341. * function download_contents($content, $type, $name, $size, $force_download = false) {
  342. */
  343. function download_contents($content, $type, $name, $size, $force_download = true, $from_filesystem = false) {
  344. if (connection_status() != 0) return false; // check connection
  345. download_headers($name, $type, $size, $force_download);
  346. if ($from_filesystem) {
  347. if (!is_readable($content)) return false;
  348. if (!ini_get('safe_mode')) @set_time_limit(0);
  349. $chunksize = 1*(1024*1024); // how many bytes per chunk
  350. $buffer = '';
  351. $handle = fopen($content, 'rb');
  352. if ($handle === false) {
  353. return false;
  354. }
  355. while (!feof($handle)) {
  356. $buffer = fread($handle, $chunksize);
  357. print $buffer;
  358. flush();
  359. ob_flush();
  360. }
  361. return fclose($handle);
  362. } else {
  363. /*
  364. print $content;
  365. */
  366. header("X-ProjectPier-Storage: mysql");
  367. header("X-ProjectPier-Size: " . $size);
  368. // 0.8.8 $content = repository id
  369. //print $content;
  370. $repository_id = $content;
  371. $repo_table = TABLE_PREFIX.'file_repo';
  372. $query = sprintf("SELECT `content`, `seq` FROM $repo_table WHERE `id`='%s' order by `seq` asc", mysql_real_escape_string($repository_id));
  373. trace(__FILE__,$query);
  374. header("X-ProjectPier-Debug1: " . $query);
  375. $result = mysql_query($query);
  376. header("X-ProjectPier-Debug2: " . mysql_error());
  377. while ($row = mysql_fetch_assoc($result)) {
  378. trace(__FILE__,$row['seq']);
  379. header("X-ProjectPier-Debug3-" . $row['seq'] . ": " . mysql_error());
  380. print $row['content'];
  381. flush();
  382. ob_flush();
  383. }
  384. header("X-ProjectPier-Debug4: " . mysql_error());
  385. mysql_free_result($result);
  386. }
  387. return((connection_status() == 0) && !connection_aborted());
  388. } // download_contents
  389. /**
  390. * function download_headers($type, $name, $size, $force_download = false)
  391. */
  392. function download_headers($name, $type, $size, $force_download = true) {
  393. if ($force_download) {
  394. /** SAVR 10/20/06
  395. * Was:
  396. * header("Cache-Control: public");
  397. */
  398. header("Cache-Control: public, must-revalidate");
  399. header("Pragma: hack");
  400. } else {
  401. header("Cache-Control: no-store, no-cache, must-revalidate");
  402. header("Cache-Control: post-check=0, pre-check=0", false);
  403. header("Pragma: no-cache");
  404. } // if
  405. header("Expires: " . gmdate("D, d M Y H:i:s", mktime(date("H") + 2, date("i"), date("s"), date("m"), date("d"), date("Y"))) . " GMT");
  406. header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
  407. header("Content-Type: $type");
  408. header("Content-Length: $size");
  409. // Prepare disposition
  410. $disposition = $force_download ? 'attachment' : 'inline';
  411. // http://www.ietf.org/rfc/rfc2183.txt
  412. $download_name = strtr($name, " ()<>@,;:\\/[]?=*%'\"", '--------------------');
  413. $download_name = normalize($download_name);
  414. header("Content-Disposition: $disposition; filename=\"$download_name\"");
  415. //header("Content-Disposition: $disposition; filename=$download_name");
  416. header("Content-Transfer-Encoding: binary");
  417. }
  418. /**
  419. * This function is used for sorting list of files.
  420. *
  421. * The most important thing about this function is $extractor. It is function
  422. * name of function that will be used to extract data that we need for sorting
  423. * - filesize, file modification type, content-type... Anything. First param of
  424. * $extractor function must be filepath.
  425. *
  426. * After the extract have all the data it need $sort_with function will be used
  427. * to sort by the extracted data... First param of the $sort_with function must
  428. * be array that need to be sorted. This function MUST RETURN SORTED ARRAY, cant
  429. * use side effect...
  430. *
  431. * Important = $sort_with must be key sorting function because this function
  432. * saves extracted data into the array keys...
  433. *
  434. * Examples:
  435. *
  436. * sort_files($files, 'filemtime', 'krsort', SORT_NUMERIC) will sort all files
  437. * by modification time and the freshest files will be at the top of the result
  438. *
  439. * @access public
  440. * @param array $file Array of filenames
  441. * @param string $extractor Function that will be used for extractiong specific
  442. * file data (like file creation time or filesize)
  443. * @param string $sort_with Function that will be used to sort the array
  444. * when we are done...
  445. * @param mixed $sort_method If this value is <> null that this will be passed
  446. * to the sort functions as second param. I added it because there are great
  447. * number of function that can use it to make a diffrence between string and int
  448. * sorting...
  449. * @return array
  450. */
  451. function sort_files($files, $extractor, $sort_with = 'array_ksort', $sort_method = null) {
  452. // Prepare...
  453. $extractor = trim($extractor);
  454. $sort_with = trim($sort_with);
  455. // Check the input data...
  456. if (!is_array($files)) {
  457. return false;
  458. } // if
  459. if (!function_exists($extractor)) {
  460. return false;
  461. } // if
  462. if (!function_exists($sort_with)) {
  463. return false;
  464. } // if
  465. // Prepare the tmp array...
  466. $tmp = array();
  467. // OK, now get the files...
  468. foreach ($files as $file) {
  469. // Pass this one?
  470. if (!is_file($file)) {
  471. continue;
  472. } // if
  473. // Get data...
  474. $data = call_user_func($extractor, $file);
  475. // Prepare array...
  476. if (!isset($tmp[$data])) {
  477. $tmp[$data] = array();
  478. } // if
  479. // Add filename to the extracted param...
  480. $tmp[$data][] = $file;
  481. } // foreach
  482. // OK, now sort subarrays
  483. foreach ($tmp as &$subarray) {
  484. if (count($subarray) > 0) {
  485. sort($subarray);
  486. } // if
  487. } // foreach
  488. // OK, do the sort thing...
  489. if (is_null($sort_method)) {
  490. $sorted = call_user_func($sort_with, $tmp);
  491. } else {
  492. $sorted = call_user_func_array($sort_with, array($tmp, $sort_method));
  493. } // if
  494. // Check sorted array
  495. if (!is_array($sorted)) {
  496. return false;
  497. } // if
  498. // OK, flatten...
  499. $result = array();
  500. foreach ($sorted as &$subarray) {
  501. $result = array_merge($result, $subarray);
  502. } // foreach
  503. // And done...
  504. return $result;
  505. } // sort_files
  506. // ================================================================
  507. // SORT FUNC REPLACEMENTS
  508. //
  509. // These function RETURN sorted array, don't use side effect. They
  510. // are used by the sort_files() function in the
  511. // environment/functions/files.php
  512. // ================================================================
  513. /**
  514. * Replacement function for sort() function. Returns array
  515. *
  516. * @access public
  517. * @param array $array Array that need to be sorted
  518. * @param int $flag Sort flag, described on sort() function documentation page
  519. * @return array
  520. */
  521. function array_sort($array, $flag = SORT_REGULAR) {
  522. sort($array, $flag);
  523. return $array;
  524. } // end func
  525. /**
  526. * Replacement function for rsort() function. Returns array
  527. *
  528. * @access public
  529. * @param array $array Array that need to be sorted
  530. * @param int $flag Sort flag, described on sort() function documentation page
  531. * @return array
  532. */
  533. function array_rsort($array, $flag = SORT_REGULAR) {
  534. rsort($array, $flag);
  535. return $array;
  536. } // end func array_rsort
  537. /**
  538. * Replacement function for ksort() function. Returns array
  539. *
  540. * @access public
  541. * @param array $array Array that need to be sorted
  542. * @param int $flag Sort flag, described on sort() function documentation page
  543. * @return array
  544. */
  545. function array_ksort($array, $flag = SORT_REGULAR) {
  546. ksort($array, $flag);
  547. return $array;
  548. } // end func array_ksort
  549. /**
  550. * Replacement function for krsort() function. Returns array
  551. *
  552. * @access public
  553. * @param array $array Array that need to be sorted
  554. * @param int $flag Sort flag, described on sort() function documentation page
  555. * @return array
  556. */
  557. function array_krsort($array, $flag = SORT_REGULAR) {
  558. krsort($array, $flag);
  559. return $array;
  560. } // end func array_krsort
  561. /*** / SORT FUNC REPLACEMENTS ***/
  562. ?>