genthumb.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. <?php
  2. include '../auth.php';
  3. ?>
  4. <?php
  5. /*
  6. Title: Thumb.php
  7. URL: http://github.com/jamiebicknell/Thumb
  8. Author: Jamie Bicknell
  9. Twitter: @jamiebicknell
  10. */
  11. define('THUMB_CACHE', 'cache/'); // Path to cache directory (must be writeable)
  12. define('THUMB_CACHE_AGE', 86400); // Duration of cached files in seconds
  13. define('THUMB_BROWSER_CACHE', true); // Browser cache true or false
  14. define('SHARPEN_MIN', 12); // Minimum sharpen value
  15. define('SHARPEN_MAX', 28); // Maximum sharpen value
  16. define('ADJUST_ORIENTATION', true); // Auto adjust orientation for JPEG true or false
  17. define('JPEG_QUALITY', 100); // Quality of generated JPEGs (0 - 100; 100 being best)
  18. $src = isset($_GET['src']) ? $_GET['src'] : false;
  19. $size = isset($_GET['size']) ? str_replace(array('<', 'x'), '', $_GET['size']) != '' ? $_GET['size'] : 100 : 100;
  20. $crop = isset($_GET['crop']) ? max(0, min(1, $_GET['crop'])) : 1;
  21. $trim = isset($_GET['trim']) ? max(0, min(1, $_GET['trim'])) : 0;
  22. $zoom = isset($_GET['zoom']) ? max(0, min(1, $_GET['zoom'])) : 0;
  23. $align = isset($_GET['align']) ? $_GET['align'] : false;
  24. $sharpen = isset($_GET['sharpen']) ? max(0, min(100, $_GET['sharpen'])) : 0;
  25. $gray = isset($_GET['gray']) ? max(0, min(1, $_GET['gray'])) : 0;
  26. $ignore = isset($_GET['ignore']) ? max(0, min(1, $_GET['ignore'])) : 0;
  27. $path = parse_url($src);
  28. if (isset($path['scheme'])) {
  29. $base = parse_url('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
  30. if (preg_replace('/^www\./i', '', $base['host']) == preg_replace('/^www\./i', '', $path['host'])) {
  31. $base = explode('/', preg_replace('/\/+/', '/', $base['path']));
  32. $path = explode('/', preg_replace('/\/+/', '/', $path['path']));
  33. $temp = $path;
  34. $part = count($base);
  35. foreach ($base as $k => $v) {
  36. if ($v == $path[$k]) {
  37. array_shift($temp);
  38. } else {
  39. if ($part - $k > 1) {
  40. $temp = array_pad($temp, 0 - (count($temp) + ($part - $k) - 1), '..');
  41. break;
  42. } else {
  43. $temp[0] = './' . $temp[0];
  44. }
  45. }
  46. }
  47. $src = implode('/', $temp);
  48. }
  49. }
  50. //$src = iconv('utf-8','big-5',$src);
  51. if (!extension_loaded('gd')) {
  52. die('GD extension is not installed');
  53. }
  54. if (!is_writable(THUMB_CACHE)) {
  55. die('Cache not writable');
  56. }
  57. if (isset($path['scheme']) || !file_exists($src)) {
  58. die('File cannot be found'.$src);
  59. }
  60. if (!in_array(strtolower(substr(strrchr($src, '.'), 1)), array('gif', 'jpg', 'jpeg', 'png'))) {
  61. die('File is not an image');
  62. }
  63. $file_salt = 'v1.0.5';
  64. $file_size = filesize($src);
  65. $file_time = filemtime($src);
  66. $file_date = gmdate('D, d M Y H:i:s T', $file_time);
  67. $file_type = strtolower(substr(strrchr($src, '.'), 1));
  68. $file_hash = md5($file_salt . ($src.$size.$crop.$trim.$zoom.$align.$sharpen.$gray.$ignore) . $file_time);
  69. $file_temp = THUMB_CACHE . $file_hash . '.img.txt';
  70. $file_name = basename(substr($src, 0, strrpos($src, '.')) . strtolower(strrchr($src, '.')));
  71. if (!file_exists(THUMB_CACHE . 'index.html')) {
  72. touch(THUMB_CACHE . 'index.html');
  73. }
  74. if (($fp = fopen(THUMB_CACHE . 'index.html', 'r')) !== false) {
  75. if (flock($fp, LOCK_EX)) {
  76. if (time() - THUMB_CACHE_AGE > filemtime(THUMB_CACHE . 'index.html')) {
  77. $files = glob(THUMB_CACHE . '*.img.txt');
  78. if (is_array($files) && count($files) > 0) {
  79. foreach ($files as $file) {
  80. if (time() - THUMB_CACHE_AGE > filemtime($file)) {
  81. unlink($file);
  82. }
  83. }
  84. }
  85. touch(THUMB_CACHE . 'index.html');
  86. }
  87. flock($fp, LOCK_UN);
  88. }
  89. fclose($fp);
  90. }
  91. if (THUMB_BROWSER_CACHE && (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) || isset($_SERVER['HTTP_IF_NONE_MATCH']))) {
  92. if ($_SERVER['HTTP_IF_MODIFIED_SINCE'] == $file_date && $_SERVER['HTTP_IF_NONE_MATCH'] == $file_hash) {
  93. header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified');
  94. die();
  95. }
  96. }
  97. if (!file_exists($file_temp)) {
  98. list($w0, $h0, $type) = getimagesize($src);
  99. $data = file_get_contents($src);
  100. if ($ignore && $type == 1) {
  101. if (preg_match('/\x00\x21\xF9\x04.{4}\x00(\x2C|\x21)/s', $data)) {
  102. header('Content-Type: image/gif');
  103. header('Content-Length: ' . $file_size);
  104. header('Content-Disposition: inline; filename="' . $file_name . '"');
  105. header('Last-Modified: ' . $file_date);
  106. header('ETag: ' . $file_hash);
  107. header('Accept-Ranges: none');
  108. if (THUMB_BROWSER_CACHE) {
  109. header('Cache-Control: max-age=604800, must-revalidate');
  110. header('Expires: ' . gmdate('D, d M Y H:i:s T', strtotime('+7 days')));
  111. } else {
  112. header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
  113. header('Expires: ' . gmdate('D, d M Y H:i:s T'));
  114. header('Pragma: no-cache');
  115. }
  116. die($data);
  117. }
  118. }
  119. $oi = imagecreatefromstring($data);
  120. if (function_exists('exif_read_data') && ADJUST_ORIENTATION && $type == 2) {
  121. // I know supressing errors is bad, but calling exif_read_data on invalid
  122. // or corrupted data returns a fatal error and there's no way to validate
  123. // the EXIF data before calling the function.
  124. $exif = @exif_read_data($src, EXIF);
  125. if (isset($exif['Orientation'])) {
  126. $degree = 0;
  127. $mirror = false;
  128. switch ($exif['Orientation']) {
  129. case 2:
  130. $mirror = true;
  131. break;
  132. case 3:
  133. $degree = 180;
  134. break;
  135. case 4:
  136. $degree = 180;
  137. $mirror = true;
  138. break;
  139. case 5:
  140. $degree = 270;
  141. $mirror = true;
  142. $w0 ^= $h0 ^= $w0 ^= $h0;
  143. break;
  144. case 6:
  145. $degree = 270;
  146. $w0 ^= $h0 ^= $w0 ^= $h0;
  147. break;
  148. case 7:
  149. $degree = 90;
  150. $mirror = true;
  151. $w0 ^= $h0 ^= $w0 ^= $h0;
  152. break;
  153. case 8:
  154. $degree = 90;
  155. $w0 ^= $h0 ^= $w0 ^= $h0;
  156. break;
  157. }
  158. if ($degree > 0) {
  159. $oi = imagerotate($oi, $degree, 0);
  160. }
  161. if ($mirror) {
  162. $nm = $oi;
  163. $oi = imagecreatetruecolor($w0, $h0);
  164. imagecopyresampled($oi, $nm, 0, 0, $w0 - 1, 0, $w0, $h0, -$w0, $h0);
  165. imagedestroy($nm);
  166. }
  167. }
  168. }
  169. list($w,$h) = explode('x', str_replace('<', '', $size) . 'x');
  170. $w = ($w != '') ? floor(max(8, min(1500, $w))) : '';
  171. $h = ($h != '') ? floor(max(8, min(1500, $h))) : '';
  172. if (strstr($size, '<')) {
  173. $h = $w;
  174. $crop = 0;
  175. $trim = 1;
  176. } elseif (!strstr($size, 'x')) {
  177. $h = $w;
  178. } elseif ($w == '' || $h == '') {
  179. $w = ($w == '') ? ($w0 * $h) / $h0 : $w;
  180. $h = ($h == '') ? ($h0 * $w) / $w0 : $h;
  181. $crop = 0;
  182. $trim = 1;
  183. }
  184. $trim_w = ($trim) ? 1 : ($w == '') ? 1 : 0;
  185. $trim_h = ($trim) ? 1 : ($h == '') ? 1 : 0;
  186. if ($crop) {
  187. $w1 = (($w0 / $h0) > ($w / $h)) ? floor($w0 * $h / $h0) : $w;
  188. $h1 = (($w0 / $h0) < ($w / $h)) ? floor($h0 * $w / $w0) : $h;
  189. if (!$zoom) {
  190. if ($h0 < $h || $w0 < $w) {
  191. $w1 = $w0;
  192. $h1 = $h0;
  193. }
  194. }
  195. } else {
  196. $w1 = (($w0 / $h0) < ($w / $h)) ? floor($w0 * $h / $h0) : floor($w);
  197. $h1 = (($w0 / $h0) > ($w / $h)) ? floor($h0 * $w / $w0) : floor($h);
  198. $w = floor($w);
  199. $h = floor($h);
  200. if (!$zoom) {
  201. if ($h0 < $h && $w0 < $w) {
  202. $w1 = $w0;
  203. $h1 = $h0;
  204. }
  205. }
  206. }
  207. $w = ($trim_w) ? (($w0 / $h0) > ($w / $h)) ? min($w, $w1) : $w1 : $w;
  208. $h = ($trim_h) ? (($w0 / $h0) < ($w / $h)) ? min($h, $h1) : $h1 : $h;
  209. if ($sharpen) {
  210. $matrix = array (
  211. array(-1, -1, -1),
  212. array(-1, SHARPEN_MAX - ($sharpen * (SHARPEN_MAX - SHARPEN_MIN)) / 100, -1),
  213. array(-1, -1, -1));
  214. $divisor = array_sum(array_map('array_sum', $matrix));
  215. }
  216. $x = strpos($align, 'l') !== false ? 0 : (strpos($align, 'r') !== false ? $w - $w1 : ($w - $w1) / 2);
  217. $y = strpos($align, 't') !== false ? 0 : (strpos($align, 'b') !== false ? $h - $h1 : ($h - $h1) / 2);
  218. $im = imagecreatetruecolor($w, $h);
  219. $bg = imagecolorallocate($im, 255, 255, 255);
  220. imagefill($im, 0, 0, $bg);
  221. switch ($type) {
  222. case 1:
  223. imagecopyresampled($im, $oi, $x, $y, 0, 0, $w1, $h1, $w0, $h0);
  224. if ($sharpen && version_compare(PHP_VERSION, '5.1.0', '>=')) {
  225. imageconvolution($im, $matrix, $divisor, 0);
  226. }
  227. if ($gray) {
  228. imagefilter($im, IMG_FILTER_GRAYSCALE);
  229. }
  230. imagegif($im, $file_temp);
  231. break;
  232. case 2:
  233. imagecopyresampled($im, $oi, $x, $y, 0, 0, $w1, $h1, $w0, $h0);
  234. if ($sharpen && version_compare(PHP_VERSION, '5.1.0', '>=')) {
  235. imageconvolution($im, $matrix, $divisor, 0);
  236. }
  237. if ($gray) {
  238. imagefilter($im, IMG_FILTER_GRAYSCALE);
  239. }
  240. imagejpeg($im, $file_temp, JPEG_QUALITY);
  241. break;
  242. case 3:
  243. imagefill($im, 0, 0, imagecolorallocatealpha($im, 0, 0, 0, 127));
  244. imagesavealpha($im, true);
  245. imagealphablending($im, false);
  246. imagecopyresampled($im, $oi, $x, $y, 0, 0, $w1, $h1, $w0, $h0);
  247. if ($sharpen && version_compare(PHP_VERSION, '5.1.0', '>=')) {
  248. $fix = imagecolorat($im, 0, 0);
  249. imageconvolution($im, $matrix, $divisor, 0);
  250. imagesetpixel($im, 0, 0, $fix);
  251. }
  252. if ($gray) {
  253. imagefilter($im, IMG_FILTER_GRAYSCALE);
  254. }
  255. imagepng($im, $file_temp);
  256. break;
  257. }
  258. imagedestroy($im);
  259. imagedestroy($oi);
  260. }
  261. header('Content-Type: image/' . $file_type);
  262. header('Content-Length: ' . filesize($file_temp));
  263. header('Content-Disposition: inline; filename="' . $file_name . '"');
  264. header('Last-Modified: ' . $file_date);
  265. header('ETag: ' . $file_hash);
  266. header('Accept-Ranges: none');
  267. if (THUMB_BROWSER_CACHE) {
  268. header('Cache-Control: max-age=604800, must-revalidate');
  269. header('Expires: ' . gmdate('D, d M Y H:i:s T', strtotime('+7 days')));
  270. } else {
  271. header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
  272. header('Expires: ' . gmdate('D, d M Y H:i:s T'));
  273. header('Pragma: no-cache');
  274. }
  275. readfile($file_temp);