├── .github
└── FUNDING.yml
├── README.md
├── images
├── Chrysanthemum.jpg
├── Desert.jpg
├── Hydrangeas.jpg
├── Jellyfish.jpg
├── Koala.jpg
├── Lighthouse.jpg
├── Penguins.jpg
└── Tulips.jpg
├── img.php
└── index.php
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [dcblogdev]
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Create a gallery from a folder with PHP
2 | =============
3 |
4 | These files acompany the tutorial: [Creating an image gallery from a folder of images automatically](http://daveismyname.com/creating-an-image-gallery-from-a-folder-of-images-automatically-bp)
--------------------------------------------------------------------------------
/images/Chrysanthemum.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dcblogdev/gallery-from-folder/7c54470fa84ca492e5ea50affb08b9b74ba02d04/images/Chrysanthemum.jpg
--------------------------------------------------------------------------------
/images/Desert.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dcblogdev/gallery-from-folder/7c54470fa84ca492e5ea50affb08b9b74ba02d04/images/Desert.jpg
--------------------------------------------------------------------------------
/images/Hydrangeas.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dcblogdev/gallery-from-folder/7c54470fa84ca492e5ea50affb08b9b74ba02d04/images/Hydrangeas.jpg
--------------------------------------------------------------------------------
/images/Jellyfish.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dcblogdev/gallery-from-folder/7c54470fa84ca492e5ea50affb08b9b74ba02d04/images/Jellyfish.jpg
--------------------------------------------------------------------------------
/images/Koala.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dcblogdev/gallery-from-folder/7c54470fa84ca492e5ea50affb08b9b74ba02d04/images/Koala.jpg
--------------------------------------------------------------------------------
/images/Lighthouse.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dcblogdev/gallery-from-folder/7c54470fa84ca492e5ea50affb08b9b74ba02d04/images/Lighthouse.jpg
--------------------------------------------------------------------------------
/images/Penguins.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dcblogdev/gallery-from-folder/7c54470fa84ca492e5ea50affb08b9b74ba02d04/images/Penguins.jpg
--------------------------------------------------------------------------------
/images/Tulips.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dcblogdev/gallery-from-folder/7c54470fa84ca492e5ea50affb08b9b74ba02d04/images/Tulips.jpg
--------------------------------------------------------------------------------
/img.php:
--------------------------------------------------------------------------------
1 | handleErrors();
390 |
391 | if ($mthumb->tryBrowserCache()) {
392 | exit(0);
393 | }
394 | $mthumb->handleErrors();
395 | if (FILE_CACHE_ENABLED && $mthumb->tryServerCache()) {
396 | exit(0);
397 | }
398 | $mthumb->handleErrors();
399 | $mthumb->run();
400 | $mthumb->handleErrors();
401 | exit(0);
402 | }
403 |
404 | /**
405 | *
406 | */
407 | public function __construct() {
408 | global $ALLOWED_SITES;
409 | $this->startTime = microtime(TRUE);
410 | date_default_timezone_set('UTC');
411 | $this->debug(1, "Starting new request from " . $this->getIP() . " to " . $_SERVER[ 'REQUEST_URI' ]);
412 | $this->calcDocRoot();
413 | //On windows systems I'm assuming fileinode returns an empty string or a number that doesn't change. Check this.
414 | $this->salt = @filemtime(__FILE__) . '-' . @fileinode(__FILE__);
415 | $this->debug(3, "Salt is: " . $this->salt);
416 | if (FILE_CACHE_DIRECTORY) {
417 | if (!is_dir(FILE_CACHE_DIRECTORY)) {
418 | @mkdir(FILE_CACHE_DIRECTORY);
419 | if (!is_dir(FILE_CACHE_DIRECTORY)) {
420 | $this->error("Could not create the file cache directory.");
421 |
422 | return FALSE;
423 | }
424 | }
425 | $this->cacheDirectory = FILE_CACHE_DIRECTORY;
426 | if (!touch($this->cacheDirectory . '/index.html')) {
427 | $this->error("Could not create the index.html file - to fix this create an empty file named index.html file in the cache directory.");
428 | }
429 | } else {
430 | $this->cacheDirectory = sys_get_temp_dir();
431 | }
432 | // Clean the cache before we do anything because we don't want the first visitor after FILE_CACHE_TIME_BETWEEN_CLEANS expires to get a stale image.
433 | $this->cleanCache();
434 |
435 | $this->myHost = preg_replace('/^www\./i', '', $_SERVER[ 'HTTP_HOST' ]);
436 |
437 | // start mindshare fix for tilde's, check if tilde is found in src
438 | if (strstr($this->param('src'), '~')) {
439 | $url_parts = explode('/', $this->param('src'));
440 | foreach ($url_parts as $url_part) {
441 | //do not include any part with a ~ when building new url
442 | if (!strstr($url_part, '~')) {
443 | $new_dev_url .= $url_part . '/';
444 | }
445 | }
446 | //remove trailing slash
447 | $new_dev_url = substr($new_dev_url, 0, -1);
448 | $this->src = $new_dev_url;
449 | } else {
450 | $this->src = $this->param('src');
451 | }
452 | // end mindshare fix for tilde's
453 | $this->url = parse_url($this->src);
454 | $this->src = preg_replace('/https?:\/\/(?:www\.)?' . $this->myHost . '/i', '', $this->src);
455 |
456 | if (strlen($this->src) <= 3) {
457 | $this->error("No image specified");
458 |
459 | return FALSE;
460 | }
461 |
462 | // Always block external sites from using this script
463 | if (array_key_exists('HTTP_REFERER', $_SERVER) && (!preg_match('/^https?:\/\/(?:www\.)?' . $this->myHost . '(?:$|\/)/i', $_SERVER[ 'HTTP_REFERER' ]))) {
464 | // base64 encoded red image that says 'no hotlinkers' nothing to worry about! :)
465 | $imgData = base64_decode("R0lGODlhUAAMAIAAAP8AAP///yH5BAAHAP8ALAAAAABQAAwAAAJpjI+py+0Po5y0OgAMjjv01YUZ\nOGplhWXfNa6JCLnWkXplrcBmW+spbwvaVr/cDyg7IoFC2KbYVC2NQ5MQ4ZNao9Ynzjl9ScNYpneb\nDULB3RP6JuPuaGfuuV4fumf8PuvqFyhYtjdoeFgAADs=");
466 | header('Content-Type: image/gif');
467 | header('Content-Length: ' . strlen($imgData));
468 | header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
469 | header("Pragma: no-cache");
470 | header('Expires: ' . gmdate('D, d M Y H:i:s', time()));
471 | echo $imgData;
472 |
473 | return FALSE;
474 | exit(0);
475 | }
476 | if (preg_match('/^https?:\/\/[^\/]+/i', $this->src)) {
477 | $this->debug(2, "Is a request for an external URL: " . $this->src);
478 | $this->isURL = TRUE;
479 | } else {
480 | $this->debug(2, "Is a request for an internal file: " . $this->src);
481 | }
482 | if ($this->isURL && (!ALLOW_EXTERNAL)) {
483 | $this->error("You are not allowed to fetch images from an external website.");
484 |
485 | return FALSE;
486 | }
487 | if ($this->isURL) {
488 |
489 | $this->debug(2, "Fetching only from selected external sites is enabled.");
490 | $allowed = FALSE;
491 | foreach ($ALLOWED_SITES as $site) {
492 | if ((strtolower(substr($this->url[ 'host' ], -strlen($site) - 1)) === strtolower(".$site")) || (strtolower($this->url[ 'host' ]) === strtolower($site))) {
493 | $this->debug(3, "URL hostname {$this->url['host']} matches $site so allowing.");
494 | $allowed = TRUE;
495 | }
496 | }
497 | if (!$allowed) {
498 | return $this->error("You may not fetch images from that site. To enable this site in mthumb, you can either add it to \$ALLOWED_SITES and set ALLOW_EXTERNAL=true.");
499 | }
500 | }
501 |
502 | $cachePrefix = ($this->isURL ? '_ext_' : '_int_');
503 | if ($this->isURL) {
504 | $arr = explode('&', $_SERVER [ 'QUERY_STRING' ]);
505 | asort($arr);
506 | $this->cachefile = $this->cacheDirectory . '/' . FILE_CACHE_PREFIX . $cachePrefix . md5($this->salt . implode('', $arr) . $this->fileCacheVersion) . FILE_CACHE_SUFFIX;
507 | } else {
508 | $this->localImage = $this->getLocalImagePath($this->src);
509 |
510 | if (!$this->localImage) {
511 | $this->debug(1, "Could not find the local image: {$this->localImage}");
512 | $this->error("Could not find the internal image you specified.");
513 | $this->set404();
514 |
515 | return FALSE;
516 | }
517 | $this->debug(1, "Local image path is {$this->localImage}");
518 | $this->localImageMTime = @filemtime($this->localImage);
519 | //We include the mtime of the local file in case in changes on disk.
520 | $this->cachefile = $this->cacheDirectory . '/' . FILE_CACHE_PREFIX . $cachePrefix . md5($this->salt . $this->localImageMTime . $_SERVER [ 'QUERY_STRING' ] . $this->fileCacheVersion) . FILE_CACHE_SUFFIX;
521 | }
522 | $this->debug(2, "Cache file is: " . $this->cachefile);
523 |
524 | return TRUE;
525 | }
526 |
527 | /**
528 | *
529 | */
530 | public function __destruct() {
531 | foreach ($this->toDeletes as $del) {
532 | $this->debug(2, "Deleting temp file $del");
533 | @unlink($del);
534 | }
535 | }
536 |
537 | /**
538 | * @return bool
539 | */
540 | public function run() {
541 | if ($this->isURL) {
542 | if (!ALLOW_EXTERNAL) {
543 | $this->debug(1, "Got a request for an external image but ALLOW_EXTERNAL is disabled so returning error msg.");
544 | $this->error("You are not allowed to fetch images from an external website.");
545 |
546 | return FALSE;
547 | }
548 | $this->debug(3, "Got request for external image. Starting serveExternalImage.");
549 | $this->serveExternalImage();
550 | } else {
551 | $this->debug(3, "Got request for internal image. Starting serveInternalImage");
552 | $this->serveInternalImage();
553 | }
554 |
555 | return TRUE;
556 | }
557 |
558 | /**
559 | * @return bool
560 | */
561 | protected function handleErrors() {
562 | if ($this->haveErrors()) {
563 | $this->serveErrors();
564 | exit(0);
565 | }
566 |
567 | return FALSE;
568 | }
569 |
570 | /**
571 | * @return bool
572 | */
573 | protected function tryBrowserCache() {
574 | if (BROWSER_CACHE_DISABLE) {
575 | $this->debug(3, "Browser caching is disabled");
576 |
577 | return FALSE;
578 | }
579 | if (!empty($_SERVER[ 'HTTP_IF_MODIFIED_SINCE' ])) {
580 | $this->debug(3, "Got a conditional get");
581 | $mtime = FALSE;
582 | //We've already checked if the real file exists in the constructor
583 | if (!is_file($this->cachefile)) {
584 | //If we don't have something cached, regenerate the cached image.
585 | return FALSE;
586 | }
587 | if ($this->localImageMTime) {
588 | $mtime = $this->localImageMTime;
589 | $this->debug(3, "Local real file's modification time is $mtime");
590 | } else {
591 | if (is_file($this->cachefile)) { //If it's not a local request then use the mtime of the cached file to determine the 304
592 | $mtime = @filemtime($this->cachefile);
593 | $this->debug(3, "Cached file's modification time is $mtime");
594 | }
595 | }
596 | if (!$mtime) {
597 | return FALSE;
598 | }
599 |
600 | $iftime = strtotime($_SERVER[ 'HTTP_IF_MODIFIED_SINCE' ]);
601 | $this->debug(3, "The conditional get's if-modified-since unixtime is $iftime");
602 | if ($iftime < 1) {
603 | $this->debug(3, "Got an invalid conditional get modified since time. Returning false.");
604 |
605 | return FALSE;
606 | }
607 | // Real file or cache file has been modified since last request, so force refetch.
608 | if ($iftime < $mtime) {
609 | $this->debug(3, "File has been modified since last fetch.");
610 |
611 | return FALSE;
612 | } else { //Otherwise serve a 304
613 | $this->debug(3, "File has not been modified since last get, so serving a 304.");
614 | header($_SERVER[ 'SERVER_PROTOCOL' ] . ' 304 Not Modified');
615 | $this->debug(1, "Returning 304 not modified");
616 |
617 | return TRUE;
618 | }
619 | }
620 |
621 | return FALSE;
622 | }
623 |
624 | /**
625 | * @return bool
626 | */
627 | protected function tryServerCache() {
628 | $this->debug(3, "Trying server cache");
629 | if (file_exists($this->cachefile)) {
630 | $this->debug(3, "Cachefile {$this->cachefile} exists");
631 | if ($this->isURL) {
632 | $this->debug(3, "This is an external request, so checking if the cachefile is empty which means the request failed previously.");
633 | if (filesize($this->cachefile) < 1) {
634 | $this->debug(3, "Found an empty cachefile indicating a failed earlier request. Checking how old it is.");
635 | //Fetching error occured previously
636 | if (time() - @filemtime($this->cachefile) > WAIT_BETWEEN_FETCH_ERRORS) {
637 | $this->debug(3, "File is older than " . WAIT_BETWEEN_FETCH_ERRORS . " seconds. Deleting and returning false so app can try and load file.");
638 | @unlink($this->cachefile);
639 |
640 | return FALSE; //to indicate we didn't serve from cache and app should try and load
641 | } else {
642 | $this->debug(3, "Empty cachefile is still fresh so returning message saying we had an error fetching this image from remote host.");
643 | $this->set404();
644 | $this->error("An error occured fetching image.");
645 |
646 | return FALSE;
647 | }
648 | }
649 | } else {
650 | $this->debug(3, "Trying to serve cachefile {$this->cachefile}");
651 | }
652 | if ($this->serveCacheFile()) {
653 | $this->debug(3, "Succesfully served cachefile {$this->cachefile}");
654 |
655 | return TRUE;
656 | } else {
657 | $this->debug(3, "Failed to serve cachefile {$this->cachefile} - Deleting it from cache.");
658 | //Image serving failed. We can't retry at this point, but lets remove it from cache so the next request recreates it
659 | @unlink($this->cachefile);
660 |
661 | return TRUE;
662 | }
663 | }
664 | }
665 |
666 | /**
667 | * @param $err
668 | *
669 | * @return bool
670 | */
671 | protected function error($err) {
672 | $this->debug(3, "Adding error message: $err");
673 | $this->errors[] = $err;
674 |
675 | return FALSE;
676 | }
677 |
678 | /**
679 | * @return bool
680 | */
681 | protected function haveErrors() {
682 | if (sizeof($this->errors) > 0) {
683 | return TRUE;
684 | }
685 |
686 | return FALSE;
687 | }
688 |
689 | /**
690 | *
691 | */
692 | protected function serveErrors() {
693 | if (!DISPLAY_ERROR_MESSAGES) {
694 | return;
695 | }
696 | header($_SERVER[ 'SERVER_PROTOCOL' ] . ' 400 Bad Request');
697 | $html = '
';
698 | foreach ($this->errors as $err) {
699 | $html .= '- ' . htmlentities($err) . '
';
700 | }
701 | $html .= '
';
702 | echo 'An error has occured
The following error(s) occured:
' . $html . '
';
703 | echo '
Query String: ' . htmlentities($_SERVER[ 'QUERY_STRING' ], ENT_QUOTES);
704 | }
705 |
706 | /**
707 | * @return bool
708 | */
709 | protected function serveInternalImage() {
710 | $this->debug(3, "Local image path is $this->localImage");
711 | if (!$this->localImage) {
712 | $this->sanityFail("localImage not set after verifying it earlier in the code.");
713 |
714 | return FALSE;
715 | }
716 | $fileSize = filesize($this->localImage);
717 | if ($fileSize > MAX_FILE_SIZE) {
718 | $this->error("The file you specified is greater than the maximum allowed file size.");
719 |
720 | return FALSE;
721 | }
722 | if ($fileSize <= 0) {
723 | $this->error("The file you specified is <= 0 bytes.");
724 |
725 | return FALSE;
726 | }
727 | $this->debug(3, "Calling processImageAndWriteToCache() for local image.");
728 | if ($this->processImageAndWriteToCache($this->localImage)) {
729 | $this->serveCacheFile();
730 |
731 | return TRUE;
732 | } else {
733 | return FALSE;
734 | }
735 | }
736 |
737 | /**
738 | * @return bool
739 | */
740 | protected function serveExternalImage() {
741 | if (!preg_match('/^https?:\/\/[a-zA-Z0-9\-\.]+/i', $this->src)) {
742 | $this->error("Invalid URL supplied.");
743 |
744 | return FALSE;
745 | }
746 | $tempfile = tempnam($this->cacheDirectory, 'mthumb');
747 | $this->debug(3, "Fetching external image into temporary file $tempfile");
748 | $this->toDelete($tempfile);
749 | // fetch file here
750 | if (!$this->getURL($this->src, $tempfile)) {
751 | @unlink($this->cachefile);
752 | touch($this->cachefile);
753 | $this->debug(3, "Error fetching URL: " . $this->lastURLError);
754 | $this->error("Error reading the URL you specified from remote host." . $this->lastURLError);
755 |
756 | return FALSE;
757 | }
758 |
759 | $mimeType = $this->getMimeType($tempfile);
760 | if (!preg_match("/^image\/(?:jpg|jpeg|gif|png)$/i", $mimeType)) {
761 | $this->debug(3, "Remote file has invalid mime type: $mimeType");
762 | @unlink($this->cachefile);
763 | touch($this->cachefile);
764 | $this->error("The remote file is not a valid image. Mimetype = '" . $mimeType . "'" . $tempfile);
765 |
766 | return FALSE;
767 | }
768 | if ($this->processImageAndWriteToCache($tempfile)) {
769 | $this->debug(3, "Image processed succesfully. Serving from cache");
770 |
771 | return $this->serveCacheFile();
772 | } else {
773 | return FALSE;
774 | }
775 | }
776 |
777 | /**
778 | * @return bool
779 | */
780 | protected function cleanCache() {
781 | if (FILE_CACHE_TIME_BETWEEN_CLEANS < 0) {
782 | return;
783 | }
784 | $this->debug(3, "cleanCache() called");
785 | $lastCleanFile = $this->cacheDirectory . '/mthumb_cacheLastCleanTime.touch';
786 |
787 | // If the cache dir isn't writable, exit
788 | if (!is_writable($lastCleanFile)) {
789 | return;
790 | }
791 | //If this is a new mthumb installation we need to create the file
792 | if (!is_file($lastCleanFile)) {
793 | $this->debug(1, "File tracking last clean doesn't exist. Creating $lastCleanFile");
794 | if (!touch($lastCleanFile)) {
795 | $this->error("Could not create cache clean timestamp file.");
796 | }
797 |
798 | return;
799 | }
800 | if (@filemtime($lastCleanFile) < (time() - FILE_CACHE_TIME_BETWEEN_CLEANS)) { //Cache was last cleaned more than 1 day ago
801 | $this->debug(1, "Cache was last cleaned more than " . FILE_CACHE_TIME_BETWEEN_CLEANS . " seconds ago. Cleaning now.");
802 | // Very slight race condition here, but worst case we'll have 2 or 3 servers cleaning the cache simultaneously once a day.
803 | if (!touch($lastCleanFile)) {
804 | $this->error("Could not create cache clean timestamp file.");
805 | }
806 | $files = glob($this->cacheDirectory . '/*' . FILE_CACHE_SUFFIX);
807 | if ($files) {
808 | $timeAgo = time() - FILE_CACHE_MAX_FILE_AGE;
809 | foreach ($files as $file) {
810 | if (@filemtime($file) < $timeAgo) {
811 | $this->debug(3, "Deleting cache file $file older than max age: " . FILE_CACHE_MAX_FILE_AGE . " seconds");
812 | @unlink($file);
813 | }
814 | }
815 | }
816 |
817 | return TRUE;
818 | } else {
819 | $this->debug(3, "Cache was cleaned less than " . FILE_CACHE_TIME_BETWEEN_CLEANS . " seconds ago so no cleaning needed.");
820 | }
821 |
822 | return FALSE;
823 | }
824 |
825 | /**
826 | * @param $localImage
827 | *
828 | * @return bool
829 | */
830 | protected function processImageAndWriteToCache($localImage) {
831 | $sData = getimagesize($localImage);
832 | $origType = $sData[ 2 ];
833 | $mimeType = $sData[ 'mime' ];
834 |
835 | $this->debug(3, "Mime type of image is $mimeType");
836 | if (!preg_match('/^image\/(?:gif|jpg|jpeg|png)$/i', $mimeType)) {
837 | return $this->error("The image being resized is not a valid gif, jpg or png.");
838 | }
839 |
840 | if (!function_exists('imagecreatetruecolor')) {
841 | return $this->error('GD Library Error: imagecreatetruecolor does not exist - please contact your webhost and ask them to install the GD library');
842 | }
843 |
844 | if (function_exists('imagefilter') && defined('IMG_FILTER_NEGATE')) {
845 | $imageFilters = array(
846 | 1 => array(IMG_FILTER_NEGATE, 0),
847 | 2 => array(IMG_FILTER_GRAYSCALE, 0),
848 | 3 => array(IMG_FILTER_BRIGHTNESS, 1),
849 | 4 => array(IMG_FILTER_CONTRAST, 1),
850 | 5 => array(IMG_FILTER_COLORIZE, 4),
851 | 6 => array(IMG_FILTER_EDGEDETECT, 0),
852 | 7 => array(IMG_FILTER_EMBOSS, 0),
853 | 8 => array(IMG_FILTER_GAUSSIAN_BLUR, 0),
854 | 9 => array(IMG_FILTER_SELECTIVE_BLUR, 0),
855 | 10 => array(IMG_FILTER_MEAN_REMOVAL, 0),
856 | 11 => array(IMG_FILTER_SMOOTH, 0),
857 | );
858 | }
859 |
860 | // get standard input properties
861 | $new_width = (int) abs($this->param('w', 0));
862 | $new_height = (int) abs($this->param('h', 0));
863 | $zoom_crop = (int) $this->param('zc', DEFAULT_ZC);
864 | $quality = (int) abs($this->param('q', DEFAULT_Q));
865 | $align = $this->cropTop ? 't' : $this->param('a', 'c');
866 | $filters = $this->param('f', DEFAULT_F);
867 | $sharpen = (bool) $this->param('s', DEFAULT_S);
868 | $canvas_color = $this->param('cc', DEFAULT_CC);
869 | $canvas_trans = (bool) $this->param('ct', '1');
870 |
871 | // set default width and height if neither are set already
872 | if ($new_width == 0 && $new_height == 0) {
873 | $new_width = (int) DEFAULT_WIDTH;
874 | $new_height = (int) DEFAULT_HEIGHT;
875 | }
876 |
877 | // ensure size limits can not be abused
878 | $new_width = min($new_width, MAX_WIDTH);
879 | $new_height = min($new_height, MAX_HEIGHT);
880 |
881 | // open the existing image
882 | $image = $this->openImage($mimeType, $localImage);
883 | if ($image === FALSE) {
884 | return $this->error('Unable to open image.');
885 | }
886 |
887 | // Get original width and height
888 | $width = imagesx($image);
889 | $height = imagesy($image);
890 | $origin_x = 0;
891 | $origin_y = 0;
892 |
893 | // generate new w/h if not provided
894 | if ($new_width && !$new_height) {
895 | $new_height = floor($height * ($new_width / $width));
896 | } else {
897 | if ($new_height && !$new_width) {
898 | $new_width = floor($width * ($new_height / $height));
899 | }
900 | }
901 |
902 | // scale down and add borders
903 | if ($zoom_crop == 3) {
904 |
905 | $final_height = $height * ($new_width / $width);
906 |
907 | if ($final_height > $new_height) {
908 | $new_width = $width * ($new_height / $height);
909 | } else {
910 | $new_height = $final_height;
911 | }
912 | }
913 |
914 | // create a new true color image
915 | $canvas = imagecreatetruecolor($new_width, $new_height);
916 | imagealphablending($canvas, FALSE);
917 |
918 | if (strlen($canvas_color) == 3) { //if is 3-char notation, edit string into 6-char notation
919 | $canvas_color = str_repeat(substr($canvas_color, 0, 1), 2) . str_repeat(substr($canvas_color, 1, 1), 2) . str_repeat(substr($canvas_color, 2, 1), 2);
920 | } else {
921 | if (strlen($canvas_color) != 6) {
922 | $canvas_color = DEFAULT_CC; // on error return default canvas color
923 | }
924 | }
925 |
926 | $canvas_color_R = hexdec(substr($canvas_color, 0, 2));
927 | $canvas_color_G = hexdec(substr($canvas_color, 2, 2));
928 | $canvas_color_B = hexdec(substr($canvas_color, 4, 2));
929 |
930 | // Create a new transparent color for image
931 | // If is a png and PNG_IS_TRANSPARENT is false then remove the alpha transparency
932 | // (and if is set a canvas color show it in the background)
933 | if (preg_match('/^image\/png$/i', $mimeType) && !PNG_IS_TRANSPARENT && $canvas_trans) {
934 | $color = imagecolorallocatealpha($canvas, $canvas_color_R, $canvas_color_G, $canvas_color_B, 127);
935 | } else {
936 | $color = imagecolorallocatealpha($canvas, $canvas_color_R, $canvas_color_G, $canvas_color_B, 0);
937 | }
938 |
939 | // Completely fill the background of the new image with allocated color.
940 | imagefill($canvas, 0, 0, $color);
941 |
942 | // scale down and add borders
943 | if ($zoom_crop == 2) {
944 |
945 | $final_height = $height * ($new_width / $width);
946 |
947 | if ($final_height > $new_height) {
948 |
949 | $origin_x = $new_width / 2;
950 | $new_width = $width * ($new_height / $height);
951 | $origin_x = round($origin_x - ($new_width / 2));
952 | } else {
953 |
954 | $origin_y = $new_height / 2;
955 | $new_height = $final_height;
956 | $origin_y = round($origin_y - ($new_height / 2));
957 | }
958 | }
959 |
960 | // Restore transparency blending
961 | imagesavealpha($canvas, TRUE);
962 |
963 | if ($zoom_crop > 0) {
964 |
965 | $src_x = $src_y = 0;
966 | $src_w = $width;
967 | $src_h = $height;
968 |
969 | $cmp_x = $width / $new_width;
970 | $cmp_y = $height / $new_height;
971 |
972 | // calculate x or y coordinate and width or height of source
973 | if ($cmp_x > $cmp_y) {
974 |
975 | $src_w = round($width / $cmp_x * $cmp_y);
976 | $src_x = round(($width - ($width / $cmp_x * $cmp_y)) / 2);
977 | } else {
978 | if ($cmp_y > $cmp_x) {
979 |
980 | $src_h = round($height / $cmp_y * $cmp_x);
981 | $src_y = round(($height - ($height / $cmp_y * $cmp_x)) / 2);
982 | }
983 | }
984 |
985 | // positional cropping!
986 | if ($align) {
987 | if (strpos($align, 't') !== FALSE) {
988 | $src_y = 0;
989 | }
990 | if (strpos($align, 'b') !== FALSE) {
991 | $src_y = $height - $src_h;
992 | }
993 | if (strpos($align, 'l') !== FALSE) {
994 | $src_x = 0;
995 | }
996 | if (strpos($align, 'r') !== FALSE) {
997 | $src_x = $width - $src_w;
998 | }
999 | }
1000 |
1001 | imagecopyresampled($canvas, $image, $origin_x, $origin_y, $src_x, $src_y, $new_width, $new_height, $src_w, $src_h);
1002 | } else {
1003 |
1004 | // copy and resize part of an image with resampling
1005 | imagecopyresampled($canvas, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
1006 | }
1007 |
1008 | if ($filters != '' && function_exists('imagefilter') && defined('IMG_FILTER_NEGATE')) {
1009 | // apply filters to image
1010 | $filterList = explode('|', $filters);
1011 | foreach ($filterList as $fl) {
1012 |
1013 | $filterSettings = explode(',', $fl);
1014 | if (isset ($imageFilters[ $filterSettings[ 0 ] ])) {
1015 |
1016 | for ($i = 0; $i < 4; $i++) {
1017 | if (!isset ($filterSettings[ $i ])) {
1018 | $filterSettings[ $i ] = NULL;
1019 | } else {
1020 | $filterSettings[ $i ] = (int) $filterSettings[ $i ];
1021 | }
1022 | }
1023 |
1024 | switch ($imageFilters[ $filterSettings[ 0 ] ][ 1 ]) {
1025 |
1026 | case 1:
1027 |
1028 | imagefilter($canvas, $imageFilters[ $filterSettings[ 0 ] ][ 0 ], $filterSettings[ 1 ]);
1029 | break;
1030 |
1031 | case 2:
1032 |
1033 | imagefilter($canvas, $imageFilters[ $filterSettings[ 0 ] ][ 0 ], $filterSettings[ 1 ], $filterSettings[ 2 ]);
1034 | break;
1035 |
1036 | case 3:
1037 |
1038 | imagefilter($canvas, $imageFilters[ $filterSettings[ 0 ] ][ 0 ], $filterSettings[ 1 ], $filterSettings[ 2 ], $filterSettings[ 3 ]);
1039 | break;
1040 |
1041 | case 4:
1042 |
1043 | imagefilter($canvas, $imageFilters[ $filterSettings[ 0 ] ][ 0 ], $filterSettings[ 1 ], $filterSettings[ 2 ], $filterSettings[ 3 ], $filterSettings[ 4 ]);
1044 | break;
1045 |
1046 | default:
1047 |
1048 | imagefilter($canvas, $imageFilters[ $filterSettings[ 0 ] ][ 0 ]);
1049 | break;
1050 | }
1051 | }
1052 | }
1053 | }
1054 |
1055 | // sharpen image
1056 | if ($sharpen && function_exists('imageconvolution')) {
1057 |
1058 | $sharpenMatrix = array(
1059 | array(-1, -1, -1),
1060 | array(-1, 16, -1),
1061 | array(-1, -1, -1),
1062 | );
1063 |
1064 | $divisor = 8;
1065 | $offset = 0;
1066 |
1067 | imageconvolution($canvas, $sharpenMatrix, $divisor, $offset);
1068 | }
1069 | //Straight from Wordpress core code. Reduces filesize by up to 70% for PNG's
1070 | if ((IMAGETYPE_PNG == $origType || IMAGETYPE_GIF == $origType) && function_exists('imageistruecolor') && !imageistruecolor($image) && imagecolortransparent($image) > 0) {
1071 | imagetruecolortopalette($canvas, FALSE, imagecolorstotal($image));
1072 | }
1073 |
1074 | $tempfile = tempnam($this->cacheDirectory, 'mthumb_tmpimg_');
1075 | if (preg_match('/^image\/(?:jpg|jpeg)$/i', $mimeType)) {
1076 | $imgType = 'jpg';
1077 | imagejpeg($canvas, $tempfile, $quality);
1078 | } else {
1079 | if (preg_match('/^image\/png$/i', $mimeType)) {
1080 | $imgType = 'png';
1081 | imagepng($canvas, $tempfile, floor($quality * 0.09));
1082 | } else {
1083 | if (preg_match('/^image\/gif$/i', $mimeType)) {
1084 | $imgType = 'gif';
1085 | imagegif($canvas, $tempfile);
1086 | } else {
1087 | return $this->sanityFail("Could not match mime type after verifying it previously.");
1088 | }
1089 | }
1090 | }
1091 |
1092 | if ($imgType == 'png' && OPTIPNG_ENABLED && OPTIPNG_PATH && @is_file(OPTIPNG_PATH)) {
1093 | $exec = OPTIPNG_PATH;
1094 | $this->debug(3, "optipng'ing $tempfile");
1095 | $presize = filesize($tempfile);
1096 | $out = `$exec -o1 $tempfile`; //you can use up to -o7 but it really slows things down
1097 | clearstatcache();
1098 | $aftersize = filesize($tempfile);
1099 | $sizeDrop = $presize - $aftersize;
1100 | if ($sizeDrop > 0) {
1101 | $this->debug(1, "optipng reduced size by $sizeDrop");
1102 | } else {
1103 | if ($sizeDrop < 0) {
1104 | $this->debug(1, "optipng increased size! Difference was: $sizeDrop");
1105 | } else {
1106 | $this->debug(1, "optipng did not change image size.");
1107 | }
1108 | }
1109 | } else {
1110 | if ($imgType == 'png' && PNGCRUSH_ENABLED && PNGCRUSH_PATH && @is_file(PNGCRUSH_PATH)) {
1111 | $exec = PNGCRUSH_PATH;
1112 | $tempfile2 = tempnam($this->cacheDirectory, 'mthumb_tmpimg_');
1113 | $this->debug(3, "pngcrush'ing $tempfile to $tempfile2");
1114 | $out = `$exec $tempfile $tempfile2`;
1115 |
1116 | if (is_file($tempfile2)) {
1117 | $sizeDrop = filesize($tempfile) - filesize($tempfile2);
1118 | if ($sizeDrop > 0) {
1119 | $this->debug(1, "pngcrush was succesful and gave a $sizeDrop byte size reduction");
1120 | $todel = $tempfile;
1121 | $tempfile = $tempfile2;
1122 | } else {
1123 | $this->debug(1, "pngcrush did not reduce file size. Difference was $sizeDrop bytes.");
1124 | $todel = $tempfile2;
1125 | }
1126 | } else {
1127 | $this->debug(3, "pngcrush failed with output: $out");
1128 | $todel = $tempfile2;
1129 | }
1130 | @unlink($todel);
1131 | }
1132 | }
1133 |
1134 | $this->debug(3, "Rewriting image with security header.");
1135 | $tempfile4 = tempnam($this->cacheDirectory, 'mthumb_tmpimg_');
1136 | $context = stream_context_create();
1137 | $fp = fopen($tempfile, 'r', 0, $context);
1138 | file_put_contents($tempfile4, $this->filePrependSecurityBlock . $imgType . ' ?' . '>'); //6 extra bytes, first 3 being image type
1139 | file_put_contents($tempfile4, $fp, FILE_APPEND);
1140 | fclose($fp);
1141 | @unlink($tempfile);
1142 | $this->debug(3, "Locking and replacing cache file.");
1143 | $lockFile = $this->cachefile . '.lock';
1144 | $fh = fopen($lockFile, 'w');
1145 | if (!$fh) {
1146 | return $this->error("Could not open the lockfile for writing an image.");
1147 | }
1148 | if (flock($fh, LOCK_EX)) {
1149 | @unlink($this->cachefile); //rename generally overwrites, but doing this in case of platform specific quirks. File might not exist yet.
1150 | rename($tempfile4, $this->cachefile);
1151 | flock($fh, LOCK_UN);
1152 | fclose($fh);
1153 | @unlink($lockFile);
1154 | } else {
1155 | fclose($fh);
1156 | @unlink($lockFile);
1157 | @unlink($tempfile4);
1158 |
1159 | return $this->error("Could not get a lock for writing.");
1160 | }
1161 | $this->debug(3, "Done image replace with security header. Cleaning up and running cleanCache()");
1162 | imagedestroy($canvas);
1163 | imagedestroy($image);
1164 |
1165 | return TRUE;
1166 | }
1167 |
1168 | /**
1169 | *
1170 | */
1171 | protected function calcDocRoot() {
1172 | $docRoot = @$_SERVER[ 'DOCUMENT_ROOT' ];
1173 | if (defined('LOCAL_FILE_BASE_DIRECTORY')) {
1174 | $docRoot = LOCAL_FILE_BASE_DIRECTORY;
1175 | }
1176 | if (!isset($docRoot)) {
1177 | $this->debug(3, "DOCUMENT_ROOT is not set. This is probably windows. Starting search 1.");
1178 | if (isset($_SERVER[ 'SCRIPT_FILENAME' ])) {
1179 | $docRoot = str_replace('\\', '/', substr($_SERVER[ 'SCRIPT_FILENAME' ], 0, 0 - strlen($_SERVER[ 'PHP_SELF' ])));
1180 | $this->debug(3, "Generated docRoot using SCRIPT_FILENAME and PHP_SELF as: $docRoot");
1181 | }
1182 | }
1183 | if (!isset($docRoot)) {
1184 | $this->debug(3, "DOCUMENT_ROOT still is not set. Starting search 2.");
1185 | if (isset($_SERVER[ 'PATH_TRANSLATED' ])) {
1186 | $docRoot = str_replace('\\', '/', substr(str_replace('\\\\', '\\', $_SERVER[ 'PATH_TRANSLATED' ]), 0, 0 - strlen($_SERVER[ 'PHP_SELF' ])));
1187 | $this->debug(3, "Generated docRoot using PATH_TRANSLATED and PHP_SELF as: $docRoot");
1188 | }
1189 | }
1190 | if ($docRoot && $_SERVER[ 'DOCUMENT_ROOT' ] != '/') {
1191 | $docRoot = preg_replace('/\/$/', '', $docRoot);
1192 | }
1193 | $this->debug(3, "Doc root is: " . $docRoot);
1194 | $this->docRoot = $docRoot;
1195 | }
1196 |
1197 | /**
1198 | * @param $src
1199 | *
1200 | * @return bool|string
1201 | */
1202 | protected function getLocalImagePath($src) {
1203 | $src = ltrim($src, '/'); //strip off the leading '/'
1204 | if (!$this->docRoot) {
1205 | $this->debug(3, "We have no document root set, so as a last resort, lets check if the image is in the current dir and serve that.");
1206 | //We don't support serving images outside the current dir if we don't have a doc root for security reasons.
1207 | $file = preg_replace('/^.*?([^\/\\\\]+)$/', '$1', $src); //strip off any path info and just leave the filename.
1208 | if (is_file($file)) {
1209 | return $this->realpath($file);
1210 | }
1211 |
1212 | return $this->error("Could not find your website document root and the file specified doesn't exist in mThumb's directory. We don't support serving files outside mThumb's directory without a document root for security reasons.");
1213 | } else {
1214 | if (!is_dir($this->docRoot)) {
1215 | $this->error("Server path does not exist. Ensure variable \$_SERVER['DOCUMENT_ROOT'] is set correctly");
1216 | }
1217 | }
1218 |
1219 | //Do not go past this point without docRoot set
1220 |
1221 | //Try src under docRoot
1222 | if (file_exists($this->docRoot . '/' . $src)) {
1223 | $this->debug(3, "Found file as " . $this->docRoot . '/' . $src);
1224 | $real = $this->realpath($this->docRoot . '/' . $src);
1225 | if (stripos($real, $this->docRoot) === 0) {
1226 | return $real;
1227 | } else {
1228 | $this->debug(1, "Security block: The file specified occurs outside the document root.");
1229 | //allow search to continue
1230 | }
1231 | }
1232 | //Check absolute paths and then verify the real path is under doc root
1233 | $absolute = $this->realpath('/' . $src);
1234 | if ($absolute && file_exists($absolute)) { //realpath does file_exists check, so can probably skip the exists check here
1235 | $this->debug(3, "Found absolute path: $absolute");
1236 | if (!$this->docRoot) {
1237 | $this->sanityFail("docRoot not set when checking absolute path.");
1238 | }
1239 | if (stripos($absolute, $this->docRoot) === 0) {
1240 | return $absolute;
1241 | } else {
1242 | $this->debug(1, "Security block: The file specified occurs outside the document root.");
1243 | //and continue search
1244 | }
1245 | }
1246 |
1247 | $base = $this->docRoot;
1248 |
1249 | // account for Windows directory structure
1250 | if (strstr($_SERVER[ 'SCRIPT_FILENAME' ], ':')) {
1251 | $sub_directories = explode('\\', str_replace($this->docRoot, '', $_SERVER[ 'SCRIPT_FILENAME' ]));
1252 | } else {
1253 | $sub_directories = explode('/', str_replace($this->docRoot, '', $_SERVER[ 'SCRIPT_FILENAME' ]));
1254 | }
1255 |
1256 | foreach ($sub_directories as $sub) {
1257 | $base .= $sub . '/';
1258 | $this->debug(3, "Trying file as: " . $base . $src);
1259 | if (file_exists($base . $src)) {
1260 | $this->debug(3, "Found file as: " . $base . $src);
1261 | $real = $this->realpath($base . $src);
1262 | if (stripos($real, $this->realpath($this->docRoot)) === 0) {
1263 | return $real;
1264 | } else {
1265 | $this->debug(1, "Security block: The file specified occurs outside the document root.");
1266 | //And continue search
1267 | }
1268 | }
1269 | }
1270 |
1271 | return FALSE;
1272 | }
1273 |
1274 | /**
1275 | * @param $path
1276 | *
1277 | * @return string
1278 | */
1279 | protected function realpath($path) {
1280 | // try to remove any relative paths
1281 | $remove_relatives = '/\w+\/\.\.\//';
1282 | while (preg_match($remove_relatives, $path)) {
1283 | $path = preg_replace($remove_relatives, '', $path);
1284 | }
1285 | // if any remain use PHP realpath to strip them out, otherwise return $path
1286 | // if using realpath, any symlinks will also be resolved
1287 | return preg_match('#^\.\./|/\.\./#', $path) ? realpath($path) : $path;
1288 | }
1289 |
1290 | /**
1291 | * @param $name
1292 | */
1293 | protected function toDelete($name) {
1294 | $this->debug(3, "Scheduling file $name to delete on destruct.");
1295 | $this->toDeletes[] = $name;
1296 | }
1297 |
1298 | /**
1299 | * @param $h
1300 | * @param $d
1301 | *
1302 | * @return int
1303 | */
1304 | public static function curlWrite($h, $d) {
1305 | fwrite(self::$curlFH, $d);
1306 | self::$curlDataWritten += strlen($d);
1307 | if (self::$curlDataWritten > MAX_FILE_SIZE) {
1308 | return 0;
1309 | } else {
1310 | return strlen($d);
1311 | }
1312 | }
1313 |
1314 | /**
1315 | * @return bool
1316 | */
1317 | protected function serveCacheFile() {
1318 | $this->debug(3, "Serving {$this->cachefile}");
1319 | if (!is_file($this->cachefile)) {
1320 | $this->error("serveCacheFile called in mthumb but we couldn't find the cached file.");
1321 |
1322 | return FALSE;
1323 | }
1324 | $fp = fopen($this->cachefile, 'rb');
1325 | if (!$fp) {
1326 | return $this->error("Could not open cachefile.");
1327 | }
1328 | fseek($fp, strlen($this->filePrependSecurityBlock), SEEK_SET);
1329 | $imgType = fread($fp, 3);
1330 | fseek($fp, 3, SEEK_CUR);
1331 | if (ftell($fp) != strlen($this->filePrependSecurityBlock) + 6) {
1332 | @unlink($this->cachefile);
1333 |
1334 | return $this->error("The cached image file seems to be corrupt.");
1335 | }
1336 | $imageDataSize = filesize($this->cachefile) - (strlen($this->filePrependSecurityBlock) + 6);
1337 | $this->sendImageHeaders($imgType, $imageDataSize);
1338 | $bytesSent = @fpassthru($fp);
1339 | fclose($fp);
1340 | if ($bytesSent > 0) {
1341 | return TRUE;
1342 | }
1343 | $content = file_get_contents($this->cachefile);
1344 | if ($content != FALSE) {
1345 | $content = substr($content, strlen($this->filePrependSecurityBlock) + 6);
1346 | echo $content;
1347 | $this->debug(3, "Served using file_get_contents and echo");
1348 |
1349 | return TRUE;
1350 | } else {
1351 | $this->error("Cache file could not be loaded.");
1352 |
1353 | return FALSE;
1354 | }
1355 | }
1356 |
1357 | /**
1358 | * @param $mimeType
1359 | * @param $dataSize
1360 | *
1361 | * @return bool
1362 | */
1363 | protected function sendImageHeaders($mimeType, $dataSize) {
1364 | if (!preg_match('/^image\//i', $mimeType)) {
1365 | $mimeType = 'image/' . $mimeType;
1366 | }
1367 | if (strtolower($mimeType) == 'image/jpg') {
1368 | $mimeType = 'image/jpeg';
1369 | }
1370 | $gmdate_expires = gmdate('D, d M Y H:i:s', strtotime('now +10 days')) . ' GMT';
1371 | $gmdate_modified = gmdate('D, d M Y H:i:s') . ' GMT';
1372 | // send content headers then display image
1373 | header('Content-Type: ' . $mimeType);
1374 | header('Accept-Ranges: none'); //Changed this because we don't accept range requests
1375 | header('Last-Modified: ' . $gmdate_modified);
1376 | header('Content-Length: ' . $dataSize);
1377 | if (BROWSER_CACHE_DISABLE) {
1378 | $this->debug(3, "Browser cache is disabled so setting non-caching headers.");
1379 | header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
1380 | header("Pragma: no-cache");
1381 | header('Expires: ' . gmdate('D, d M Y H:i:s', time()));
1382 | } else {
1383 | $this->debug(3, "Browser caching is enabled");
1384 | header('Cache-Control: max-age=' . BROWSER_CACHE_MAX_AGE . ', must-revalidate');
1385 | header('Expires: ' . $gmdate_expires);
1386 | }
1387 |
1388 | return TRUE;
1389 | }
1390 |
1391 | /**
1392 | * @param $property
1393 | * @param string $default
1394 | *
1395 | * @return string
1396 | */
1397 | protected function param($property, $default = '') {
1398 | if (isset ($_GET[ $property ])) {
1399 | return $_GET[ $property ];
1400 | } else {
1401 | return $default;
1402 | }
1403 | }
1404 |
1405 | /**
1406 | * @param $mimeType
1407 | * @param $src
1408 | *
1409 | * @return resource
1410 | */
1411 | protected function openImage($mimeType, $src) {
1412 | switch ($mimeType) {
1413 | case 'image/jpeg':
1414 | $image = imagecreatefromjpeg($src);
1415 | break;
1416 |
1417 | case 'image/png':
1418 | $image = imagecreatefrompng($src);
1419 | imagealphablending($image, TRUE);
1420 | imagesavealpha($image, TRUE);
1421 | break;
1422 |
1423 | case 'image/gif':
1424 | $image = imagecreatefromgif($src);
1425 | break;
1426 |
1427 | default:
1428 | $this->error("Unrecognised mimeType");
1429 | }
1430 |
1431 | return $image;
1432 | }
1433 |
1434 | /**
1435 | * @return string
1436 | */
1437 | protected function getIP() {
1438 | $rem = @$_SERVER[ "REMOTE_ADDR" ];
1439 | $ff = @$_SERVER[ "HTTP_X_FORWARDED_FOR" ];
1440 | $ci = @$_SERVER[ "HTTP_CLIENT_IP" ];
1441 | if (preg_match('/^(?:192\.168|172\.16|10\.|127\.)/', $rem)) {
1442 | if ($ff) {
1443 | return $ff;
1444 | }
1445 | if ($ci) {
1446 | return $ci;
1447 | }
1448 |
1449 | return $rem;
1450 | } else {
1451 | if ($rem) {
1452 | return $rem;
1453 | }
1454 | if ($ff) {
1455 | return $ff;
1456 | }
1457 | if ($ci) {
1458 | return $ci;
1459 | }
1460 |
1461 | return "UNKNOWN";
1462 | }
1463 | }
1464 |
1465 | /**
1466 | * @param $level
1467 | * @param $msg
1468 | */
1469 | protected function debug($level, $msg) {
1470 | if (DEBUG_ON && $level <= DEBUG_LEVEL) {
1471 | $execTime = sprintf('%.6f', microtime(TRUE) - $this->startTime);
1472 | $tick = sprintf('%.6f', 0);
1473 | if ($this->lastBenchTime > 0) {
1474 | $tick = sprintf('%.6f', microtime(TRUE) - $this->lastBenchTime);
1475 | }
1476 | $this->lastBenchTime = microtime(TRUE);
1477 | error_log("mThumb Debug line " . __LINE__ . " [$execTime : $tick]: $msg");
1478 | }
1479 | }
1480 |
1481 | /**
1482 | * @param $msg
1483 | *
1484 | * @return bool
1485 | */
1486 | protected function sanityFail($msg) {
1487 | return $this->error("There is a problem in the mThumb code. Message: Please report this error at mThumb's issue tracking page: $msg");
1488 | }
1489 |
1490 | /**
1491 | * @param $file
1492 | *
1493 | * @return string
1494 | */
1495 | protected function getMimeType($file) {
1496 | $info = getimagesize($file);
1497 | if (is_array($info) && $info[ 'mime' ]) {
1498 | return $info[ 'mime' ];
1499 | }
1500 |
1501 | return '';
1502 | }
1503 |
1504 | /**
1505 | * @param $size_str
1506 | *
1507 | * @return int
1508 | */
1509 | protected static function returnBytes($size_str) {
1510 | switch (substr($size_str, -1)) {
1511 | case 'M':
1512 | case 'm':
1513 | return (int) $size_str * 1048576;
1514 | case 'K':
1515 | case 'k':
1516 | return (int) $size_str * 1024;
1517 | case 'G':
1518 | case 'g':
1519 | return (int) $size_str * 1073741824;
1520 | default:
1521 | return $size_str;
1522 | }
1523 | }
1524 |
1525 | /**
1526 | * @param $url
1527 | * @param $tempfile
1528 | *
1529 | * @return bool
1530 | */
1531 | protected function getURL($url, $tempfile) {
1532 | $this->lastURLError = FALSE;
1533 | $url = preg_replace('/ /', '%20', $url);
1534 | if (function_exists('curl_init')) {
1535 | $this->debug(3, "Curl is installed so using it to fetch URL.");
1536 | self::$curlFH = fopen($tempfile, 'w');
1537 | if (!self::$curlFH) {
1538 | $this->error("Could not open $tempfile for writing.");
1539 |
1540 | return FALSE;
1541 | }
1542 | self::$curlDataWritten = 0;
1543 | $this->debug(3, "Fetching url with curl: $url");
1544 | $curl = curl_init($url);
1545 | curl_setopt($curl, CURLOPT_TIMEOUT, CURL_TIMEOUT);
1546 | curl_setopt($curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30");
1547 | curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
1548 | curl_setopt($curl, CURLOPT_HEADER, 0);
1549 | curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
1550 | curl_setopt($curl, CURLOPT_WRITEFUNCTION, 'mthumb::curlWrite');
1551 | @curl_setopt($curl, CURLOPT_FOLLOWLOCATION, TRUE);
1552 | @curl_setopt($curl, CURLOPT_MAXREDIRS, 10);
1553 |
1554 | $curlResult = curl_exec($curl);
1555 | fclose(self::$curlFH);
1556 | $httpStatus = curl_getinfo($curl, CURLINFO_HTTP_CODE);
1557 | if ($httpStatus == 404) {
1558 | $this->set404();
1559 | }
1560 | if ($httpStatus == 302) {
1561 | $this->error("External Image is Redirecting. Try alternate image URL.");
1562 |
1563 | return FALSE;
1564 | }
1565 | if ($curlResult) {
1566 | curl_close($curl);
1567 |
1568 | return TRUE;
1569 | } else {
1570 | $this->lastURLError = curl_error($curl);
1571 | curl_close($curl);
1572 |
1573 | return FALSE;
1574 | }
1575 | } else {
1576 | $img = @file_get_contents($url);
1577 | if ($img === FALSE) {
1578 | $err = error_get_last();
1579 | if (is_array($err) && $err[ 'message' ]) {
1580 | $this->lastURLError = $err[ 'message' ];
1581 | } else {
1582 | $this->lastURLError = $err;
1583 | }
1584 | if (preg_match('/404/', $this->lastURLError)) {
1585 | $this->set404();
1586 | }
1587 |
1588 | return FALSE;
1589 | }
1590 | if (!file_put_contents($tempfile, $img)) {
1591 | $this->error("Could not write to $tempfile.");
1592 |
1593 | return FALSE;
1594 | }
1595 |
1596 | return TRUE;
1597 | }
1598 | }
1599 |
1600 | /**
1601 | * @param $file
1602 | *
1603 | * @return bool
1604 | */
1605 | protected function serveImg($file) {
1606 | $s = getimagesize($file);
1607 | if (!($s && $s[ 'mime' ])) {
1608 | return FALSE;
1609 | }
1610 | header('Content-Type: ' . $s[ 'mime' ]);
1611 | header('Content-Length: ' . filesize($file));
1612 | header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
1613 | header("Pragma: no-cache");
1614 | $bytes = @readfile($file);
1615 | if ($bytes > 0) {
1616 | return TRUE;
1617 | }
1618 | $content = @file_get_contents($file);
1619 | if ($content != FALSE) {
1620 | echo $content;
1621 |
1622 | return TRUE;
1623 | }
1624 |
1625 | return FALSE;
1626 | }
1627 |
1628 | /**
1629 | *
1630 | */
1631 | protected function set404() {
1632 | $this->is404 = TRUE;
1633 | }
1634 |
1635 | /**
1636 | * @return bool
1637 | */
1638 | protected function is404() {
1639 | return $this->is404;
1640 | }
1641 | }
1642 | }
1643 | endif;
1644 |
1645 | mthumb::start();
1646 |
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Gallery from Folder Demo
6 |
17 |
18 |
19 |
20 |
21 |
\n ";
29 | }
30 | }
31 | ?>
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------