PageRenderTime 96ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/utilities/File.php

http://github.com/phpwax/phpwax
PHP | 747 lines | 622 code | 87 blank | 38 comment | 126 complexity | dba366fb5ae02adef662c99bded2dacc MD5 | raw file
  1. <?php
  2. /**
  3. * File Class encapsulating common file functions
  4. *
  5. * @package PHP-Wax
  6. */
  7. class File
  8. {
  9. public static $compression_quality = '85';
  10. public static $resize_library = 'gd'; // Optionally set to 'gd'
  11. static function is_older_than($file, $time)
  12. {
  13. if (file_exists($file)) {
  14. $modtime = filemtime($file);
  15. if ($modtime >= (time() - $time)) {
  16. return false;
  17. }
  18. return true;
  19. }
  20. }
  21. static function safe_file_save($dir, $file)
  22. {
  23. $file = preg_replace('/[^\w\.\-_]/', '', $file);
  24. $i = 1;
  25. while (is_file($dir.$file)) {
  26. $file = substr($file, 0, strpos($file, "."))."_$i.".substr(strrchr($file, "."), 1);
  27. $i++;
  28. }
  29. return $file;
  30. }
  31. static function clear_image_cache($image_id)
  32. {
  33. $look_for = CACHE_DIR . 'images/' . $image_id . '_*';
  34. foreach (glob($look_for) as $filename) {
  35. @unlink($filename);
  36. }
  37. }
  38. /**
  39. * modes:
  40. * crop (default) - keeps aspect ratio, fills target size, crops the rest
  41. * nocrop - as above, but skips the cropping. 1 dimension will be longer than asked for.
  42. * small - keeps aspect ratio. fits image in specified size. will produce blank pixels.
  43. * stretch - ignores aspect ratio.
  44. * @param $source
  45. * @param $destination
  46. * @param $width
  47. * @param $height
  48. * @param string $mode
  49. * @return bool|void
  50. */
  51. public static function smart_resize_image($source, $destination, $width, $height, $mode = 'crop')
  52. {
  53. if (!is_readable($source)) {
  54. return;
  55. }
  56. list($source_width, $source_height, $image_type) = getimagesize($source);
  57. if ((!$width && !$height) || !function_exists('imagecopyresampled')) {
  58. return false;
  59. }
  60. if (!$height || !$width) {
  61. $mode = 'nocrop';
  62. } //force nocrop when specifying only 1 dimension
  63. $r_h = $height / $source_height;
  64. $r_w = $width / $source_width;
  65. if ($r_h == $r_h && $r_h == 1) {
  66. copy($source, $destination);
  67. return true;
  68. }
  69. //mode calculations, the clever stuff
  70. if ($mode == "small") {
  71. if ($r_h < $r_w) {
  72. $width = $r_h * $source_width;
  73. } //ignore target width and use the aspect ratio to work it out
  74. else {
  75. $height = $r_w * $source_height;
  76. } //ignore target height and use the aspect ratio to work it out
  77. } elseif ($mode != "stretch") { //skip messing with anything for stretch mode, this block runs for crop and aspect modes
  78. if ($r_h > $r_w) {
  79. if ($mode == "nocrop") {
  80. $width = $r_h * $source_width;
  81. } //ignore target width and use the aspect ratio to work it out
  82. else {
  83. $new_source_width = $source_height * $width / $height;
  84. $source_x = ($source_width - $new_source_width) / 2;
  85. $source_width = $new_source_width;
  86. }
  87. } else {
  88. if ($mode == "nocrop") {
  89. $height = $r_w * $source_height;
  90. } //ignore target height and use the aspect ratio to work it out
  91. else {
  92. $new_source_height = $source_width * $height / $width;
  93. $source_y = ($source_height - $new_source_height) / 2;
  94. $source_height = $new_source_height;
  95. }
  96. }
  97. }
  98. switch ($image_type) {
  99. case 1:
  100. $src = imagecreatefromgif($source);
  101. break;
  102. case 2:
  103. $src = imagecreatefromjpeg($source);
  104. break;
  105. case 3:
  106. $src = imagecreatefrompng($source);
  107. break;
  108. default:
  109. return false;
  110. break;
  111. }
  112. if (self::is_animated($source)) {
  113. return self::resize_image($source, $destination, $width, false, false, true);
  114. } else {
  115. $dst = imagecreatetruecolor($width, $height);
  116. imagesavealpha($dst, true);
  117. imagefill($dst, 0, 0, imagecolorallocatealpha($dst, 255, 255, 255, 127));
  118. if (!imagecopyresampled(
  119. $dst,
  120. $src,
  121. 0,
  122. 0,
  123. $source_x,
  124. $source_y,
  125. $width,
  126. $height,
  127. $source_width,
  128. $source_height
  129. )) {
  130. return false;
  131. }
  132. return self::output_image_gd($image_type, $dst, $destination);
  133. }
  134. }
  135. static function is_animated($filename)
  136. {
  137. if (!($fh = @fopen($filename, 'rb'))) {
  138. return false;
  139. }
  140. $count = 0;
  141. //an animated gif contains multiple "frames", with each frame having a
  142. //header made up of:
  143. // * a static 4-byte sequence (\x00\x21\xF9\x04)
  144. // * 4 variable bytes
  145. // * a static 2-byte sequence (\x00\x2C)
  146. // We read through the file til we reach the end of the file, or we've found
  147. // at least 2 frame headers
  148. while (!feof($fh) && $count < 2) {
  149. $chunk = fread($fh, 1024 * 100); //read 100kb at a time
  150. $count += preg_match_all('#\x00\x21\xF9\x04.{4}\x00\x2C#s', $chunk, $matches);
  151. }
  152. fclose($fh);
  153. return $count > 1;
  154. }
  155. /**
  156. * @param $source The Original Image File
  157. * @param $destination The New File to write to
  158. * @param $width The width of the new image
  159. * @return bool
  160. */
  161. static function resize_image($source, $destination, $width, $overwrite = false, $force_width = false)
  162. {
  163. if (!self::is_image($source)) {
  164. return false;
  165. }
  166. if (self::$resize_library == "gd" && function_exists("imagecreatefromjpeg")) {
  167. return self::gd_resize_image($source, $destination, $width, $overwrite = false, $force_width = false);
  168. }
  169. $dimensions = getimagesize($source);
  170. $x = $dimensions[0];
  171. $y = $dimensions[1];
  172. if ($y > $x && !$force_width) {
  173. $height = $width;
  174. $ratio = $y / $width;
  175. $width = floor($x / $ratio);
  176. } else {
  177. $ratio = $x / $width;
  178. $height = floor($y / $ratio);
  179. }
  180. if ($ratio == 1) {
  181. $command = "cp ".escapeshellarg($source)." ".escapeshellarg($destination);
  182. } elseif ($overwrite) {
  183. $command = "mogrify ".escapeshellarg(
  184. $source
  185. )." -limit area 30 -render -flatten -coalesce -colorspace RGB -resize {$width}x{$height} -quality ".self::$compression_quality;
  186. } else {
  187. $command = "convert ".escapeshellarg(
  188. $source
  189. )." -limit area 30 -coalesce -thumbnail {$width}x{$height} -density 72x72 -quality ".self::$compression_quality." $destination";
  190. }
  191. system($command);
  192. if (!is_file($destination)) {
  193. return false;
  194. }
  195. chmod($destination, 0777);
  196. return true;
  197. }
  198. static function is_image($file)
  199. {
  200. if (!is_file($file)) {
  201. return false;
  202. }
  203. if (getimagesize($file)) {
  204. return true;
  205. }
  206. return false;
  207. }
  208. static public function gd_resize_image($source, $destination, $r_width, $overwrite = false, $force_width = false)
  209. {
  210. list($width, $height, $image_type) = getimagesize($source);
  211. if (!$width) {
  212. return false;
  213. }
  214. $r = $width / $height;
  215. $r_height = $r_width;
  216. if ($r_width / $r_height > $r && !$force_width) {
  217. $newwidth = $r_height * $r;
  218. $newheight = $r_height;
  219. } else {
  220. $newheight = $r_width / $r;
  221. $newwidth = $r_width;
  222. }
  223. switch ($image_type) {
  224. case 1:
  225. $src = imagecreatefromgif($source);
  226. break;
  227. case 2:
  228. $src = imagecreatefromjpeg($source);
  229. break;
  230. case 3:
  231. $src = imagecreatefrompng($source);
  232. break;
  233. default:
  234. return '';
  235. break;
  236. }
  237. $dst = imagecreatetruecolor($newwidth, $newheight);
  238. imagesavealpha($dst, true);
  239. $trans_colour = imagecolorallocatealpha($dst, 255, 255, 255, 127);
  240. imagefill($dst, 0, 0, $trans_colour);
  241. $img = imagecopyresampled($dst, $src, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
  242. return self::output_image_gd($image_type, $dst, $destination);
  243. }
  244. static private function output_image_gd($image_type, $dst, $destination)
  245. {
  246. switch ($image_type) {
  247. case "gif":
  248. case 1:
  249. $src = imagegif($dst, $destination);
  250. break;
  251. case "jpg":
  252. case "jpeg":
  253. case 2:
  254. $src = imagejpeg($dst, $destination, self::$compression_quality);
  255. break;
  256. case "png":
  257. case 3:
  258. $src = imagepng($dst, $destination);
  259. break;
  260. }
  261. imagedestroy($dst);
  262. if (!is_file($destination)) {
  263. return false;
  264. }
  265. chmod($destination, 0777);
  266. return true;
  267. }
  268. static function rotate_image($source, $destination, $angle)
  269. {
  270. if (!self::is_image($source)) {
  271. return false;
  272. }
  273. if (self::$resize_library == "gd" && function_exists("imagerotate")) {
  274. return self::gd_rotate_image($source, $destination, $angle);
  275. }
  276. system("cp $source $destination");
  277. $command = "mogrify $source -colorspace RGB -rotate {$angle} $destination";
  278. system($command);
  279. if (!is_file($destination)) {
  280. return false;
  281. }
  282. chmod($destination, 0777);
  283. return true;
  284. }
  285. static function gd_rotate_image($source, $destination, $angle)
  286. {
  287. list($width, $height, $image_type) = getimagesize($source);
  288. switch ($image_type) {
  289. case 1:
  290. $src = imagecreatefromgif($source);
  291. break;
  292. case 2:
  293. $src = imagecreatefromjpeg($source);
  294. break;
  295. case 3:
  296. $src = imagecreatefrompng($source);
  297. break;
  298. default:
  299. return '';
  300. break;
  301. }
  302. $dst = imagerotate($src, $angle, -1);
  303. return self::output_image_gd($image_type, $dst, $destination);
  304. }
  305. static function resize_image_extra(
  306. $source,
  307. $destination,
  308. $percent = false,
  309. $x = false,
  310. $y = false,
  311. $ignore_ratio = false
  312. ) {
  313. if (!self::is_image($source)) {
  314. return false;
  315. }
  316. system("cp {$source} {$destination}");
  317. $command = "convert {$source} -coalesce -colorspace RGB -resize";
  318. if ($percent) {
  319. $command .= " {$percent}%";
  320. } elseif ($x && $y) {
  321. $command .= " {$x}x{$y}";
  322. if ($ignore_ratio) {
  323. $command .= "\!";
  324. }
  325. }
  326. $command .= " {$destination}";
  327. system($command);
  328. if (!is_file($destination)) {
  329. return false;
  330. }
  331. chmod($destination, 0777);
  332. return true;
  333. }
  334. static public function image_convert($source, $destination, $type = "jpeg", $quality = 75)
  335. {
  336. if (!function_exists("getimagesize")) {
  337. return false;
  338. }
  339. list($source_width, $source_height, $image_type) = getimagesize($source);
  340. switch ($image_type) {
  341. case 1:
  342. $src = imagecreatefromgif($source);
  343. break;
  344. case 2:
  345. $src = imagecreatefromjpeg($source);
  346. break;
  347. case 3:
  348. $src = imagecreatefrompng($source);
  349. break;
  350. default:
  351. return false;
  352. break;
  353. }
  354. $ret = call_user_func("image".$type, $src, $destination, $quality);
  355. imagedestroy($src);
  356. return $ret;
  357. }
  358. static function crop_image($source, $destination, $x, $y, $width, $height)
  359. {
  360. if (!self::is_image($source)) {
  361. return false;
  362. }
  363. if (self::$resize_library == "gd" && function_exists("imagecopyresampled")) {
  364. return self::gd_crop_image($source, $destination, $x, $y, $width, $height);
  365. }
  366. system("cp $source $destination");
  367. $command = "convert {$source} -crop ".$width."x".$height."+".$x."+".$y." +repage $destination";
  368. system($command);
  369. if (!is_file($destination)) {
  370. return false;
  371. }
  372. chmod($destination, 0777);
  373. return true;
  374. }
  375. static function gd_crop_image($source, $destination, $x, $y, $width, $height)
  376. {
  377. list($source_width, $source_height, $image_type) = getimagesize($source);
  378. switch ($image_type) {
  379. case 1:
  380. $src = imagecreatefromgif($source);
  381. break;
  382. case 2:
  383. $src = imagecreatefromjpeg($source);
  384. break;
  385. case 3:
  386. $src = imagecreatefrompng($source);
  387. break;
  388. default:
  389. return false;
  390. break;
  391. }
  392. $dst = imagecreatetruecolor($width, $height);
  393. imagesavealpha($dst, true);
  394. imagefill($dst, 0, 0, imagecolorallocatealpha($dst, 255, 255, 255, 127));
  395. if (!imagecopyresampled($dst, $src, 0, 0, $x, $y, $width, $height, $width, $height)) {
  396. return false;
  397. }
  398. return self::output_image_gd($image_type, $dst, $destination);
  399. }
  400. static function stream_file($file, $stream_as = false, $autoexit = true)
  401. {
  402. $length = filesize($file);
  403. $filename = preg_replace("/[^a-zA-Z0-9-_\.]/", "_", basename($file));
  404. if (is_readable($file)) {
  405. header("Content-Type: application/force-download"."\n");
  406. header("Content-Length: ".$length.'\n');
  407. if ($stream_as) {
  408. $filename = $stream_as;
  409. }
  410. header("Content-disposition: inline; filename=".$filename."\n");
  411. header("Connection: close"."\n");
  412. ob_end_clean();
  413. readfile($file);
  414. if (!$autoexit) {
  415. return true;
  416. }
  417. exit;
  418. }
  419. return false;
  420. }
  421. static function get_extension($file)
  422. {
  423. return substr($file, strrpos($file, '.') + 1);
  424. }
  425. static function get_folders($directory)
  426. {
  427. if (!is_dir($directory)) {
  428. return [];
  429. }
  430. $iter = new RecursiveIteratorIterator(
  431. new RecursiveDirectoryIterator($directory),
  432. RecursiveIteratorIterator::SELF_FIRST
  433. );
  434. foreach ($iter as $file) {
  435. if (($iter->hasChildren(true)) && !strstr($iter->getRealPath()."/".$file->getFilename(), "/.")) {
  436. if ($iter->isLink()) {
  437. $row['path'] = $iter->getLinkTarget().'/'.$file->getFilename();
  438. } else {
  439. $row['path'] = $iter->getPath().'/'.$file->getFilename();
  440. }
  441. $row['name'] = str_repeat('&nbsp;&nbsp;', $iter->getDepth() + 2).ucfirst($file->getFilename());
  442. $rows[] = $row;
  443. unset($row);
  444. if ($iter->isLink()) {
  445. $rows = array_merge(
  446. $rows,
  447. self::get_folders($iter->getLinkTarget().'/'.$file->getFilename())
  448. );
  449. }
  450. }
  451. }
  452. return $rows;
  453. }
  454. static function recursively_delete($item)
  455. {
  456. if (!is_file($item) && !is_dir($item)) {
  457. return true;
  458. }
  459. if (is_file($item) && is_readable($item)) {
  460. unlink($item);
  461. return true;
  462. }
  463. $iter = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($item), 2);
  464. foreach ($iter as $file) {
  465. if ($iter->isDir() && is_readable($file) && !$iter->isDot()) {
  466. rmdir($file);
  467. } elseif ($iter->isFile() && is_readable($file)) {
  468. unlink($file);
  469. }
  470. }
  471. if (is_dir($item) && is_readable($item) && substr($item, -1) != ".") {
  472. rmdir($item);
  473. }
  474. return true;
  475. }
  476. static function scandir_recursive($directory)
  477. {
  478. $folderContents = [];
  479. foreach (scandir($directory) as $folderItem) {
  480. if ($folderItem != "." && $folderItem != ".." && substr($folderItem, 0, 1) != '.') {
  481. if (is_dir($directory.'/'.$folderItem)) {
  482. $folderContents[$folderItem] = self::scandir_recursive($directory.'/'.$folderItem);
  483. } else {
  484. $folderContents[] = $folderItem;
  485. }
  486. }
  487. }
  488. return $folderContents;
  489. }
  490. static function list_images_recursive($directory)
  491. {
  492. $dir = new RecursiveIteratorIterator(
  493. new RecursiveDirectoryIterator($directory), true
  494. );
  495. foreach ($dir as $file) {
  496. if (!strstr($dir->getPath()."/".$file, "/.")) {
  497. if (self::is_image($file)) {
  498. $imagearray[] = ["filename" => $dir->getFilename(), "path" => base64_encode($file)];
  499. }
  500. }
  501. }
  502. return $imagearray;
  503. }
  504. static public function render_temp_image($original, $size)
  505. {
  506. if (self::is_image($original)) {
  507. $destination = tempnam(CACHE_DIR, "file_image_");
  508. self::resize_image($original, $destination, $size, $overwrite = false);
  509. self::display_image($destination);
  510. return true;
  511. }
  512. return false;
  513. }
  514. static function display_image($image)
  515. {
  516. if (!self::is_image($image)) {
  517. return false;
  518. }
  519. $info = getimagesize($image);
  520. $mime = image_type_to_mime_type($info[2]);
  521. self::display_asset($image, $mime);
  522. }
  523. static function display_asset($path, $mime = null)
  524. {
  525. if (!is_readable($path)) {
  526. return false;
  527. }
  528. if ($mime === null) {
  529. $mime = self::detect_mime($path);
  530. }
  531. $length = filesize($path);
  532. header('Content-Type: '.$mime."\n");
  533. header('Content-Length: '.$length."\n");
  534. header('Content-disposition: inline; filename='.basename($path)."\n");
  535. header('Expires: '.date('D, d M Y H:i:s', time() + 200000).' GMT');
  536. header('Cache-Control: max-age=200000');
  537. header('Pragma:');
  538. ob_end_clean();
  539. $handle = fopen($path, 'rb');
  540. while (!feof($handle)) {
  541. echo fread($handle, 8192);
  542. }
  543. fclose($handle);
  544. }
  545. public static function detect_mime($file)
  546. {
  547. if ($res = self::mime_map($file)) {
  548. $type = $res;
  549. } elseif (function_exists('mime_content_type')) {
  550. $type = mime_content_type($file);
  551. } else {
  552. $type = exec('file --mime -b '.escapeshellarg($file));
  553. }
  554. return $type;
  555. }
  556. static function mime_map($filename)
  557. {
  558. $mime_types = [
  559. 'txt' => 'text/plain',
  560. 'htm' => 'text/html',
  561. 'html' => 'text/html',
  562. 'php' => 'text/html',
  563. 'css' => 'text/css',
  564. 'js' => 'application/javascript',
  565. 'json' => 'application/json',
  566. 'xml' => 'application/xml',
  567. 'swf' => 'application/x-shockwave-flash',
  568. 'flv' => 'video/x-flv',
  569. // images
  570. 'png' => 'image/png',
  571. 'jpe' => 'image/jpeg',
  572. 'jpeg' => 'image/jpeg',
  573. 'jpg' => 'image/jpeg',
  574. 'gif' => 'image/gif',
  575. 'bmp' => 'image/bmp',
  576. 'ico' => 'image/vnd.microsoft.icon',
  577. 'tiff' => 'image/tiff',
  578. 'tif' => 'image/tiff',
  579. 'svg' => 'image/svg+xml',
  580. 'svgz' => 'image/svg+xml',
  581. // archives
  582. 'zip' => 'application/zip',
  583. 'rar' => 'application/x-rar-compressed',
  584. 'exe' => 'application/x-msdownload',
  585. 'msi' => 'application/x-msdownload',
  586. 'cab' => 'application/vnd.ms-cab-compressed',
  587. // audio/video
  588. 'mp3' => 'audio/mpeg',
  589. 'qt' => 'video/quicktime',
  590. 'mov' => 'video/quicktime',
  591. // adobe
  592. 'pdf' => 'application/pdf',
  593. 'psd' => 'image/vnd.adobe.photoshop',
  594. 'ai' => 'application/postscript',
  595. 'eps' => 'application/postscript',
  596. 'ps' => 'application/postscript',
  597. // ms office
  598. 'doc' => 'application/msword',
  599. 'rtf' => 'application/rtf',
  600. 'xls' => 'application/vnd.ms-excel',
  601. 'ppt' => 'application/vnd.ms-powerpoint',
  602. // open office
  603. 'odt' => 'application/vnd.oasis.opendocument.text',
  604. 'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
  605. ];
  606. $fileParts = explode('.', $filename);
  607. $ext = strtolower(array_pop($fileParts));
  608. if (array_key_exists($ext, $mime_types)) {
  609. return $mime_types[$ext];
  610. }
  611. }
  612. static function write_to_file($filename, $filecontents, $mode = 0777)
  613. {
  614. if (!$res = file_put_contents($filename, $filecontents)) {
  615. chmod($filename, $mode);
  616. return false;
  617. }
  618. return true;
  619. }
  620. static function read_from_file($filename)
  621. {
  622. if (!is_readable($filename)) {
  623. return false;
  624. }
  625. return file_get_contents($filename);
  626. }
  627. static function recursive_directory_copy($source, $destination, $verbose = true)
  628. {
  629. if (!is_dir($destination)) {
  630. if (!mkdir($destination) && !is_dir($destination)) {
  631. throw new \RuntimeException(sprintf('Directory "%s" was not created', $destination));
  632. }
  633. }
  634. foreach (File::scandir($source, ".htaccess") as $file) {
  635. if (is_file($source.DIRECTORY_SEPARATOR.$file)) {
  636. copy($source.DIRECTORY_SEPARATOR.$file, $destination.DIRECTORY_SEPARATOR.$file);
  637. if ($verbose) {
  638. echo "..created ".$destination.DIRECTORY_SEPARATOR.$file."\n";
  639. }
  640. } else {
  641. File::recursive_directory_copy(
  642. $source.DIRECTORY_SEPARATOR.$file,
  643. $destination.DIRECTORY_SEPARATOR.$file
  644. );
  645. }
  646. }
  647. }
  648. public static function scandir($directory, $include_pattern = false)
  649. {
  650. $list = [];
  651. foreach (scandir($directory) as $item) {
  652. if (preg_match("/".$include_pattern."/", $item)) {
  653. $list[] = $item;
  654. } elseif ($item != "." && $item != ".." && substr($item, 0, 1) != '.') {
  655. $list[] = $item;
  656. }
  657. }
  658. return $list;
  659. }
  660. }