mosbth /
cimage
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | /** |
||
| 3 | * Resize and crop images on the fly, store generated images in a cache. |
||
| 4 | * |
||
| 5 | * @author Mikael Roos [email protected] |
||
| 6 | * @example http://dbwebb.se/opensource/cimage |
||
| 7 | * @link https://github.com/mosbth/cimage |
||
| 8 | * |
||
| 9 | */ |
||
| 10 | |||
| 11 | $version = "v0.7.12 (2016-06-01)"; |
||
| 12 | |||
| 13 | // For CRemoteImage |
||
| 14 | define("CIMAGE_USER_AGENT", "CImage/$version"); |
||
| 15 | |||
| 16 | |||
| 17 | // Include debug functions |
||
| 18 | function debug($msg) |
||
|
0 ignored issues
–
show
|
|||
| 19 | { |
||
| 20 | $file = "/tmp/cimage"; |
||
| 21 | $msg .= ":" . count(get_included_files()); |
||
| 22 | $msg .= ":" . round(memory_get_peak_usage()/1024/1024, 3) . "MB"; |
||
| 23 | $msg .= ":" . (string) round((microtime(true) - $_SERVER['REQUEST_TIME_FLOAT']), 6) . "ms"; |
||
| 24 | file_put_contents($file, "$msg\n", FILE_APPEND); |
||
| 25 | |||
| 26 | } |
||
| 27 | |||
| 28 | |||
| 29 | /** |
||
| 30 | * Display error message. |
||
| 31 | * |
||
| 32 | * @param string $msg to display. |
||
| 33 | * @param int $type of HTTP error to display. |
||
| 34 | * |
||
| 35 | * @return void |
||
| 36 | */ |
||
| 37 | function errorPage($msg, $type = 500) |
||
| 38 | { |
||
| 39 | global $mode; |
||
| 40 | |||
| 41 | switch ($type) { |
||
| 42 | case 403: |
||
| 43 | $header = "403 Forbidden"; |
||
| 44 | break; |
||
| 45 | case 404: |
||
| 46 | $header = "404 Not Found"; |
||
| 47 | break; |
||
| 48 | default: |
||
| 49 | $header = "500 Internal Server Error"; |
||
| 50 | } |
||
| 51 | |||
| 52 | if ($mode == "strict") { |
||
| 53 | $header = "404 Not Found"; |
||
| 54 | } |
||
| 55 | |||
| 56 | header("HTTP/1.0 $header"); |
||
| 57 | |||
| 58 | if ($mode == "development") { |
||
| 59 | die("[img.php] $msg"); |
||
| 60 | } |
||
| 61 | |||
| 62 | error_log("[img.php] $msg"); |
||
| 63 | die("HTTP/1.0 $header"); |
||
| 64 | } |
||
| 65 | |||
| 66 | |||
| 67 | |||
| 68 | /** |
||
| 69 | * Custom exception handler. |
||
| 70 | */ |
||
| 71 | set_exception_handler(function ($exception) { |
||
| 72 | errorPage( |
||
| 73 | "<p><b>img.php: Uncaught exception:</b> <p>" |
||
| 74 | . $exception->getMessage() |
||
| 75 | . "</p><pre>" |
||
| 76 | . $exception->getTraceAsString() |
||
| 77 | . "</pre>", |
||
| 78 | 500 |
||
| 79 | ); |
||
| 80 | }); |
||
| 81 | |||
| 82 | |||
| 83 | |||
| 84 | /** |
||
| 85 | * Get input from query string or return default value if not set. |
||
| 86 | * |
||
| 87 | * @param mixed $key as string or array of string values to look for in $_GET. |
||
| 88 | * @param mixed $default value to return when $key is not set in $_GET. |
||
| 89 | * |
||
| 90 | * @return mixed value from $_GET or default value. |
||
| 91 | */ |
||
| 92 | function get($key, $default = null) |
||
| 93 | { |
||
| 94 | if (is_array($key)) { |
||
| 95 | foreach ($key as $val) { |
||
| 96 | if (isset($_GET[$val])) { |
||
| 97 | return $_GET[$val]; |
||
| 98 | } |
||
| 99 | } |
||
| 100 | } elseif (isset($_GET[$key])) { |
||
| 101 | return $_GET[$key]; |
||
| 102 | } |
||
| 103 | return $default; |
||
| 104 | } |
||
| 105 | |||
| 106 | |||
| 107 | |||
| 108 | /** |
||
| 109 | * Get input from query string and set to $defined if defined or else $undefined. |
||
| 110 | * |
||
| 111 | * @param mixed $key as string or array of string values to look for in $_GET. |
||
| 112 | * @param mixed $defined value to return when $key is set in $_GET. |
||
| 113 | * @param mixed $undefined value to return when $key is not set in $_GET. |
||
| 114 | * |
||
| 115 | * @return mixed value as $defined or $undefined. |
||
| 116 | */ |
||
| 117 | function getDefined($key, $defined, $undefined) |
||
| 118 | { |
||
| 119 | return get($key) === null ? $undefined : $defined; |
||
| 120 | } |
||
| 121 | |||
| 122 | |||
| 123 | |||
| 124 | /** |
||
| 125 | * Get value from config array or default if key is not set in config array. |
||
| 126 | * |
||
| 127 | * @param string $key the key in the config array. |
||
| 128 | * @param mixed $default value to be default if $key is not set in config. |
||
| 129 | * |
||
| 130 | * @return mixed value as $config[$key] or $default. |
||
| 131 | */ |
||
| 132 | function getConfig($key, $default) |
||
| 133 | { |
||
| 134 | global $config; |
||
| 135 | return isset($config[$key]) |
||
| 136 | ? $config[$key] |
||
| 137 | : $default; |
||
| 138 | } |
||
| 139 | |||
| 140 | |||
| 141 | |||
| 142 | /** |
||
| 143 | * Log when verbose mode, when used without argument it returns the result. |
||
| 144 | * |
||
| 145 | * @param string $msg to log. |
||
| 146 | * |
||
| 147 | * @return void or array. |
||
| 148 | */ |
||
| 149 | function verbose($msg = null) |
||
| 150 | { |
||
| 151 | global $verbose, $verboseFile; |
||
| 152 | static $log = array(); |
||
| 153 | |||
| 154 | if (!($verbose || $verboseFile)) { |
||
| 155 | return; |
||
| 156 | } |
||
| 157 | |||
| 158 | if (is_null($msg)) { |
||
| 159 | return $log; |
||
| 160 | } |
||
| 161 | |||
| 162 | $log[] = $msg; |
||
| 163 | } |
||
| 164 | |||
| 165 | |||
| 166 | |||
| 167 | /** |
||
| 168 | * Get configuration options from file, if the file exists, else use $config |
||
| 169 | * if its defined or create an empty $config. |
||
| 170 | */ |
||
| 171 | $configFile = __DIR__.'/'.basename(__FILE__, '.php').'_config.php'; |
||
| 172 | |||
| 173 | if (is_file($configFile)) { |
||
| 174 | $config = require $configFile; |
||
| 175 | } elseif (!isset($config)) { |
||
| 176 | $config = array(); |
||
| 177 | } |
||
| 178 | |||
| 179 | |||
| 180 | |||
| 181 | /** |
||
| 182 | * verbose, v - do a verbose dump of what happens |
||
| 183 | * vf - do verbose dump to file |
||
| 184 | */ |
||
| 185 | $verbose = getDefined(array('verbose', 'v'), true, false); |
||
| 186 | $verboseFile = getDefined('vf', true, false); |
||
| 187 | verbose("img.php version = $version"); |
||
| 188 | |||
| 189 | |||
| 190 | |||
| 191 | /** |
||
| 192 | * status - do a verbose dump of the configuration |
||
| 193 | */ |
||
| 194 | $status = getDefined('status', true, false); |
||
| 195 | |||
| 196 | |||
| 197 | |||
| 198 | /** |
||
| 199 | * Set mode as strict, production or development. |
||
| 200 | * Default is production environment. |
||
| 201 | */ |
||
| 202 | $mode = getConfig('mode', 'production'); |
||
| 203 | |||
| 204 | // Settings for any mode |
||
| 205 | set_time_limit(20); |
||
| 206 | ini_set('gd.jpeg_ignore_warning', 1); |
||
| 207 | |||
| 208 | if (!extension_loaded('gd')) { |
||
| 209 | errorPage("Extension gd is not loaded.", 500); |
||
| 210 | } |
||
| 211 | |||
| 212 | // Specific settings for each mode |
||
| 213 | if ($mode == 'strict') { |
||
| 214 | |||
| 215 | error_reporting(0); |
||
| 216 | ini_set('display_errors', 0); |
||
| 217 | ini_set('log_errors', 1); |
||
| 218 | $verbose = false; |
||
| 219 | $status = false; |
||
| 220 | $verboseFile = false; |
||
| 221 | |||
| 222 | } elseif ($mode == 'production') { |
||
| 223 | |||
| 224 | error_reporting(-1); |
||
| 225 | ini_set('display_errors', 0); |
||
| 226 | ini_set('log_errors', 1); |
||
| 227 | $verbose = false; |
||
| 228 | $status = false; |
||
| 229 | $verboseFile = false; |
||
| 230 | |||
| 231 | } elseif ($mode == 'development') { |
||
| 232 | |||
| 233 | error_reporting(-1); |
||
| 234 | ini_set('display_errors', 1); |
||
| 235 | ini_set('log_errors', 0); |
||
| 236 | $verboseFile = false; |
||
| 237 | |||
| 238 | } elseif ($mode == 'test') { |
||
| 239 | |||
| 240 | error_reporting(-1); |
||
| 241 | ini_set('display_errors', 1); |
||
| 242 | ini_set('log_errors', 0); |
||
| 243 | |||
| 244 | } else { |
||
| 245 | errorPage("Unknown mode: $mode", 500); |
||
| 246 | } |
||
| 247 | |||
| 248 | verbose("mode = $mode"); |
||
| 249 | verbose("error log = " . ini_get('error_log')); |
||
| 250 | |||
| 251 | |||
| 252 | |||
| 253 | /** |
||
| 254 | * Set default timezone if not set or if its set in the config-file. |
||
| 255 | */ |
||
| 256 | $defaultTimezone = getConfig('default_timezone', null); |
||
| 257 | |||
| 258 | if ($defaultTimezone) { |
||
| 259 | date_default_timezone_set($defaultTimezone); |
||
| 260 | } elseif (!ini_get('default_timezone')) { |
||
| 261 | date_default_timezone_set('UTC'); |
||
| 262 | } |
||
| 263 | |||
| 264 | |||
| 265 | |||
| 266 | /** |
||
| 267 | * Check if passwords are configured, used and match. |
||
| 268 | * Options decide themself if they require passwords to be used. |
||
| 269 | */ |
||
| 270 | $pwdConfig = getConfig('password', false); |
||
| 271 | $pwdAlways = getConfig('password_always', false); |
||
| 272 | $pwdType = getConfig('password_type', 'text'); |
||
| 273 | $pwd = get(array('password', 'pwd'), null); |
||
| 274 | |||
| 275 | // Check if passwords match, if configured to use passwords |
||
| 276 | $passwordMatch = null; |
||
| 277 | if ($pwd) { |
||
| 278 | switch ($pwdType) { |
||
| 279 | case 'md5': |
||
| 280 | $passwordMatch = ($pwdConfig === md5($pwd)); |
||
| 281 | break; |
||
| 282 | case 'hash': |
||
| 283 | $passwordMatch = password_verify($pwd, $pwdConfig); |
||
| 284 | break; |
||
| 285 | case 'text': |
||
| 286 | $passwordMatch = ($pwdConfig === $pwd); |
||
| 287 | break; |
||
| 288 | default: |
||
| 289 | $passwordMatch = false; |
||
| 290 | } |
||
| 291 | } |
||
| 292 | |||
| 293 | if ($pwdAlways && $passwordMatch !== true) { |
||
| 294 | errorPage("Password required and does not match or exists.", 403); |
||
| 295 | } |
||
| 296 | |||
| 297 | verbose("password match = $passwordMatch"); |
||
| 298 | |||
| 299 | |||
| 300 | |||
| 301 | /** |
||
| 302 | * Prevent hotlinking, leeching, of images by controlling who access them |
||
| 303 | * from where. |
||
| 304 | * |
||
| 305 | */ |
||
| 306 | $allowHotlinking = getConfig('allow_hotlinking', true); |
||
| 307 | $hotlinkingWhitelist = getConfig('hotlinking_whitelist', array()); |
||
| 308 | |||
| 309 | $serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null; |
||
| 310 | $referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null; |
||
| 311 | $refererHost = parse_url($referer, PHP_URL_HOST); |
||
| 312 | |||
| 313 | if (!$allowHotlinking) { |
||
| 314 | if ($passwordMatch) { |
||
| 315 | ; // Always allow when password match |
||
| 316 | verbose("Hotlinking since passwordmatch"); |
||
| 317 | } elseif ($passwordMatch === false) { |
||
| 318 | errorPage("Hotlinking/leeching not allowed when password missmatch.", 403); |
||
| 319 | } elseif (!$referer) { |
||
| 320 | errorPage("Hotlinking/leeching not allowed and referer is missing.", 403); |
||
| 321 | } elseif (strcmp($serverName, $refererHost) == 0) { |
||
| 322 | ; // Allow when serverName matches refererHost |
||
| 323 | verbose("Hotlinking disallowed but serverName matches refererHost."); |
||
| 324 | } elseif (!empty($hotlinkingWhitelist)) { |
||
| 325 | $whitelist = new CWhitelist(); |
||
| 326 | $allowedByWhitelist = $whitelist->check($refererHost, $hotlinkingWhitelist); |
||
| 327 | |||
| 328 | if ($allowedByWhitelist) { |
||
| 329 | verbose("Hotlinking/leeching allowed by whitelist."); |
||
| 330 | } else { |
||
| 331 | errorPage("Hotlinking/leeching not allowed by whitelist. Referer: $referer.", 403); |
||
| 332 | } |
||
| 333 | |||
| 334 | } else { |
||
| 335 | errorPage("Hotlinking/leeching not allowed.", 403); |
||
| 336 | } |
||
| 337 | } |
||
| 338 | |||
| 339 | verbose("allow_hotlinking = $allowHotlinking"); |
||
| 340 | verbose("referer = $referer"); |
||
| 341 | verbose("referer host = $refererHost"); |
||
| 342 | |||
| 343 | |||
| 344 | |||
| 345 | /** |
||
| 346 | * Get the source files. |
||
| 347 | */ |
||
| 348 | $autoloader = getConfig('autoloader', false); |
||
| 349 | $cimageClass = getConfig('cimage_class', false); |
||
| 350 | |||
| 351 | if ($autoloader) { |
||
| 352 | require $autoloader; |
||
| 353 | } elseif ($cimageClass) { |
||
| 354 | require $cimageClass; |
||
| 355 | } |
||
| 356 | |||
| 357 | |||
| 358 | |||
| 359 | /** |
||
| 360 | * Create the class for the image. |
||
| 361 | */ |
||
| 362 | $CImage = getConfig('CImage', 'CImage'); |
||
| 363 | $img = new $CImage(); |
||
| 364 | $img->setVerbose($verbose || $verboseFile); |
||
| 365 | |||
| 366 | |||
| 367 | |||
| 368 | /** |
||
| 369 | * Get the cachepath from config. |
||
| 370 | */ |
||
| 371 | $CCache = getConfig('CCache', 'CCache'); |
||
| 372 | $cachePath = getConfig('cache_path', __DIR__ . '/../cache/'); |
||
| 373 | $cache = new $CCache(); |
||
| 374 | $cache->setDir($cachePath); |
||
| 375 | |||
| 376 | |||
| 377 | |||
| 378 | /** |
||
| 379 | * no-cache, nc - skip the cached version and process and create a new version in cache. |
||
| 380 | */ |
||
| 381 | $useCache = getDefined(array('no-cache', 'nc'), false, true); |
||
| 382 | |||
| 383 | verbose("use cache = $useCache"); |
||
| 384 | |||
| 385 | |||
| 386 | |||
| 387 | /** |
||
| 388 | * Prepare fast track cache for swriting cache items. |
||
| 389 | */ |
||
| 390 | $fastTrackCache = "fasttrack"; |
||
| 391 | $allowFastTrackCache = getConfig('fast_track_allow', false); |
||
| 392 | |||
| 393 | $CFastTrackCache = getConfig('CFastTrackCache', 'CFastTrackCache'); |
||
| 394 | $ftc = new $CFastTrackCache(); |
||
| 395 | $ftc->setCacheDir($cache->getPathToSubdir($fastTrackCache)) |
||
| 396 | ->enable($allowFastTrackCache) |
||
| 397 | ->setFilename(array('no-cache', 'nc')); |
||
| 398 | $img->injectDependency("fastTrackCache", $ftc); |
||
| 399 | |||
| 400 | |||
| 401 | |||
| 402 | /** |
||
| 403 | * Load and output images from fast track cache, if items are available |
||
| 404 | * in cache. |
||
| 405 | */ |
||
| 406 | if ($useCache && $allowFastTrackCache) { |
||
| 407 | $ftc->output(); |
||
| 408 | } |
||
| 409 | |||
| 410 | |||
| 411 | |||
| 412 | /** |
||
| 413 | * Allow or disallow remote download of images from other servers. |
||
| 414 | * Passwords apply if used. |
||
| 415 | * |
||
| 416 | */ |
||
| 417 | $allowRemote = getConfig('remote_allow', false); |
||
| 418 | |||
| 419 | if ($allowRemote && $passwordMatch !== false) { |
||
| 420 | $cacheRemote = $cache->getPathToSubdir("remote"); |
||
| 421 | |||
| 422 | $pattern = getConfig('remote_pattern', null); |
||
| 423 | $img->setRemoteDownload($allowRemote, $cacheRemote, $pattern); |
||
| 424 | |||
| 425 | $whitelist = getConfig('remote_whitelist', null); |
||
| 426 | $img->setRemoteHostWhitelist($whitelist); |
||
| 427 | } |
||
| 428 | |||
| 429 | |||
| 430 | |||
| 431 | /** |
||
| 432 | * shortcut, sc - extend arguments with a constant value, defined |
||
| 433 | * in config-file. |
||
| 434 | */ |
||
| 435 | $shortcut = get(array('shortcut', 'sc'), null); |
||
| 436 | $shortcutConfig = getConfig('shortcut', array( |
||
| 437 | 'sepia' => "&f=grayscale&f0=brightness,-10&f1=contrast,-20&f2=colorize,120,60,0,0&sharpen", |
||
| 438 | )); |
||
| 439 | |||
| 440 | verbose("shortcut = $shortcut"); |
||
| 441 | |||
| 442 | if (isset($shortcut) |
||
| 443 | && isset($shortcutConfig[$shortcut])) { |
||
| 444 | |||
| 445 | parse_str($shortcutConfig[$shortcut], $get); |
||
| 446 | verbose("shortcut-constant = {$shortcutConfig[$shortcut]}"); |
||
| 447 | $_GET = array_merge($_GET, $get); |
||
| 448 | } |
||
| 449 | |||
| 450 | |||
| 451 | |||
| 452 | /** |
||
| 453 | * src - the source image file. |
||
| 454 | */ |
||
| 455 | $srcImage = urldecode(get('src')) |
||
| 456 | or errorPage('Must set src-attribute.', 404); |
||
| 457 | |||
| 458 | // Get settings for src-alt as backup image |
||
| 459 | $srcAltImage = urldecode(get('src-alt', null)); |
||
| 460 | $srcAltConfig = getConfig('src_alt', null); |
||
| 461 | if (empty($srcAltImage)) { |
||
| 462 | $srcAltImage = $srcAltConfig; |
||
| 463 | } |
||
| 464 | |||
| 465 | // Check for valid/invalid characters |
||
| 466 | $imagePath = getConfig('image_path', __DIR__ . '/img/'); |
||
| 467 | $imagePathConstraint = getConfig('image_path_constraint', true); |
||
| 468 | $validFilename = getConfig('valid_filename', '#^[a-z0-9A-Z-/_ \.:]+$#'); |
||
| 469 | |||
| 470 | // Source is remote |
||
| 471 | $remoteSource = false; |
||
| 472 | |||
| 473 | // Dummy image feature |
||
| 474 | $dummyEnabled = getConfig('dummy_enabled', true); |
||
| 475 | $dummyFilename = getConfig('dummy_filename', 'dummy'); |
||
| 476 | $dummyImage = false; |
||
| 477 | |||
| 478 | preg_match($validFilename, $srcImage) |
||
| 479 | or errorPage('Source filename contains invalid characters.', 404); |
||
| 480 | |||
| 481 | if ($dummyEnabled && $srcImage === $dummyFilename) { |
||
| 482 | |||
| 483 | // Prepare to create a dummy image and use it as the source image. |
||
| 484 | $dummyImage = true; |
||
| 485 | |||
| 486 | } elseif ($allowRemote && $img->isRemoteSource($srcImage)) { |
||
| 487 | |||
| 488 | // If source is a remote file, ignore local file checks. |
||
| 489 | $remoteSource = true; |
||
| 490 | |||
| 491 | } else { |
||
| 492 | |||
| 493 | // Check if file exists on disk or try using src-alt |
||
| 494 | $pathToImage = realpath($imagePath . $srcImage); |
||
| 495 | |||
| 496 | if (!is_file($pathToImage) && !empty($srcAltImage)) { |
||
| 497 | // Try using the src-alt instead |
||
| 498 | $srcImage = $srcAltImage; |
||
| 499 | $pathToImage = realpath($imagePath . $srcImage); |
||
| 500 | |||
| 501 | preg_match($validFilename, $srcImage) |
||
| 502 | or errorPage('Source (alt) filename contains invalid characters.', 404); |
||
| 503 | |||
| 504 | if ($dummyEnabled && $srcImage === $dummyFilename) { |
||
| 505 | // Check if src-alt is the dummy image |
||
| 506 | $dummyImage = true; |
||
| 507 | } |
||
| 508 | } |
||
| 509 | |||
| 510 | if (!$dummyImage) { |
||
| 511 | is_file($pathToImage) |
||
| 512 | or errorPage( |
||
| 513 | 'Source image is not a valid file, check the filename and that a |
||
| 514 | matching file exists on the filesystem.', |
||
| 515 | 404 |
||
| 516 | ); |
||
| 517 | } |
||
| 518 | } |
||
| 519 | |||
| 520 | if ($imagePathConstraint && !$dummyImage && !$remoteSource) { |
||
| 521 | // Check that the image is a file below the directory 'image_path'. |
||
| 522 | $imageDir = realpath($imagePath); |
||
| 523 | |||
| 524 | substr_compare($imageDir, $pathToImage, 0, strlen($imageDir)) == 0 |
||
| 525 | or errorPage( |
||
| 526 | 'Security constraint: Source image is not below the directory "image_path" |
||
| 527 | as specified in the config file img_config.php.', |
||
| 528 | 404 |
||
| 529 | ); |
||
| 530 | } |
||
| 531 | |||
| 532 | verbose("src = $srcImage"); |
||
| 533 | |||
| 534 | |||
| 535 | |||
| 536 | /** |
||
| 537 | * Manage size constants from config file, use constants to replace values |
||
| 538 | * for width and height. |
||
| 539 | */ |
||
| 540 | $sizeConstant = getConfig('size_constant', function () { |
||
| 541 | |||
| 542 | // Set sizes to map constant to value, easier to use with width or height |
||
| 543 | $sizes = array( |
||
| 544 | 'w1' => 613, |
||
| 545 | 'w2' => 630, |
||
| 546 | ); |
||
| 547 | |||
| 548 | // Add grid column width, useful for use as predefined size for width (or height). |
||
| 549 | $gridColumnWidth = 30; |
||
| 550 | $gridGutterWidth = 10; |
||
| 551 | $gridColumns = 24; |
||
| 552 | |||
| 553 | for ($i = 1; $i <= $gridColumns; $i++) { |
||
| 554 | $sizes['c' . $i] = ($gridColumnWidth + $gridGutterWidth) * $i - $gridGutterWidth; |
||
| 555 | } |
||
| 556 | |||
| 557 | return $sizes; |
||
| 558 | }); |
||
| 559 | |||
| 560 | $sizes = call_user_func($sizeConstant); |
||
| 561 | |||
| 562 | |||
| 563 | |||
| 564 | /** |
||
| 565 | * width, w - set target width, affecting the resulting image width, height and resize options |
||
| 566 | */ |
||
| 567 | $newWidth = get(array('width', 'w')); |
||
| 568 | $maxWidth = getConfig('max_width', 2000); |
||
| 569 | |||
| 570 | // Check to replace predefined size |
||
| 571 | if (isset($sizes[$newWidth])) { |
||
| 572 | $newWidth = $sizes[$newWidth]; |
||
| 573 | } |
||
| 574 | |||
| 575 | // Support width as % of original width |
||
| 576 | if ($newWidth[strlen($newWidth)-1] == '%') { |
||
| 577 | is_numeric(substr($newWidth, 0, -1)) |
||
| 578 | or errorPage('Width % not numeric.', 404); |
||
| 579 | } else { |
||
| 580 | is_null($newWidth) |
||
| 581 | or ($newWidth > 10 && $newWidth <= $maxWidth) |
||
| 582 | or errorPage('Width out of range.', 404); |
||
| 583 | } |
||
| 584 | |||
| 585 | verbose("new width = $newWidth"); |
||
| 586 | |||
| 587 | |||
| 588 | |||
| 589 | /** |
||
| 590 | * height, h - set target height, affecting the resulting image width, height and resize options |
||
| 591 | */ |
||
| 592 | $newHeight = get(array('height', 'h')); |
||
| 593 | $maxHeight = getConfig('max_height', 2000); |
||
| 594 | |||
| 595 | // Check to replace predefined size |
||
| 596 | if (isset($sizes[$newHeight])) { |
||
| 597 | $newHeight = $sizes[$newHeight]; |
||
| 598 | } |
||
| 599 | |||
| 600 | // height |
||
| 601 | if ($newHeight[strlen($newHeight)-1] == '%') { |
||
| 602 | is_numeric(substr($newHeight, 0, -1)) |
||
| 603 | or errorPage('Height % out of range.', 404); |
||
| 604 | } else { |
||
| 605 | is_null($newHeight) |
||
| 606 | or ($newHeight > 10 && $newHeight <= $maxHeight) |
||
| 607 | or errorPage('Height out of range.', 404); |
||
| 608 | } |
||
| 609 | |||
| 610 | verbose("new height = $newHeight"); |
||
| 611 | |||
| 612 | |||
| 613 | |||
| 614 | /** |
||
| 615 | * aspect-ratio, ar - affecting the resulting image width, height and resize options |
||
| 616 | */ |
||
| 617 | $aspectRatio = get(array('aspect-ratio', 'ar')); |
||
| 618 | $aspectRatioConstant = getConfig('aspect_ratio_constant', function () { |
||
| 619 | return array( |
||
| 620 | '3:1' => 3/1, |
||
| 621 | '3:2' => 3/2, |
||
| 622 | '4:3' => 4/3, |
||
| 623 | '8:5' => 8/5, |
||
| 624 | '16:10' => 16/10, |
||
| 625 | '16:9' => 16/9, |
||
| 626 | 'golden' => 1.618, |
||
| 627 | ); |
||
| 628 | }); |
||
| 629 | |||
| 630 | // Check to replace predefined aspect ratio |
||
| 631 | $aspectRatios = call_user_func($aspectRatioConstant); |
||
| 632 | $negateAspectRatio = ($aspectRatio[0] == '!') ? true : false; |
||
| 633 | $aspectRatio = $negateAspectRatio ? substr($aspectRatio, 1) : $aspectRatio; |
||
| 634 | |||
| 635 | if (isset($aspectRatios[$aspectRatio])) { |
||
| 636 | $aspectRatio = $aspectRatios[$aspectRatio]; |
||
| 637 | } |
||
| 638 | |||
| 639 | if ($negateAspectRatio) { |
||
| 640 | $aspectRatio = 1 / $aspectRatio; |
||
| 641 | } |
||
| 642 | |||
| 643 | is_null($aspectRatio) |
||
| 644 | or is_numeric($aspectRatio) |
||
| 645 | or errorPage('Aspect ratio out of range', 404); |
||
| 646 | |||
| 647 | verbose("aspect ratio = $aspectRatio"); |
||
| 648 | |||
| 649 | |||
| 650 | |||
| 651 | /** |
||
| 652 | * crop-to-fit, cf - affecting the resulting image width, height and resize options |
||
| 653 | */ |
||
| 654 | $cropToFit = getDefined(array('crop-to-fit', 'cf'), true, false); |
||
| 655 | |||
| 656 | verbose("crop to fit = $cropToFit"); |
||
| 657 | |||
| 658 | |||
| 659 | |||
| 660 | /** |
||
| 661 | * Set default background color from config file. |
||
| 662 | */ |
||
| 663 | $backgroundColor = getConfig('background_color', null); |
||
| 664 | |||
| 665 | if ($backgroundColor) { |
||
| 666 | $img->setDefaultBackgroundColor($backgroundColor); |
||
| 667 | verbose("Using default background_color = $backgroundColor"); |
||
| 668 | } |
||
| 669 | |||
| 670 | |||
| 671 | |||
| 672 | /** |
||
| 673 | * bgColor - Default background color to use |
||
| 674 | */ |
||
| 675 | $bgColor = get(array('bgColor', 'bg-color', 'bgc'), null); |
||
| 676 | |||
| 677 | verbose("bgColor = $bgColor"); |
||
| 678 | |||
| 679 | |||
| 680 | |||
| 681 | /** |
||
| 682 | * Do or do not resample image when resizing. |
||
| 683 | */ |
||
| 684 | $resizeStrategy = getDefined(array('no-resample'), true, false); |
||
| 685 | |||
| 686 | if ($resizeStrategy) { |
||
| 687 | $img->setCopyResizeStrategy($img::RESIZE); |
||
| 688 | verbose("Setting = Resize instead of resample"); |
||
| 689 | } |
||
| 690 | |||
| 691 | |||
| 692 | |||
| 693 | |||
| 694 | /** |
||
| 695 | * fill-to-fit, ff - affecting the resulting image width, height and resize options |
||
| 696 | */ |
||
| 697 | $fillToFit = get(array('fill-to-fit', 'ff'), null); |
||
| 698 | |||
| 699 | verbose("fill-to-fit = $fillToFit"); |
||
| 700 | |||
| 701 | if ($fillToFit !== null) { |
||
| 702 | |||
| 703 | if (!empty($fillToFit)) { |
||
| 704 | $bgColor = $fillToFit; |
||
| 705 | verbose("fillToFit changed bgColor to = $bgColor"); |
||
| 706 | } |
||
| 707 | |||
| 708 | $fillToFit = true; |
||
| 709 | verbose("fill-to-fit (fixed) = $fillToFit"); |
||
| 710 | } |
||
| 711 | |||
| 712 | |||
| 713 | |||
| 714 | /** |
||
| 715 | * no-ratio, nr, stretch - affecting the resulting image width, height and resize options |
||
| 716 | */ |
||
| 717 | $keepRatio = getDefined(array('no-ratio', 'nr', 'stretch'), false, true); |
||
| 718 | |||
| 719 | verbose("keep ratio = $keepRatio"); |
||
| 720 | |||
| 721 | |||
| 722 | |||
| 723 | /** |
||
| 724 | * crop, c - affecting the resulting image width, height and resize options |
||
| 725 | */ |
||
| 726 | $crop = get(array('crop', 'c')); |
||
| 727 | |||
| 728 | verbose("crop = $crop"); |
||
| 729 | |||
| 730 | |||
| 731 | |||
| 732 | /** |
||
| 733 | * area, a - affecting the resulting image width, height and resize options |
||
| 734 | */ |
||
| 735 | $area = get(array('area', 'a')); |
||
| 736 | |||
| 737 | verbose("area = $area"); |
||
| 738 | |||
| 739 | |||
| 740 | |||
| 741 | /** |
||
| 742 | * skip-original, so - skip the original image and always process a new image |
||
| 743 | */ |
||
| 744 | $useOriginal = getDefined(array('skip-original', 'so'), false, true); |
||
| 745 | $useOriginalDefault = getConfig('skip_original', false); |
||
| 746 | |||
| 747 | if ($useOriginalDefault === true) { |
||
| 748 | verbose("skip original is default ON"); |
||
| 749 | $useOriginal = false; |
||
| 750 | } |
||
| 751 | |||
| 752 | verbose("use original = $useOriginal"); |
||
| 753 | |||
| 754 | |||
| 755 | |||
| 756 | /** |
||
| 757 | * quality, q - set level of quality for jpeg images |
||
| 758 | */ |
||
| 759 | $quality = get(array('quality', 'q')); |
||
| 760 | $qualityDefault = getConfig('jpg_quality', null); |
||
| 761 | |||
| 762 | is_null($quality) |
||
| 763 | or ($quality > 0 and $quality <= 100) |
||
| 764 | or errorPage('Quality out of range', 404); |
||
| 765 | |||
| 766 | if (is_null($quality) && !is_null($qualityDefault)) { |
||
| 767 | $quality = $qualityDefault; |
||
| 768 | } |
||
| 769 | |||
| 770 | verbose("quality = $quality"); |
||
| 771 | |||
| 772 | |||
| 773 | |||
| 774 | /** |
||
| 775 | * compress, co - what strategy to use when compressing png images |
||
| 776 | */ |
||
| 777 | $compress = get(array('compress', 'co')); |
||
| 778 | $compressDefault = getConfig('png_compression', null); |
||
| 779 | |||
| 780 | is_null($compress) |
||
| 781 | or ($compress > 0 and $compress <= 9) |
||
| 782 | or errorPage('Compress out of range', 404); |
||
| 783 | |||
| 784 | if (is_null($compress) && !is_null($compressDefault)) { |
||
| 785 | $compress = $compressDefault; |
||
| 786 | } |
||
| 787 | |||
| 788 | verbose("compress = $compress"); |
||
| 789 | |||
| 790 | |||
| 791 | |||
| 792 | /** |
||
| 793 | * save-as, sa - what type of image to save |
||
| 794 | */ |
||
| 795 | $saveAs = get(array('save-as', 'sa')); |
||
| 796 | |||
| 797 | verbose("save as = $saveAs"); |
||
| 798 | |||
| 799 | |||
| 800 | |||
| 801 | /** |
||
| 802 | * scale, s - Processing option, scale up or down the image prior actual resize |
||
| 803 | */ |
||
| 804 | $scale = get(array('scale', 's')); |
||
| 805 | |||
| 806 | is_null($scale) |
||
| 807 | or ($scale >= 0 and $scale <= 400) |
||
| 808 | or errorPage('Scale out of range', 404); |
||
| 809 | |||
| 810 | verbose("scale = $scale"); |
||
| 811 | |||
| 812 | |||
| 813 | |||
| 814 | /** |
||
| 815 | * palette, p - Processing option, create a palette version of the image |
||
| 816 | */ |
||
| 817 | $palette = getDefined(array('palette', 'p'), true, false); |
||
| 818 | |||
| 819 | verbose("palette = $palette"); |
||
| 820 | |||
| 821 | |||
| 822 | |||
| 823 | /** |
||
| 824 | * sharpen - Processing option, post filter for sharpen effect |
||
| 825 | */ |
||
| 826 | $sharpen = getDefined('sharpen', true, null); |
||
| 827 | |||
| 828 | verbose("sharpen = $sharpen"); |
||
| 829 | |||
| 830 | |||
| 831 | |||
| 832 | /** |
||
| 833 | * emboss - Processing option, post filter for emboss effect |
||
| 834 | */ |
||
| 835 | $emboss = getDefined('emboss', true, null); |
||
| 836 | |||
| 837 | verbose("emboss = $emboss"); |
||
| 838 | |||
| 839 | |||
| 840 | |||
| 841 | /** |
||
| 842 | * blur - Processing option, post filter for blur effect |
||
| 843 | */ |
||
| 844 | $blur = getDefined('blur', true, null); |
||
| 845 | |||
| 846 | verbose("blur = $blur"); |
||
| 847 | |||
| 848 | |||
| 849 | |||
| 850 | /** |
||
| 851 | * rotateBefore - Rotate the image with an angle, before processing |
||
| 852 | */ |
||
| 853 | $rotateBefore = get(array('rotateBefore', 'rotate-before', 'rb')); |
||
| 854 | |||
| 855 | is_null($rotateBefore) |
||
| 856 | or ($rotateBefore >= -360 and $rotateBefore <= 360) |
||
| 857 | or errorPage('RotateBefore out of range', 404); |
||
| 858 | |||
| 859 | verbose("rotateBefore = $rotateBefore"); |
||
| 860 | |||
| 861 | |||
| 862 | |||
| 863 | /** |
||
| 864 | * rotateAfter - Rotate the image with an angle, before processing |
||
| 865 | */ |
||
| 866 | $rotateAfter = get(array('rotateAfter', 'rotate-after', 'ra', 'rotate', 'r')); |
||
| 867 | |||
| 868 | is_null($rotateAfter) |
||
| 869 | or ($rotateAfter >= -360 and $rotateAfter <= 360) |
||
| 870 | or errorPage('RotateBefore out of range', 404); |
||
| 871 | |||
| 872 | verbose("rotateAfter = $rotateAfter"); |
||
| 873 | |||
| 874 | |||
| 875 | |||
| 876 | /** |
||
| 877 | * autoRotate - Auto rotate based on EXIF information |
||
| 878 | */ |
||
| 879 | $autoRotate = getDefined(array('autoRotate', 'auto-rotate', 'aro'), true, false); |
||
| 880 | |||
| 881 | verbose("autoRotate = $autoRotate"); |
||
| 882 | |||
| 883 | |||
| 884 | |||
| 885 | /** |
||
| 886 | * filter, f, f0-f9 - Processing option, post filter for various effects using imagefilter() |
||
| 887 | */ |
||
| 888 | $filters = array(); |
||
| 889 | $filter = get(array('filter', 'f')); |
||
| 890 | if ($filter) { |
||
| 891 | $filters[] = $filter; |
||
| 892 | } |
||
| 893 | |||
| 894 | for ($i = 0; $i < 10; $i++) { |
||
| 895 | $filter = get(array("filter{$i}", "f{$i}")); |
||
| 896 | if ($filter) { |
||
| 897 | $filters[] = $filter; |
||
| 898 | } |
||
| 899 | } |
||
| 900 | |||
| 901 | verbose("filters = " . print_r($filters, 1)); |
||
| 902 | |||
| 903 | |||
| 904 | |||
| 905 | /** |
||
| 906 | * json - output the image as a JSON object with details on the image. |
||
| 907 | * ascii - output the image as ASCII art. |
||
| 908 | */ |
||
| 909 | $outputFormat = getDefined('json', 'json', null); |
||
| 910 | $outputFormat = getDefined('ascii', 'ascii', $outputFormat); |
||
| 911 | |||
| 912 | verbose("outputformat = $outputFormat"); |
||
| 913 | |||
| 914 | if ($outputFormat == 'ascii') { |
||
| 915 | $defaultOptions = getConfig( |
||
| 916 | 'ascii-options', |
||
| 917 | array( |
||
| 918 | "characterSet" => 'two', |
||
| 919 | "scale" => 14, |
||
| 920 | "luminanceStrategy" => 3, |
||
| 921 | "customCharacterSet" => null, |
||
| 922 | ) |
||
| 923 | ); |
||
| 924 | $options = get('ascii'); |
||
| 925 | $options = explode(',', $options); |
||
| 926 | |||
| 927 | if (isset($options[0]) && !empty($options[0])) { |
||
| 928 | $defaultOptions['characterSet'] = $options[0]; |
||
| 929 | } |
||
| 930 | |||
| 931 | if (isset($options[1]) && !empty($options[1])) { |
||
| 932 | $defaultOptions['scale'] = $options[1]; |
||
| 933 | } |
||
| 934 | |||
| 935 | if (isset($options[2]) && !empty($options[2])) { |
||
| 936 | $defaultOptions['luminanceStrategy'] = $options[2]; |
||
| 937 | } |
||
| 938 | |||
| 939 | if (count($options) > 3) { |
||
| 940 | // Last option is custom character string |
||
| 941 | unset($options[0]); |
||
| 942 | unset($options[1]); |
||
| 943 | unset($options[2]); |
||
| 944 | $characterString = implode($options); |
||
| 945 | $defaultOptions['customCharacterSet'] = $characterString; |
||
| 946 | } |
||
| 947 | |||
| 948 | $img->setAsciiOptions($defaultOptions); |
||
| 949 | } |
||
| 950 | |||
| 951 | |||
| 952 | |||
| 953 | |||
| 954 | /** |
||
| 955 | * dpr - change to get larger image to easier support larger dpr, such as retina. |
||
| 956 | */ |
||
| 957 | $dpr = get(array('ppi', 'dpr', 'device-pixel-ratio'), 1); |
||
| 958 | |||
| 959 | verbose("dpr = $dpr"); |
||
| 960 | |||
| 961 | |||
| 962 | |||
| 963 | /** |
||
| 964 | * convolve - image convolution as in http://php.net/manual/en/function.imageconvolution.php |
||
| 965 | */ |
||
| 966 | $convolve = get('convolve', null); |
||
| 967 | $convolutionConstant = getConfig('convolution_constant', array()); |
||
| 968 | |||
| 969 | // Check if the convolve is matching an existing constant |
||
| 970 | if ($convolve && isset($convolutionConstant)) { |
||
| 971 | $img->addConvolveExpressions($convolutionConstant); |
||
| 972 | verbose("convolve constant = " . print_r($convolutionConstant, 1)); |
||
| 973 | } |
||
| 974 | |||
| 975 | verbose("convolve = " . print_r($convolve, 1)); |
||
| 976 | |||
| 977 | |||
| 978 | |||
| 979 | /** |
||
| 980 | * no-upscale, nu - Do not upscale smaller image to larger dimension. |
||
| 981 | */ |
||
| 982 | $upscale = getDefined(array('no-upscale', 'nu'), false, true); |
||
| 983 | |||
| 984 | verbose("upscale = $upscale"); |
||
| 985 | |||
| 986 | |||
| 987 | |||
| 988 | /** |
||
| 989 | * Get details for post processing |
||
| 990 | */ |
||
| 991 | $postProcessing = getConfig('postprocessing', array( |
||
| 992 | 'png_filter' => false, |
||
| 993 | 'png_filter_cmd' => '/usr/local/bin/optipng -q', |
||
| 994 | |||
| 995 | 'png_deflate' => false, |
||
| 996 | 'png_deflate_cmd' => '/usr/local/bin/pngout -q', |
||
| 997 | |||
| 998 | 'jpeg_optimize' => false, |
||
| 999 | 'jpeg_optimize_cmd' => '/usr/local/bin/jpegtran -copy none -optimize', |
||
| 1000 | )); |
||
| 1001 | |||
| 1002 | |||
| 1003 | |||
| 1004 | /** |
||
| 1005 | * alias - Save resulting image to another alias name. |
||
| 1006 | * Password always apply, must be defined. |
||
| 1007 | */ |
||
| 1008 | $alias = get('alias', null); |
||
| 1009 | $aliasPath = getConfig('alias_path', null); |
||
| 1010 | $validAliasname = getConfig('valid_aliasname', '#^[a-z0-9A-Z-_]+$#'); |
||
| 1011 | $aliasTarget = null; |
||
| 1012 | |||
| 1013 | if ($alias && $aliasPath && $passwordMatch) { |
||
| 1014 | |||
| 1015 | $aliasTarget = $aliasPath . $alias; |
||
| 1016 | $useCache = false; |
||
| 1017 | |||
| 1018 | is_writable($aliasPath) |
||
| 1019 | or errorPage("Directory for alias is not writable.", 403); |
||
| 1020 | |||
| 1021 | preg_match($validAliasname, $alias) |
||
| 1022 | or errorPage('Filename for alias contains invalid characters. Do not add extension.', 404); |
||
| 1023 | |||
| 1024 | } elseif ($alias) { |
||
| 1025 | errorPage('Alias is not enabled in the config file or password not matching.', 403); |
||
| 1026 | } |
||
| 1027 | |||
| 1028 | verbose("alias = $alias"); |
||
| 1029 | |||
| 1030 | |||
| 1031 | |||
| 1032 | /** |
||
| 1033 | * Add cache control HTTP header. |
||
| 1034 | */ |
||
| 1035 | $cacheControl = getConfig('cache_control', null); |
||
| 1036 | |||
| 1037 | if ($cacheControl) { |
||
| 1038 | verbose("cacheControl = $cacheControl"); |
||
| 1039 | $img->addHTTPHeader("Cache-Control", $cacheControl); |
||
| 1040 | } |
||
| 1041 | |||
| 1042 | |||
| 1043 | |||
| 1044 | /** |
||
| 1045 | * Prepare a dummy image and use it as source image. |
||
| 1046 | */ |
||
| 1047 | if ($dummyImage === true) { |
||
| 1048 | $dummyDir = $cache->getPathToSubdir("dummy"); |
||
| 1049 | |||
| 1050 | $img->setSaveFolder($dummyDir) |
||
| 1051 | ->setSource($dummyFilename, $dummyDir) |
||
| 1052 | ->setOptions( |
||
| 1053 | array( |
||
| 1054 | 'newWidth' => $newWidth, |
||
| 1055 | 'newHeight' => $newHeight, |
||
| 1056 | 'bgColor' => $bgColor, |
||
| 1057 | ) |
||
| 1058 | ) |
||
| 1059 | ->setJpegQuality($quality) |
||
| 1060 | ->setPngCompression($compress) |
||
| 1061 | ->createDummyImage() |
||
| 1062 | ->generateFilename(null, false) |
||
| 1063 | ->save(null, null, false); |
||
| 1064 | |||
| 1065 | $srcImage = $img->getTarget(); |
||
| 1066 | $imagePath = null; |
||
| 1067 | |||
| 1068 | verbose("src (updated) = $srcImage"); |
||
| 1069 | } |
||
| 1070 | |||
| 1071 | |||
| 1072 | |||
| 1073 | /** |
||
| 1074 | * Prepare a sRGB version of the image and use it as source image. |
||
| 1075 | */ |
||
| 1076 | $srgbDefault = getConfig('srgb_default', false); |
||
| 1077 | $srgbColorProfile = getConfig('srgb_colorprofile', __DIR__ . '/../icc/sRGB_IEC61966-2-1_black_scaled.icc'); |
||
| 1078 | $srgb = getDefined('srgb', true, null); |
||
| 1079 | |||
| 1080 | if ($srgb || $srgbDefault) { |
||
| 1081 | |||
| 1082 | $filename = $img->convert2sRGBColorSpace( |
||
| 1083 | $srcImage, |
||
| 1084 | $imagePath, |
||
| 1085 | $cache->getPathToSubdir("srgb"), |
||
| 1086 | $srgbColorProfile, |
||
| 1087 | $useCache |
||
| 1088 | ); |
||
| 1089 | |||
| 1090 | if ($filename) { |
||
| 1091 | $srcImage = $img->getTarget(); |
||
| 1092 | $imagePath = null; |
||
| 1093 | verbose("srgb conversion and saved to cache = $srcImage"); |
||
| 1094 | } else { |
||
| 1095 | verbose("srgb not op"); |
||
| 1096 | } |
||
| 1097 | } |
||
| 1098 | |||
| 1099 | |||
| 1100 | |||
| 1101 | /** |
||
| 1102 | * Display status |
||
| 1103 | */ |
||
| 1104 | if ($status) { |
||
| 1105 | $text = "img.php version = $version\n"; |
||
| 1106 | $text .= "PHP version = " . PHP_VERSION . "\n"; |
||
| 1107 | $text .= "Running on: " . $_SERVER['SERVER_SOFTWARE'] . "\n"; |
||
| 1108 | $text .= "Allow remote images = $allowRemote\n"; |
||
| 1109 | |||
| 1110 | $res = $cache->getStatusOfSubdir(""); |
||
| 1111 | $text .= "Cache $res\n"; |
||
| 1112 | |||
| 1113 | $res = $cache->getStatusOfSubdir("remote"); |
||
| 1114 | $text .= "Cache remote $res\n"; |
||
| 1115 | |||
| 1116 | $res = $cache->getStatusOfSubdir("dummy"); |
||
| 1117 | $text .= "Cache dummy $res\n"; |
||
| 1118 | |||
| 1119 | $res = $cache->getStatusOfSubdir("srgb"); |
||
| 1120 | $text .= "Cache srgb $res\n"; |
||
| 1121 | |||
| 1122 | $res = $cache->getStatusOfSubdir($fasttrackCache); |
||
| 1123 | $text .= "Cache fasttrack $res\n"; |
||
| 1124 | |||
| 1125 | $text .= "Alias path writable = " . is_writable($aliasPath) . "\n"; |
||
| 1126 | |||
| 1127 | $no = extension_loaded('exif') ? null : 'NOT'; |
||
| 1128 | $text .= "Extension exif is $no loaded.<br>"; |
||
| 1129 | |||
| 1130 | $no = extension_loaded('curl') ? null : 'NOT'; |
||
| 1131 | $text .= "Extension curl is $no loaded.<br>"; |
||
| 1132 | |||
| 1133 | $no = extension_loaded('imagick') ? null : 'NOT'; |
||
| 1134 | $text .= "Extension imagick is $no loaded.<br>"; |
||
| 1135 | |||
| 1136 | $no = extension_loaded('gd') ? null : 'NOT'; |
||
| 1137 | $text .= "Extension gd is $no loaded.<br>"; |
||
| 1138 | |||
| 1139 | if (!$no) { |
||
| 1140 | $text .= print_r(gd_info(), 1); |
||
| 1141 | } |
||
| 1142 | |||
| 1143 | echo <<<EOD |
||
| 1144 | <!doctype html> |
||
| 1145 | <html lang=en> |
||
| 1146 | <meta charset=utf-8> |
||
| 1147 | <title>CImage status</title> |
||
| 1148 | <pre>$text</pre> |
||
| 1149 | EOD; |
||
| 1150 | exit; |
||
| 1151 | } |
||
| 1152 | |||
| 1153 | |||
| 1154 | |||
| 1155 | /** |
||
| 1156 | * Log verbose details to file |
||
| 1157 | */ |
||
| 1158 | if ($verboseFile) { |
||
| 1159 | $img->setVerboseToFile("$cachePath/log.txt"); |
||
| 1160 | } |
||
| 1161 | |||
| 1162 | |||
| 1163 | |||
| 1164 | /** |
||
| 1165 | * Hook after img.php configuration and before processing with CImage |
||
| 1166 | */ |
||
| 1167 | $hookBeforeCImage = getConfig('hook_before_CImage', null); |
||
| 1168 | |||
| 1169 | if (is_callable($hookBeforeCImage)) { |
||
| 1170 | verbose("hookBeforeCImage activated"); |
||
| 1171 | |||
| 1172 | $allConfig = $hookBeforeCImage($img, array( |
||
| 1173 | // Options for calculate dimensions |
||
| 1174 | 'newWidth' => $newWidth, |
||
| 1175 | 'newHeight' => $newHeight, |
||
| 1176 | 'aspectRatio' => $aspectRatio, |
||
| 1177 | 'keepRatio' => $keepRatio, |
||
| 1178 | 'cropToFit' => $cropToFit, |
||
| 1179 | 'fillToFit' => $fillToFit, |
||
| 1180 | 'crop' => $crop, |
||
| 1181 | 'area' => $area, |
||
| 1182 | 'upscale' => $upscale, |
||
| 1183 | |||
| 1184 | // Pre-processing, before resizing is done |
||
| 1185 | 'scale' => $scale, |
||
| 1186 | 'rotateBefore' => $rotateBefore, |
||
| 1187 | 'autoRotate' => $autoRotate, |
||
| 1188 | |||
| 1189 | // General processing options |
||
| 1190 | 'bgColor' => $bgColor, |
||
| 1191 | |||
| 1192 | // Post-processing, after resizing is done |
||
| 1193 | 'palette' => $palette, |
||
| 1194 | 'filters' => $filters, |
||
| 1195 | 'sharpen' => $sharpen, |
||
| 1196 | 'emboss' => $emboss, |
||
| 1197 | 'blur' => $blur, |
||
| 1198 | 'convolve' => $convolve, |
||
| 1199 | 'rotateAfter' => $rotateAfter, |
||
| 1200 | |||
| 1201 | // Output format |
||
| 1202 | 'outputFormat' => $outputFormat, |
||
| 1203 | 'dpr' => $dpr, |
||
| 1204 | |||
| 1205 | // Other |
||
| 1206 | 'postProcessing' => $postProcessing, |
||
| 1207 | )); |
||
| 1208 | verbose(print_r($allConfig, 1)); |
||
| 1209 | extract($allConfig); |
||
| 1210 | } |
||
| 1211 | |||
| 1212 | |||
| 1213 | |||
| 1214 | /** |
||
| 1215 | * Display image if verbose mode |
||
| 1216 | */ |
||
| 1217 | if ($verbose) { |
||
| 1218 | $query = array(); |
||
| 1219 | parse_str($_SERVER['QUERY_STRING'], $query); |
||
| 1220 | unset($query['verbose']); |
||
| 1221 | unset($query['v']); |
||
| 1222 | unset($query['nocache']); |
||
| 1223 | unset($query['nc']); |
||
| 1224 | unset($query['json']); |
||
| 1225 | $url1 = '?' . htmlentities(urldecode(http_build_query($query))); |
||
| 1226 | $url2 = '?' . urldecode(http_build_query($query)); |
||
| 1227 | echo <<<EOD |
||
| 1228 | <!doctype html> |
||
| 1229 | <html lang=en> |
||
| 1230 | <meta charset=utf-8> |
||
| 1231 | <title>CImage verbose output</title> |
||
| 1232 | <style>body{background-color: #ddd}</style> |
||
| 1233 | <a href=$url1><code>$url1</code></a><br> |
||
| 1234 | <img src='{$url1}' /> |
||
| 1235 | <pre id="json"></pre> |
||
| 1236 | <script src="https://code.jquery.com/jquery-2.1.1.min.js"></script> |
||
| 1237 | <script type="text/javascript"> |
||
| 1238 | window.getDetails = function (url, id) { |
||
| 1239 | $.getJSON(url, function(data) { |
||
| 1240 | element = document.getElementById(id); |
||
| 1241 | element.innerHTML = "filename: " + data.filename + "\\nmime type: " + data.mimeType + "\\ncolors: " + data.colors + "\\nsize: " + data.size + "\\nwidth: " + data.width + "\\nheigh: " + data.height + "\\naspect-ratio: " + data.aspectRatio + ( data.pngType ? "\\npng-type: " + data.pngType : ''); |
||
| 1242 | }); |
||
| 1243 | } |
||
| 1244 | </script> |
||
| 1245 | <script type="text/javascript">window.getDetails("{$url2}&json", "json")</script> |
||
| 1246 | EOD; |
||
| 1247 | } |
||
| 1248 | |||
| 1249 | |||
| 1250 | |||
| 1251 | /** |
||
| 1252 | * Load, process and output the image |
||
| 1253 | */ |
||
| 1254 | $img->log("Incoming arguments: " . print_r(verbose(), 1)) |
||
| 1255 | ->setSaveFolder($cachePath) |
||
| 1256 | ->useCache($useCache) |
||
| 1257 | ->setSource($srcImage, $imagePath) |
||
| 1258 | ->setOptions( |
||
| 1259 | array( |
||
| 1260 | // Options for calculate dimensions |
||
| 1261 | 'newWidth' => $newWidth, |
||
| 1262 | 'newHeight' => $newHeight, |
||
| 1263 | 'aspectRatio' => $aspectRatio, |
||
| 1264 | 'keepRatio' => $keepRatio, |
||
| 1265 | 'cropToFit' => $cropToFit, |
||
| 1266 | 'fillToFit' => $fillToFit, |
||
| 1267 | 'crop' => $crop, |
||
| 1268 | 'area' => $area, |
||
| 1269 | 'upscale' => $upscale, |
||
| 1270 | |||
| 1271 | // Pre-processing, before resizing is done |
||
| 1272 | 'scale' => $scale, |
||
| 1273 | 'rotateBefore' => $rotateBefore, |
||
| 1274 | 'autoRotate' => $autoRotate, |
||
| 1275 | |||
| 1276 | // General processing options |
||
| 1277 | 'bgColor' => $bgColor, |
||
| 1278 | |||
| 1279 | // Post-processing, after resizing is done |
||
| 1280 | 'palette' => $palette, |
||
| 1281 | 'filters' => $filters, |
||
| 1282 | 'sharpen' => $sharpen, |
||
| 1283 | 'emboss' => $emboss, |
||
| 1284 | 'blur' => $blur, |
||
| 1285 | 'convolve' => $convolve, |
||
| 1286 | 'rotateAfter' => $rotateAfter, |
||
| 1287 | |||
| 1288 | // Output format |
||
| 1289 | 'outputFormat' => $outputFormat, |
||
| 1290 | 'dpr' => $dpr, |
||
| 1291 | ) |
||
| 1292 | ) |
||
| 1293 | ->loadImageDetails() |
||
| 1294 | ->initDimensions() |
||
| 1295 | ->calculateNewWidthAndHeight() |
||
| 1296 | ->setSaveAsExtension($saveAs) |
||
| 1297 | ->setJpegQuality($quality) |
||
| 1298 | ->setPngCompression($compress) |
||
| 1299 | ->useOriginalIfPossible($useOriginal) |
||
| 1300 | ->generateFilename($cachePath) |
||
| 1301 | ->useCacheIfPossible($useCache) |
||
| 1302 | ->load() |
||
| 1303 | ->preResize() |
||
| 1304 | ->resize() |
||
| 1305 | ->postResize() |
||
| 1306 | ->setPostProcessingOptions($postProcessing) |
||
| 1307 | ->save() |
||
| 1308 | ->linkToCacheFile($aliasTarget) |
||
| 1309 | ->output(); |
||
| 1310 |
Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable: