1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41:
42:
43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62:
63: define('MEMORY_TO_ALLOCATE', '100M');
64: define('DEFAULT_IMAGE_QUALITY', 90);
65: define('DEFAULT_BACKGROUND_COLOR', '000000');
66: define('ONLY_LOCAL_IMAGES', true);
67: define('ENABLE_IMAGEFILTER', true);
68: define('ENABLE_ROUNDCORNER', true);
69: define('ENABLE_IMAGEROTATE', true);
70:
71: if (get_magic_quotes_runtime()) {
72: set_magic_quotes_runtime(false);
73: }
74: if (function_exists('mb_http_output')) {
75: mb_http_output('pass');
76: }
77:
78: $xoopsOption['nocommon'] = true;
79: require_once __DIR__ . '/mainfile.php';
80:
81: include_once __DIR__ . '/include/defines.php';
82: include_once __DIR__ . '/include/functions.php';
83: include_once __DIR__ . '/include/version.php';
84: include_once __DIR__ . '/kernel/object.php';
85: include_once __DIR__ . '/class/xoopsload.php';
86: include_once __DIR__ . '/class/preload.php';
87: include_once __DIR__ . '/class/module.textsanitizer.php';
88: include_once __DIR__ . '/class/database/databasefactory.php';
89: require_once __DIR__ . '/class/criteria.php';
90: XoopsLoad::load('xoopslogger');
91: $xoopsLogger = XoopsLogger::getInstance();
92: $xoopsLogger->startTime();
93: error_reporting(0);
94:
95: 96: 97: 98: 99:
100: function doConditionalGet($etag, $lastModified)
101: {
102: header("Last-Modified: $lastModified");
103: header("ETag: \"{$etag}\"");
104: $ifNoneMatch = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) : false;
105: $ifModifiedSince = isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])
106: ? stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE']) : false;
107: if (!$ifModifiedSince && !$ifNoneMatch) {
108: return null;
109: }
110: if ($ifNoneMatch && $ifNoneMatch != $etag && $ifNoneMatch != '"' . $etag . '"') {
111: return null;
112: }
113: if ($ifModifiedSince && $ifModifiedSince != $lastModified) {
114: return null;
115: }
116:
117: header('HTTP/1.1 304 Not Modified');
118: exit();
119: }
120:
121: 122: 123: 124: 125: 126: 127: 128: 129:
130: function imageCreateCorners($sourceImage, $radii)
131: {
132: $q = 2;
133:
134:
135: $tryCounter = 0;
136: do {
137: if (++$tryCounter > 255) {
138: $r = 2;
139: $g = 254;
140: $b = 0;
141: break;
142: }
143: $r = rand(0, 255);
144: $g = rand(0, 255);
145: $b = rand(0, 255);
146: } while (imagecolorexact($sourceImage, $r, $g, $b) < 0);
147:
148: $imageWidth = imagesx($sourceImage);
149: $imageHeight = imagesy($sourceImage);
150:
151: $workingWidth = $imageWidth * $q;
152: $workingHeight = $imageHeight * $q;
153:
154: $workingImage= imagecreatetruecolor($workingWidth, $workingHeight);
155: $alphaColor = imagecolorallocatealpha($workingImage, $r, $g, $b, 127);
156: imagealphablending($workingImage, false);
157: imagesavealpha($workingImage, true);
158: imagefilledrectangle($workingImage, 0, 0, $workingWidth, $workingHeight, $alphaColor);
159:
160: imagefill($workingImage, 0, 0, $alphaColor);
161: imagecopyresampled($workingImage, $sourceImage, 0, 0, 0, 0, $workingWidth, $workingHeight, $imageWidth, $imageHeight);
162: if (0 < ($radius = $radii[0] * $q)) {
163: imagearc($workingImage, $radius - 1, $radius - 1, $radius * 2, $radius * 2, 180, 270, $alphaColor);
164: imagefilltoborder($workingImage, 0, 0, $alphaColor, $alphaColor);
165: }
166: if (0 < ($radius = $radii[1] * $q)) {
167: imagearc($workingImage, $workingWidth - $radius, $radius - 1, $radius * 2, $radius * 2, 270, 0, $alphaColor);
168: imagefilltoborder($workingImage, $workingWidth - 1, 0, $alphaColor, $alphaColor);
169: }
170: if (0 < ($radius = $radii[2] * $q)) {
171: imagearc($workingImage, $radius - 1, $workingHeight - $radius, $radius * 2, $radius * 2, 90, 180, $alphaColor);
172: imagefilltoborder($workingImage, 0, $workingHeight - 1, $alphaColor, $alphaColor);
173: }
174: if (0 < ($radius = $radii[3] * $q)) {
175: imagearc($workingImage, $workingWidth - $radius, $workingHeight - $radius, $radius * 2, $radius * 2, 0, 90, $alphaColor);
176: imagefilltoborder($workingImage, $workingWidth - 1, $workingHeight - 1, $alphaColor, $alphaColor);
177: }
178: imagealphablending($workingImage, true);
179: imagecolortransparent($workingImage, $alphaColor);
180:
181:
182: $destinationImage = imagecreatetruecolor($imageWidth, $imageHeight);
183: imagealphablending($destinationImage, false);
184: imagesavealpha($destinationImage, true);
185: imagefilledrectangle($destinationImage, 0, 0, $imageWidth, $imageHeight, $alphaColor);
186: imagecopyresampled($destinationImage, $workingImage, 0, 0, 0, 0, $imageWidth, $imageHeight, $workingWidth, $workingHeight);
187:
188:
189: imagedestroy($workingImage);
190:
191: return $destinationImage;
192: }
193:
194: 195: 196: 197: 198: 199:
200: function findSharp($orig, $final)
201: {
202:
203: $final *= (750.0 / $orig);
204: $a = 52;
205: $b = -0.27810650887573124;
206: $c = .00047337278106508946;
207: $result = $a + $b * $final + $c * $final * $final;
208:
209: return max(round($result), 0);
210: }
211:
212: 213: 214: 215: 216:
217: function exit404BadReq()
218: {
219: header('HTTP/1.1 404 Not Found');
220: exit();
221: }
222:
223: 224: 225: 226: 227: 228: 229:
230: function imageFilenameCheck($imageUrl)
231: {
232: if ($imageUrl[0] !== '/') {
233: exit404BadReq();
234: }
235:
236: if ($imageUrl === '/') {
237: exit404BadReq();
238: }
239:
240: if (preg_match('/(\.\.|<|>|\:|[[:cntrl:]])/', $imageUrl)) {
241: exit404BadReq();
242: }
243:
244: $fullPath = XOOPS_ROOT_PATH . $imageUrl;
245: if (strpos($fullPath, XOOPS_VAR_PATH) === 0) {
246: exit404BadReq();
247: }
248: if (strpos($fullPath, XOOPS_PATH) === 0) {
249: exit404BadReq();
250: }
251:
252: return true;
253: }
254:
255: 256: 257:
258:
259: $imageId = isset($_GET['id']) ? (int)$_GET['id'] : false;
260: $imageUrl = isset($_GET['url']) ? (string)$_GET['url'] : (isset($_GET['src']) ? (string)$_GET['src'] : false);
261: if (!empty($imageId)) {
262:
263:
264: $imageHandler = xoops_getHandler('image');
265: $criteria = new CriteriaCompo(new Criteria('i.image_display', true));
266: $criteria->add(new Criteria('i.image_id', $imageId));
267: $images = $imageHandler->getObjects($criteria, false, true);
268: if (count($images) != 1) {
269:
270: header('Content-type: image/gif');
271: readfile(XOOPS_UPLOAD_PATH . '/blank.gif');
272: exit();
273: }
274: $image = $images[0];
275:
276: $imgcatId = $image->getVar('imgcat_id');
277: $imgcatHandler = xoops_getHandler('imagecategory');
278: if (!$imgcat = $imgcatHandler->get($imgcatId)) {
279:
280: header('Content-type: image/gif');
281: readfile(XOOPS_UPLOAD_PATH . '/blank.gif');
282: exit();
283: }
284:
285: $imageFilename = $image->getVar('image_name');
286: $imageMimetype = $image->getVar('image_mimetype');
287: $imageCreatedTime = $image->getVar('image_created');
288: if ($imgcat->getVar('imgcat_storetype') === 'db') {
289: $imagePath = null;
290: $imageData = $image->getVar('image_body');
291: } else {
292: $imagePath = XOOPS_UPLOAD_PATH . '/' . $image->getVar('image_name');
293: $imageData = file_get_contents($imagePath);
294: }
295: $sourceImage = imagecreatefromstring($imageData);
296: $imageWidth = imagesx($sourceImage);
297: $imageHeight = imagesy($sourceImage);
298: } elseif (!empty($imageUrl)) {
299:
300: if (ONLY_LOCAL_IMAGES) {
301:
302: $imageUrl = str_replace(XOOPS_URL, '', $imageUrl);
303:
304:
305: imageFilenameCheck($imageUrl);
306:
307: $imagePath = XOOPS_ROOT_PATH . $imageUrl;
308: if (!file_exists($imagePath)) {
309: exit404BadReq();
310: }
311: } else {
312: if ($imageUrl{0} === '/') {
313: $imageUrl = substr($imageUrl, 0, 1);
314: }
315: $imagePath = $imageUrl;
316: }
317:
318: $imageFilename = basename($imagePath);
319: $imagesize = getimagesize($imagePath);
320: $imageWidth = $imagesize[0];
321: $imageHeight = $imagesize[1];
322: $imageMimetype = $imagesize['mime'];
323: $imageCreatedTime = filemtime($imagePath);
324: $imageData = file_get_contents($imagePath);
325: switch ($imageMimetype) {
326: case 'image/gif':
327: $sourceImage = imagecreatefromgif($imagePath);
328: break;
329: case 'image/png':
330: $sourceImage = imagecreatefrompng($imagePath);
331: break;
332: case 'image/jpeg':
333: $sourceImage = imagecreatefromjpeg($imagePath);
334: break;
335: default:
336: exit404BadReq();
337: break;
338: }
339: } else {
340:
341: header('Content-type: image/gif');
342: readfile(XOOPS_ROOT_PATH . '/uploads/blank.gif');
343: exit();
344: }
345:
346: 347: 348:
349:
350:
351: xoops_load('XoopsCache');
352: $edited_image_filename = 'editedimage_' . md5($_SERVER['REQUEST_URI']) . '_' . $imageFilename;
353: $cached_image = XoopsCache::read($edited_image_filename);
354: if (!isset($_GET['nocache']) && !isset($_GET['noservercache']) && !empty($cached_image)
355: && ($cached_image['cached_time'] >= $imageCreatedTime)) {
356: header("Content-type: {$imageMimetype}");
357: header('Content-Length: ' . strlen($cached_image['image_data']));
358: echo $cached_image['image_data'];
359: exit();
360: }
361:
362: 363: 364:
365:
366: $max_width = isset($_GET['width']) ? (int)$_GET['width'] : false;
367: $max_height = isset($_GET['height']) ? (int)$_GET['height'] : false;
368:
369:
370:
371: if (!$max_width && $max_height) {
372: $max_width = PHP_INT_MAX;
373: } elseif ($max_width && !$max_height) {
374: $max_height = PHP_INT_MAX;
375: } elseif (!$max_width && !$max_height) {
376: $max_width = $imageWidth;
377: $max_height = $imageHeight;
378: }
379:
380:
381: $color = isset($_GET['color']) ? preg_replace('/[^0-9a-fA-F]/', '', (string)$_GET['color']) : false;
382:
383:
384: $filter = isset($_GET['filter']) ? $_GET['filter'] : false;
385: $radius = isset($_GET['radius']) ? (string)$_GET['radius'] : false;
386: $angle = isset($_GET['angle']) ? (float)$_GET['angle'] : false;
387:
388:
389:
390: if (empty($_GET['width']) && empty($_GET['height']) && empty($_GET['color']) && empty($_GET['filter'])
391: && empty($_GET['radius']) && empty($_GET['angle'])) {
392: $last_modified_string = gmdate('D, d M Y H:i:s', $imageCreatedTime) . ' GMT';
393: $etag = md5($imageData);
394: doConditionalGet($etag, $last_modified_string);
395: header("Content-type: {$imageMimetype}");
396: header('Content-Length: ' . strlen($imageData));
397: echo $imageData;
398: exit();
399: }
400:
401:
402: $offset_x = 0;
403: $offset_y = 0;
404: if (isset($_GET['cropratio'])) {
405: $crop_ratio = explode(':', (string)$_GET['cropratio']);
406: if (count($crop_ratio) == 2) {
407: $ratio_computed = $imageWidth / $imageHeight;
408: $crop_radio_computed = (float)$crop_ratio[0] / (float)$crop_ratio[1];
409: if ($ratio_computed < $crop_radio_computed) {
410:
411: $orig_height = $imageHeight;
412: $imageHeight = $imageWidth / $crop_radio_computed;
413: $offset_y = ($orig_height - $imageHeight) / 2;
414: } elseif ($ratio_computed > $crop_radio_computed) {
415:
416: $orig_width = $imageWidth;
417: $imageWidth = $imageHeight * $crop_radio_computed;
418: $offset_x = ($orig_width - $imageWidth) / 2;
419: }
420: }
421: }
422:
423:
424: $xRatio = $max_width / $imageWidth;
425: $yRatio = $max_height / $imageHeight;
426: if ($xRatio * $imageHeight < $max_height) {
427:
428: $tn_height = ceil($xRatio * $imageHeight);
429: $tn_width = $max_width;
430: } else {
431:
432: $tn_width = ceil($yRatio * $imageWidth);
433: $tn_height = $max_height;
434: }
435:
436:
437: $quality = isset($_GET['quality']) ? (int)$_GET['quality'] : DEFAULT_IMAGE_QUALITY;
438:
439: 440: 441:
442:
443: ini_set('memory_limit', MEMORY_TO_ALLOCATE);
444:
445:
446: $destination_image = imagecreatetruecolor($tn_width, $tn_height);
447:
448:
449: switch ($imageMimetype) {
450: case 'image/gif':
451:
452:
453: $output_function = 'imagepng';
454: $imageMimetype = 'image/png';
455: $do_sharpen = false;
456: $quality = round(10 - ($quality / 10));
457:
458: break;
459: case 'image/png':
460: $output_function = 'imagepng';
461: $do_sharpen = false;
462: $quality = round(10 - ($quality / 10));
463: break;
464: case 'image/jpeg':
465: $output_function = 'imagejpeg';
466: $do_sharpen = true;
467: break;
468: default:
469: exit400BadReq();
470: break;
471: }
472:
473:
474: imagecopyresampled($destination_image, $sourceImage, 0, 0, $offset_x, $offset_y, $tn_width, $tn_height, $imageWidth, $imageHeight);
475:
476:
477: if (in_array($imageMimetype, array('image/gif', 'image/png'))) {
478: if (!$color) {
479:
480: imagealphablending($destination_image, false);
481: imagesavealpha($destination_image, true);
482: $png_transparency = imagecolorallocatealpha($destination_image, 0, 0, 0, 127);
483: imagefill($destination_image, 0, 0, $png_transparency);
484: } else {
485:
486: if ($color[0] === '#') {
487: $color = substr($color, 1);
488: }
489: $background = false;
490: if (strlen($color) == 6) {
491: $background = imagecolorallocate(
492: $destination_image,
493: intval($color[0] . $color[1], 16),
494: intval($color[2] . $color[3], 16),
495: intval($color[4] . $color[5], 16)
496: );
497: } elseif (strlen($color) == 3) {
498: $background = imagecolorallocate(
499: $destination_image,
500: intval($color[0] . $color[0], 16),
501: intval($color[1] . $color[1], 16),
502: intval($color[2] . $color[2], 16)
503: );
504: }
505: if ($background) {
506: imagefill($destination_image, 0, 0, $background);
507: }
508: }
509: } else {
510: if (!$color) {
511: $color = DEFAULT_BACKGROUND_COLOR;
512: }
513:
514: if ($color[0] === '#') {
515: $color = substr($color, 1);
516: }
517: $background = false;
518: if (strlen($color) == 6) {
519: $background = imagecolorallocate(
520: $destination_image,
521: intval($color[0] . $color[1], 16),
522: intval($color[2] . $color[3], 16),
523: intval($color[4] . $color[5], 16)
524: );
525: } elseif (strlen($color) == 3) {
526: $background = imagecolorallocate(
527: $destination_image,
528: intval($color[0] . $color[0], 16),
529: intval($color[1] . $color[1], 16),
530: intval($color[2] . $color[2], 16)
531: );
532: }
533: if ($background) {
534: imagefill($destination_image, 0, 0, $background);
535: }
536: }
537:
538:
539: if (ENABLE_IMAGEFILTER && !empty($filter)) {
540: $filterSet = (array) $filter;
541: foreach ($filterSet as $currentFilter) {
542: $rawFilterArgs = explode(',', $currentFilter);
543: $filterConst = constant(array_shift($rawFilterArgs));
544: if (null !== $filterConst) {
545: $filterArgs = array();
546: $filterArgs[] = $destination_image;
547: $filterArgs[] = $filterConst;
548: foreach ($rawFilterArgs as $tempValue) {
549: $filterArgs[] = trim($tempValue);
550: }
551: call_user_func_array('imagefilter', $filterArgs);
552: }
553: }
554: }
555:
556:
557: if (ENABLE_ROUNDCORNER && !empty($radius)) {
558: $radii = explode(',', $radius);
559: switch (count($radii)) {
560: case 1:
561: $radii[3] = $radii[2] = $radii[1] = $radii[0];
562: break;
563: case 2:
564: $radii[3] = $radii[0];
565: $radii[2] = $radii[1];
566: break;
567: case 3:
568: $radii[3] = $radii[0];
569: break;
570: case 4:
571:
572: break;
573: }
574:
575: $destination_image = imageCreateCorners($destination_image, $radii);
576:
577: if ($imageMimetype === 'image/jpeg') {
578: $output_function = 'imagepng';
579: $imageMimetype = 'image/png';
580: $do_sharpen = false;
581: $quality = round(10 - ($quality / 10));
582: }
583: }
584:
585:
586: if (ENABLE_IMAGEROTATE && !empty($angle)) {
587: $destination_image = imagerotate($destination_image, $angle, $background, 0);
588: }
589:
590: if ($do_sharpen) {
591:
592:
593:
594: $sharpness = findSharp($imageWidth, $tn_width);
595: $sharpen_matrix = array(
596: array(-1, -2, -1),
597: array(-2, $sharpness + 12, -2),
598: array(-1, -2, -1));
599: $divisor = $sharpness;
600: $offset = 0;
601: imageconvolution($destination_image, $sharpen_matrix, $divisor, $offset);
602: }
603:
604:
605: ob_start();
606: $output_function($destination_image, null, $quality);
607: $imageData = ob_get_contents();
608: ob_end_clean();
609:
610: $imageCreatedTime = time();
611:
612:
613: imagedestroy($sourceImage);
614: imagedestroy($destination_image);
615:
616: 617: 618:
619: $cached_image['edited_image_filename'] = $edited_image_filename;
620: $cached_image['image_data'] = $imageData;
621: $cached_image['cached_time'] = $imageCreatedTime;
622: XoopsCache::write($edited_image_filename, $cached_image);
623:
624: 625: 626:
627:
628: $last_modified_string = gmdate('D, d M Y H:i:s', $imageCreatedTime) . ' GMT';
629: $etag = md5($imageData);
630: doConditionalGet($etag, $last_modified_string);
631:
632: header('HTTP/1.1 200 OK');
633:
634: if (!isset($_GET['nocache']) && !isset($_GET['nobrowsercache'])) {
635: header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $imageCreatedTime) . 'GMT');
636: header('Cache-control: max-age=31536000');
637: header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 31536000) . 'GMT');
638: } else {
639:
640: header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
641: header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
642: header('Cache-Control: no-store, no-cache, must-revalidate');
643: header('Cache-Control: post-check=0, pre-check=0', false);
644: header('Pragma: no-cache');
645: }
646: header("Content-type: {$imageMimetype}");
647: header("Content-disposition: filename={$imageFilename}");
648: header('Content-Length: ' . strlen($imageData));
649: echo $imageData;
650: