From 8bc710f3b857a9efe115f331b53a7bb30218f3ac Mon Sep 17 00:00:00 2001 From: Mikael Roos Date: Sat, 25 Jul 2015 22:21:12 +0200 Subject: [PATCH] * Using `CWhitelist` for checking hotlinking to images, fix #88. * Added mode for `test` which enables logging verbose mode to file, fix #97. --- CImage.php | 72 ++++++++++++--- CWhitelist.php | 6 +- REVISION.md | 1 + test/CImageRemoteDownloadTest.php | 15 +++ webroot/img.php | 69 +++++++++----- webroot/img_config.php | 13 +-- webroot/imgd.php | 147 ++++++++++++++++++++++-------- webroot/imgp.php | 147 ++++++++++++++++++++++-------- webroot/imgs.php | 147 ++++++++++++++++++++++-------- 9 files changed, 467 insertions(+), 150 deletions(-) diff --git a/CImage.php b/CImage.php index c8bbc95..24be590 100644 --- a/CImage.php +++ b/CImage.php @@ -318,6 +318,22 @@ class CImage private $useCache = true; + + /* + * Set whitelist for valid hostnames from where remote source can be + * downloaded. + */ + private $remoteHostWhitelist = null; + + + + /* + * Do verbose logging to file by setting this to a filename. + */ + private $verboseFileName = null; + + + /** * Properties, the class is mutable and the method setOptions() * decides (partly) what properties are created. @@ -418,10 +434,12 @@ class CImage $this->allowRemote = $allow; $this->remotePattern = is_null($pattern) ? $this->remotePattern : $pattern; - $this->log("Set remote download to: " + $this->log( + "Set remote download to: " . ($this->allowRemote ? "true" : "false") . " using pattern " - . $this->remotePattern); + . $this->remotePattern + ); return $this; } @@ -455,7 +473,10 @@ class CImage public function setRemoteHostWhitelist($whitelist = null) { $this->remoteHostWhitelist = $whitelist; - $this->log("Setting remote host whitelist to: " . print_r($this->remoteHostWhitelist, 1)); + $this->log( + "Setting remote host whitelist to: " + . (is_null($whitelist) ? "null" : print_r($whitelist, 1)) + ); return $this; } @@ -472,14 +493,18 @@ class CImage public function isRemoteSourceOnWhitelist($src) { if (is_null($this->remoteHostWhitelist)) { - $allow = true; - } else { - $whitelist = new CWhitelist(); - $hostname = parse_url($src, PHP_URL_HOST); - $allow = $whitelist->check($hostname, $this->remoteHostWhitelist); + $this->log("Remote host on whitelist not configured - allowing."); + return true; } - $this->log("Remote host is on whitelist: " . ($allow ? "true" : "false")); + $whitelist = new CWhitelist(); + $hostname = parse_url($src, PHP_URL_HOST); + $allow = $whitelist->check($hostname, $this->remoteHostWhitelist); + + $this->log( + "Remote host is on whitelist: " + . ($allow ? "true" : "false") + ); return $allow; } @@ -2253,7 +2278,10 @@ class CImage if ($this->verbose) { $this->log("Last modified: " . $gmdate . " GMT"); $this->verboseOutput(); - exit; + + if (is_null($this->verboseFileName)) { + exit; + } } // Get details on image @@ -2331,6 +2359,21 @@ class CImage + /** + * Do verbose output to a file. + * + * @param string $fileName where to write the verbose output. + * + * @return void + */ + public function setVerboseToFile($fileName) + { + $this->log("Setting verbose output to file."); + $this->verboseFileName = $fileName; + } + + + /** * Do verbose output and print out the log and the actual images. * @@ -2356,10 +2399,17 @@ class CImage } } - echo <<verboseFileName)) { + file_put_contents( + $this->verboseFileName, + str_replace("
", "\n", $log) + ); + } else { + echo <<CImage Verbose Output
{$log}
EOD; + } } diff --git a/CWhitelist.php b/CWhitelist.php index 539e392..3ecdb97 100644 --- a/CWhitelist.php +++ b/CWhitelist.php @@ -23,11 +23,11 @@ class CWhitelist */ public function set($whitelist = array()) { - if (is_array($whitelist)) { - $this->whitelist = $whitelist; - } else { + if (!is_array($whitelist)) { throw new Exception("Whitelist is not of a supported format."); } + + $this->whitelist = $whitelist; return $this; } diff --git a/REVISION.md b/REVISION.md index 4eb72f0..3479ed1 100644 --- a/REVISION.md +++ b/REVISION.md @@ -8,6 +8,7 @@ Revision history v0.7.0.x (latest) ------------------------------------- +* Added mode for test which enables logging verbose mode to file. * Improved codestyle and added `phpcs.xml` to start using phpcs to check code style, fix #95. * Adding `composer.json` for publishing on packagist. * Add permalink to setup for comparing images with `webroot/compare/compare.php`, fix #92. diff --git a/test/CImageRemoteDownloadTest.php b/test/CImageRemoteDownloadTest.php index 6d2dc9d..dd2af20 100644 --- a/test/CImageRemoteDownloadTest.php +++ b/test/CImageRemoteDownloadTest.php @@ -162,4 +162,19 @@ class CImageRemoteDownloadTest extends \PHPUnit_Framework_TestCase $res = $img->isRemoteSourceOnWhitelist("http://$hostname/img.jpg"); $this->assertFalse($res, "Should not be a valid hostname on the whitelist: '$hostname'."); } + + + + /** + * Test + * + * @return void + * + */ + public function testRemoteHostWhitelistNotConfigured() + { + $img = new CImage(); + $res = $img->isRemoteSourceOnWhitelist(null); + $this->assertTrue($res, "Should allow when whitelist not configured."); + } } diff --git a/webroot/img.php b/webroot/img.php index 7292832..0cc7ab9 100644 --- a/webroot/img.php +++ b/webroot/img.php @@ -27,10 +27,10 @@ function errorPage($msg) if ($mode == 'development') { die("[img.php] $msg"); - } else { - error_log("[img.php] $msg"); - die("HTTP/1.0 500 Internal Server Error"); } + + error_log("[img.php] $msg"); + die("HTTP/1.0 500 Internal Server Error"); } @@ -39,7 +39,13 @@ function errorPage($msg) * Custom exception handler. */ set_exception_handler(function ($exception) { - errorPage("

img.php: Uncaught exception:

" . $exception->getMessage() . "

" . $exception->getTraceAsString(), "
"); + errorPage( + "

img.php: Uncaught exception:

" + . $exception->getMessage() + . "

"
+        . $exception->getTraceAsString()
+        . "
" + ); }); @@ -111,10 +117,10 @@ function getConfig($key, $default) */ function verbose($msg = null) { - global $verbose; + global $verbose, $verboseFile; static $log = array(); - if (!$verbose) { + if (!($verbose || $verboseFile)) { return; } @@ -143,8 +149,10 @@ if (is_file($configFile)) { /** * verbose, v - do a verbose dump of what happens +* vf - do verbose dump to file */ $verbose = getDefined(array('verbose', 'v'), true, false); +$verboseFile = getDefined('vf', true, false); verbose("img.php version = $version"); @@ -170,19 +178,28 @@ if ($mode == 'strict') { ini_set('display_errors', 0); ini_set('log_errors', 1); $verbose = false; - + $verboseFile = false; + } elseif ($mode == 'production') { error_reporting(-1); ini_set('display_errors', 0); ini_set('log_errors', 1); $verbose = false; + $verboseFile = false; } elseif ($mode == 'development') { error_reporting(-1); ini_set('display_errors', 1); ini_set('log_errors', 0); + $verboseFile = false; + +} elseif ($mode == 'test') { + + error_reporting(-1); + ini_set('display_errors', 1); + ini_set('log_errors', 0); } else { errorPage("Unknown mode: $mode"); @@ -247,23 +264,22 @@ $refererHost = parse_url($referer, PHP_URL_HOST); if (!$allowHotlinking) { if ($passwordMatch) { ; // Always allow when password match + verbose("Hotlinking since passwordmatch"); } elseif ($passwordMatch === false) { errorPage("Hotlinking/leeching not allowed when password missmatch."); } elseif (!$referer) { errorPage("Hotlinking/leeching not allowed and referer is missing."); } elseif (strcmp($serverName, $refererHost) == 0) { ; // Allow when serverName matches refererHost + verbose("Hotlinking disallowed but serverName matches refererHost."); } elseif (!empty($hotlinkingWhitelist)) { + $whitelist = new CWhitelist(); + $allowedByWhitelist = $whitelist->check($refererHost, $hotlinkingWhitelist); - $allowedByWhitelist = false; - foreach ($hotlinkingWhitelist as $val) { - if (preg_match($val, $refererHost)) { - $allowedByWhitelist = true; - } - } - - if (!$allowedByWhitelist) { - errorPage("Hotlinking/leeching not allowed by whitelist."); + if ($allowedByWhitelist) { + verbose("Hotlinking/leeching allowed by whitelist."); + } else { + errorPage("Hotlinking/leeching not allowed by whitelist. Referer: $referer."); } } else { @@ -295,7 +311,7 @@ if ($autoloader) { * Create the class for the image. */ $img = new CImage(); -$img->setVerbose($verbose); +$img->setVerbose($verbose || $verboseFile); @@ -815,6 +831,13 @@ verbose("alias = $alias"); +/** + * Get the cachepath from config. + */ +$cachePath = getConfig('cache_path', __DIR__ . '/../cache/'); + + + /** * Display image if verbose mode */ @@ -853,15 +876,17 @@ EOD; /** - * Get the cachepath from config. + * Log verbose details to file */ -$cachePath = getConfig('cache_path', __DIR__ . '/../cache/'); +if ($verboseFile) { + $img->setVerboseToFile("$cachePath/log.txt"); +} -/** - * Load, process and output the image - */ + /** + * Load, process and output the image + */ $img->log("Incoming arguments: " . print_r(verbose(), 1)) ->setSaveFolder($cachePath) ->useCache($useCache) diff --git a/webroot/img_config.php b/webroot/img_config.php index a0994e9..2e0ddc4 100644 --- a/webroot/img_config.php +++ b/webroot/img_config.php @@ -201,9 +201,12 @@ return array( /** - * Prevent leeching of images by controlling who can access them from where. - * Default it to allow hotlinking. - * Password apply when hotlinking is disallowed, use password to allow. + * Prevent leeching of images by controlling the hostname of those who + * can access the images. Default is to allow hotlinking. + * + * Password apply when hotlinking is disallowed, use password to allow + * hotlinking. + * * The whitelist is an array of regexpes for allowed hostnames that can * hotlink images. * @@ -214,13 +217,11 @@ return array( /* 'allow_hotlinking' => false, 'hotlinking_whitelist' => array( - '#^localhost$#', - '#^dbwebb\.se$#', + '^dbwebb\.se$', ), */ - /** * Create custom shortcuts for more advanced expressions. * diff --git a/webroot/imgd.php b/webroot/imgd.php index 4eccafb..585287b 100644 --- a/webroot/imgd.php +++ b/webroot/imgd.php @@ -916,6 +916,22 @@ class CImage private $useCache = true; + + /* + * Set whitelist for valid hostnames from where remote source can be + * downloaded. + */ + private $remoteHostWhitelist = null; + + + + /* + * Do verbose logging to file by setting this to a filename. + */ + private $verboseFileName = null; + + + /** * Properties, the class is mutable and the method setOptions() * decides (partly) what properties are created. @@ -1016,10 +1032,12 @@ class CImage $this->allowRemote = $allow; $this->remotePattern = is_null($pattern) ? $this->remotePattern : $pattern; - $this->log("Set remote download to: " + $this->log( + "Set remote download to: " . ($this->allowRemote ? "true" : "false") . " using pattern " - . $this->remotePattern); + . $this->remotePattern + ); return $this; } @@ -1053,7 +1071,10 @@ class CImage public function setRemoteHostWhitelist($whitelist = null) { $this->remoteHostWhitelist = $whitelist; - $this->log("Setting remote host whitelist to: " . print_r($this->remoteHostWhitelist, 1)); + $this->log( + "Setting remote host whitelist to: " + . (is_null($whitelist) ? "null" : print_r($whitelist, 1)) + ); return $this; } @@ -1070,14 +1091,18 @@ class CImage public function isRemoteSourceOnWhitelist($src) { if (is_null($this->remoteHostWhitelist)) { - $allow = true; - } else { - $whitelist = new CWhitelist(); - $hostname = parse_url($src, PHP_URL_HOST); - $allow = $whitelist->check($hostname, $this->remoteHostWhitelist); + $this->log("Remote host on whitelist not configured - allowing."); + return true; } - $this->log("Remote host is on whitelist: " . ($allow ? "true" : "false")); + $whitelist = new CWhitelist(); + $hostname = parse_url($src, PHP_URL_HOST); + $allow = $whitelist->check($hostname, $this->remoteHostWhitelist); + + $this->log( + "Remote host is on whitelist: " + . ($allow ? "true" : "false") + ); return $allow; } @@ -2851,7 +2876,10 @@ class CImage if ($this->verbose) { $this->log("Last modified: " . $gmdate . " GMT"); $this->verboseOutput(); - exit; + + if (is_null($this->verboseFileName)) { + exit; + } } // Get details on image @@ -2929,6 +2957,21 @@ class CImage + /** + * Do verbose output to a file. + * + * @param string $fileName where to write the verbose output. + * + * @return void + */ + public function setVerboseToFile($fileName) + { + $this->log("Setting verbose output to file."); + $this->verboseFileName = $fileName; + } + + + /** * Do verbose output and print out the log and the actual images. * @@ -2954,10 +2997,17 @@ class CImage } } - echo <<verboseFileName)) { + file_put_contents( + $this->verboseFileName, + str_replace("
", "\n", $log) + ); + } else { + echo <<CImage Verbose Output
{$log}
EOD; + } } @@ -3002,11 +3052,11 @@ class CWhitelist */ public function set($whitelist = array()) { - if (is_array($whitelist)) { - $this->whitelist = $whitelist; - } else { + if (!is_array($whitelist)) { throw new Exception("Whitelist is not of a supported format."); } + + $this->whitelist = $whitelist; return $this; } @@ -3070,10 +3120,10 @@ function errorPage($msg) if ($mode == 'development') { die("[img.php] $msg"); - } else { - error_log("[img.php] $msg"); - die("HTTP/1.0 500 Internal Server Error"); } + + error_log("[img.php] $msg"); + die("HTTP/1.0 500 Internal Server Error"); } @@ -3082,7 +3132,13 @@ function errorPage($msg) * Custom exception handler. */ set_exception_handler(function ($exception) { - errorPage("

img.php: Uncaught exception:

" . $exception->getMessage() . "

" . $exception->getTraceAsString(), "
"); + errorPage( + "

img.php: Uncaught exception:

" + . $exception->getMessage() + . "

"
+        . $exception->getTraceAsString()
+        . "
" + ); }); @@ -3154,10 +3210,10 @@ function getConfig($key, $default) */ function verbose($msg = null) { - global $verbose; + global $verbose, $verboseFile; static $log = array(); - if (!$verbose) { + if (!($verbose || $verboseFile)) { return; } @@ -3186,8 +3242,10 @@ if (is_file($configFile)) { /** * verbose, v - do a verbose dump of what happens +* vf - do verbose dump to file */ $verbose = getDefined(array('verbose', 'v'), true, false); +$verboseFile = getDefined('vf', true, false); verbose("img.php version = $version"); @@ -3213,19 +3271,28 @@ if ($mode == 'strict') { ini_set('display_errors', 0); ini_set('log_errors', 1); $verbose = false; - + $verboseFile = false; + } elseif ($mode == 'production') { error_reporting(-1); ini_set('display_errors', 0); ini_set('log_errors', 1); $verbose = false; + $verboseFile = false; } elseif ($mode == 'development') { error_reporting(-1); ini_set('display_errors', 1); ini_set('log_errors', 0); + $verboseFile = false; + +} elseif ($mode == 'test') { + + error_reporting(-1); + ini_set('display_errors', 1); + ini_set('log_errors', 0); } else { errorPage("Unknown mode: $mode"); @@ -3290,23 +3357,22 @@ $refererHost = parse_url($referer, PHP_URL_HOST); if (!$allowHotlinking) { if ($passwordMatch) { ; // Always allow when password match + verbose("Hotlinking since passwordmatch"); } elseif ($passwordMatch === false) { errorPage("Hotlinking/leeching not allowed when password missmatch."); } elseif (!$referer) { errorPage("Hotlinking/leeching not allowed and referer is missing."); } elseif (strcmp($serverName, $refererHost) == 0) { ; // Allow when serverName matches refererHost + verbose("Hotlinking disallowed but serverName matches refererHost."); } elseif (!empty($hotlinkingWhitelist)) { + $whitelist = new CWhitelist(); + $allowedByWhitelist = $whitelist->check($refererHost, $hotlinkingWhitelist); - $allowedByWhitelist = false; - foreach ($hotlinkingWhitelist as $val) { - if (preg_match($val, $refererHost)) { - $allowedByWhitelist = true; - } - } - - if (!$allowedByWhitelist) { - errorPage("Hotlinking/leeching not allowed by whitelist."); + if ($allowedByWhitelist) { + verbose("Hotlinking/leeching allowed by whitelist."); + } else { + errorPage("Hotlinking/leeching not allowed by whitelist. Referer: $referer."); } } else { @@ -3338,7 +3404,7 @@ if ($autoloader) { * Create the class for the image. */ $img = new CImage(); -$img->setVerbose($verbose); +$img->setVerbose($verbose || $verboseFile); @@ -3858,6 +3924,13 @@ verbose("alias = $alias"); +/** + * Get the cachepath from config. + */ +$cachePath = getConfig('cache_path', __DIR__ . '/../cache/'); + + + /** * Display image if verbose mode */ @@ -3896,15 +3969,17 @@ EOD; /** - * Get the cachepath from config. + * Log verbose details to file */ -$cachePath = getConfig('cache_path', __DIR__ . '/../cache/'); +if ($verboseFile) { + $img->setVerboseToFile("$cachePath/log.txt"); +} -/** - * Load, process and output the image - */ + /** + * Load, process and output the image + */ $img->log("Incoming arguments: " . print_r(verbose(), 1)) ->setSaveFolder($cachePath) ->useCache($useCache) diff --git a/webroot/imgp.php b/webroot/imgp.php index b7293d4..4a762b5 100644 --- a/webroot/imgp.php +++ b/webroot/imgp.php @@ -916,6 +916,22 @@ class CImage private $useCache = true; + + /* + * Set whitelist for valid hostnames from where remote source can be + * downloaded. + */ + private $remoteHostWhitelist = null; + + + + /* + * Do verbose logging to file by setting this to a filename. + */ + private $verboseFileName = null; + + + /** * Properties, the class is mutable and the method setOptions() * decides (partly) what properties are created. @@ -1016,10 +1032,12 @@ class CImage $this->allowRemote = $allow; $this->remotePattern = is_null($pattern) ? $this->remotePattern : $pattern; - $this->log("Set remote download to: " + $this->log( + "Set remote download to: " . ($this->allowRemote ? "true" : "false") . " using pattern " - . $this->remotePattern); + . $this->remotePattern + ); return $this; } @@ -1053,7 +1071,10 @@ class CImage public function setRemoteHostWhitelist($whitelist = null) { $this->remoteHostWhitelist = $whitelist; - $this->log("Setting remote host whitelist to: " . print_r($this->remoteHostWhitelist, 1)); + $this->log( + "Setting remote host whitelist to: " + . (is_null($whitelist) ? "null" : print_r($whitelist, 1)) + ); return $this; } @@ -1070,14 +1091,18 @@ class CImage public function isRemoteSourceOnWhitelist($src) { if (is_null($this->remoteHostWhitelist)) { - $allow = true; - } else { - $whitelist = new CWhitelist(); - $hostname = parse_url($src, PHP_URL_HOST); - $allow = $whitelist->check($hostname, $this->remoteHostWhitelist); + $this->log("Remote host on whitelist not configured - allowing."); + return true; } - $this->log("Remote host is on whitelist: " . ($allow ? "true" : "false")); + $whitelist = new CWhitelist(); + $hostname = parse_url($src, PHP_URL_HOST); + $allow = $whitelist->check($hostname, $this->remoteHostWhitelist); + + $this->log( + "Remote host is on whitelist: " + . ($allow ? "true" : "false") + ); return $allow; } @@ -2851,7 +2876,10 @@ class CImage if ($this->verbose) { $this->log("Last modified: " . $gmdate . " GMT"); $this->verboseOutput(); - exit; + + if (is_null($this->verboseFileName)) { + exit; + } } // Get details on image @@ -2929,6 +2957,21 @@ class CImage + /** + * Do verbose output to a file. + * + * @param string $fileName where to write the verbose output. + * + * @return void + */ + public function setVerboseToFile($fileName) + { + $this->log("Setting verbose output to file."); + $this->verboseFileName = $fileName; + } + + + /** * Do verbose output and print out the log and the actual images. * @@ -2954,10 +2997,17 @@ class CImage } } - echo <<verboseFileName)) { + file_put_contents( + $this->verboseFileName, + str_replace("
", "\n", $log) + ); + } else { + echo <<CImage Verbose Output
{$log}
EOD; + } } @@ -3002,11 +3052,11 @@ class CWhitelist */ public function set($whitelist = array()) { - if (is_array($whitelist)) { - $this->whitelist = $whitelist; - } else { + if (!is_array($whitelist)) { throw new Exception("Whitelist is not of a supported format."); } + + $this->whitelist = $whitelist; return $this; } @@ -3070,10 +3120,10 @@ function errorPage($msg) if ($mode == 'development') { die("[img.php] $msg"); - } else { - error_log("[img.php] $msg"); - die("HTTP/1.0 500 Internal Server Error"); } + + error_log("[img.php] $msg"); + die("HTTP/1.0 500 Internal Server Error"); } @@ -3082,7 +3132,13 @@ function errorPage($msg) * Custom exception handler. */ set_exception_handler(function ($exception) { - errorPage("

img.php: Uncaught exception:

" . $exception->getMessage() . "

" . $exception->getTraceAsString(), "
"); + errorPage( + "

img.php: Uncaught exception:

" + . $exception->getMessage() + . "

"
+        . $exception->getTraceAsString()
+        . "
" + ); }); @@ -3154,10 +3210,10 @@ function getConfig($key, $default) */ function verbose($msg = null) { - global $verbose; + global $verbose, $verboseFile; static $log = array(); - if (!$verbose) { + if (!($verbose || $verboseFile)) { return; } @@ -3186,8 +3242,10 @@ if (is_file($configFile)) { /** * verbose, v - do a verbose dump of what happens +* vf - do verbose dump to file */ $verbose = getDefined(array('verbose', 'v'), true, false); +$verboseFile = getDefined('vf', true, false); verbose("img.php version = $version"); @@ -3213,19 +3271,28 @@ if ($mode == 'strict') { ini_set('display_errors', 0); ini_set('log_errors', 1); $verbose = false; - + $verboseFile = false; + } elseif ($mode == 'production') { error_reporting(-1); ini_set('display_errors', 0); ini_set('log_errors', 1); $verbose = false; + $verboseFile = false; } elseif ($mode == 'development') { error_reporting(-1); ini_set('display_errors', 1); ini_set('log_errors', 0); + $verboseFile = false; + +} elseif ($mode == 'test') { + + error_reporting(-1); + ini_set('display_errors', 1); + ini_set('log_errors', 0); } else { errorPage("Unknown mode: $mode"); @@ -3290,23 +3357,22 @@ $refererHost = parse_url($referer, PHP_URL_HOST); if (!$allowHotlinking) { if ($passwordMatch) { ; // Always allow when password match + verbose("Hotlinking since passwordmatch"); } elseif ($passwordMatch === false) { errorPage("Hotlinking/leeching not allowed when password missmatch."); } elseif (!$referer) { errorPage("Hotlinking/leeching not allowed and referer is missing."); } elseif (strcmp($serverName, $refererHost) == 0) { ; // Allow when serverName matches refererHost + verbose("Hotlinking disallowed but serverName matches refererHost."); } elseif (!empty($hotlinkingWhitelist)) { + $whitelist = new CWhitelist(); + $allowedByWhitelist = $whitelist->check($refererHost, $hotlinkingWhitelist); - $allowedByWhitelist = false; - foreach ($hotlinkingWhitelist as $val) { - if (preg_match($val, $refererHost)) { - $allowedByWhitelist = true; - } - } - - if (!$allowedByWhitelist) { - errorPage("Hotlinking/leeching not allowed by whitelist."); + if ($allowedByWhitelist) { + verbose("Hotlinking/leeching allowed by whitelist."); + } else { + errorPage("Hotlinking/leeching not allowed by whitelist. Referer: $referer."); } } else { @@ -3338,7 +3404,7 @@ if ($autoloader) { * Create the class for the image. */ $img = new CImage(); -$img->setVerbose($verbose); +$img->setVerbose($verbose || $verboseFile); @@ -3858,6 +3924,13 @@ verbose("alias = $alias"); +/** + * Get the cachepath from config. + */ +$cachePath = getConfig('cache_path', __DIR__ . '/../cache/'); + + + /** * Display image if verbose mode */ @@ -3896,15 +3969,17 @@ EOD; /** - * Get the cachepath from config. + * Log verbose details to file */ -$cachePath = getConfig('cache_path', __DIR__ . '/../cache/'); +if ($verboseFile) { + $img->setVerboseToFile("$cachePath/log.txt"); +} -/** - * Load, process and output the image - */ + /** + * Load, process and output the image + */ $img->log("Incoming arguments: " . print_r(verbose(), 1)) ->setSaveFolder($cachePath) ->useCache($useCache) diff --git a/webroot/imgs.php b/webroot/imgs.php index 4eccafb..585287b 100644 --- a/webroot/imgs.php +++ b/webroot/imgs.php @@ -916,6 +916,22 @@ class CImage private $useCache = true; + + /* + * Set whitelist for valid hostnames from where remote source can be + * downloaded. + */ + private $remoteHostWhitelist = null; + + + + /* + * Do verbose logging to file by setting this to a filename. + */ + private $verboseFileName = null; + + + /** * Properties, the class is mutable and the method setOptions() * decides (partly) what properties are created. @@ -1016,10 +1032,12 @@ class CImage $this->allowRemote = $allow; $this->remotePattern = is_null($pattern) ? $this->remotePattern : $pattern; - $this->log("Set remote download to: " + $this->log( + "Set remote download to: " . ($this->allowRemote ? "true" : "false") . " using pattern " - . $this->remotePattern); + . $this->remotePattern + ); return $this; } @@ -1053,7 +1071,10 @@ class CImage public function setRemoteHostWhitelist($whitelist = null) { $this->remoteHostWhitelist = $whitelist; - $this->log("Setting remote host whitelist to: " . print_r($this->remoteHostWhitelist, 1)); + $this->log( + "Setting remote host whitelist to: " + . (is_null($whitelist) ? "null" : print_r($whitelist, 1)) + ); return $this; } @@ -1070,14 +1091,18 @@ class CImage public function isRemoteSourceOnWhitelist($src) { if (is_null($this->remoteHostWhitelist)) { - $allow = true; - } else { - $whitelist = new CWhitelist(); - $hostname = parse_url($src, PHP_URL_HOST); - $allow = $whitelist->check($hostname, $this->remoteHostWhitelist); + $this->log("Remote host on whitelist not configured - allowing."); + return true; } - $this->log("Remote host is on whitelist: " . ($allow ? "true" : "false")); + $whitelist = new CWhitelist(); + $hostname = parse_url($src, PHP_URL_HOST); + $allow = $whitelist->check($hostname, $this->remoteHostWhitelist); + + $this->log( + "Remote host is on whitelist: " + . ($allow ? "true" : "false") + ); return $allow; } @@ -2851,7 +2876,10 @@ class CImage if ($this->verbose) { $this->log("Last modified: " . $gmdate . " GMT"); $this->verboseOutput(); - exit; + + if (is_null($this->verboseFileName)) { + exit; + } } // Get details on image @@ -2929,6 +2957,21 @@ class CImage + /** + * Do verbose output to a file. + * + * @param string $fileName where to write the verbose output. + * + * @return void + */ + public function setVerboseToFile($fileName) + { + $this->log("Setting verbose output to file."); + $this->verboseFileName = $fileName; + } + + + /** * Do verbose output and print out the log and the actual images. * @@ -2954,10 +2997,17 @@ class CImage } } - echo <<verboseFileName)) { + file_put_contents( + $this->verboseFileName, + str_replace("
", "\n", $log) + ); + } else { + echo <<CImage Verbose Output
{$log}
EOD; + } } @@ -3002,11 +3052,11 @@ class CWhitelist */ public function set($whitelist = array()) { - if (is_array($whitelist)) { - $this->whitelist = $whitelist; - } else { + if (!is_array($whitelist)) { throw new Exception("Whitelist is not of a supported format."); } + + $this->whitelist = $whitelist; return $this; } @@ -3070,10 +3120,10 @@ function errorPage($msg) if ($mode == 'development') { die("[img.php] $msg"); - } else { - error_log("[img.php] $msg"); - die("HTTP/1.0 500 Internal Server Error"); } + + error_log("[img.php] $msg"); + die("HTTP/1.0 500 Internal Server Error"); } @@ -3082,7 +3132,13 @@ function errorPage($msg) * Custom exception handler. */ set_exception_handler(function ($exception) { - errorPage("

img.php: Uncaught exception:

" . $exception->getMessage() . "

" . $exception->getTraceAsString(), "
"); + errorPage( + "

img.php: Uncaught exception:

" + . $exception->getMessage() + . "

"
+        . $exception->getTraceAsString()
+        . "
" + ); }); @@ -3154,10 +3210,10 @@ function getConfig($key, $default) */ function verbose($msg = null) { - global $verbose; + global $verbose, $verboseFile; static $log = array(); - if (!$verbose) { + if (!($verbose || $verboseFile)) { return; } @@ -3186,8 +3242,10 @@ if (is_file($configFile)) { /** * verbose, v - do a verbose dump of what happens +* vf - do verbose dump to file */ $verbose = getDefined(array('verbose', 'v'), true, false); +$verboseFile = getDefined('vf', true, false); verbose("img.php version = $version"); @@ -3213,19 +3271,28 @@ if ($mode == 'strict') { ini_set('display_errors', 0); ini_set('log_errors', 1); $verbose = false; - + $verboseFile = false; + } elseif ($mode == 'production') { error_reporting(-1); ini_set('display_errors', 0); ini_set('log_errors', 1); $verbose = false; + $verboseFile = false; } elseif ($mode == 'development') { error_reporting(-1); ini_set('display_errors', 1); ini_set('log_errors', 0); + $verboseFile = false; + +} elseif ($mode == 'test') { + + error_reporting(-1); + ini_set('display_errors', 1); + ini_set('log_errors', 0); } else { errorPage("Unknown mode: $mode"); @@ -3290,23 +3357,22 @@ $refererHost = parse_url($referer, PHP_URL_HOST); if (!$allowHotlinking) { if ($passwordMatch) { ; // Always allow when password match + verbose("Hotlinking since passwordmatch"); } elseif ($passwordMatch === false) { errorPage("Hotlinking/leeching not allowed when password missmatch."); } elseif (!$referer) { errorPage("Hotlinking/leeching not allowed and referer is missing."); } elseif (strcmp($serverName, $refererHost) == 0) { ; // Allow when serverName matches refererHost + verbose("Hotlinking disallowed but serverName matches refererHost."); } elseif (!empty($hotlinkingWhitelist)) { + $whitelist = new CWhitelist(); + $allowedByWhitelist = $whitelist->check($refererHost, $hotlinkingWhitelist); - $allowedByWhitelist = false; - foreach ($hotlinkingWhitelist as $val) { - if (preg_match($val, $refererHost)) { - $allowedByWhitelist = true; - } - } - - if (!$allowedByWhitelist) { - errorPage("Hotlinking/leeching not allowed by whitelist."); + if ($allowedByWhitelist) { + verbose("Hotlinking/leeching allowed by whitelist."); + } else { + errorPage("Hotlinking/leeching not allowed by whitelist. Referer: $referer."); } } else { @@ -3338,7 +3404,7 @@ if ($autoloader) { * Create the class for the image. */ $img = new CImage(); -$img->setVerbose($verbose); +$img->setVerbose($verbose || $verboseFile); @@ -3858,6 +3924,13 @@ verbose("alias = $alias"); +/** + * Get the cachepath from config. + */ +$cachePath = getConfig('cache_path', __DIR__ . '/../cache/'); + + + /** * Display image if verbose mode */ @@ -3896,15 +3969,17 @@ EOD; /** - * Get the cachepath from config. + * Log verbose details to file */ -$cachePath = getConfig('cache_path', __DIR__ . '/../cache/'); +if ($verboseFile) { + $img->setVerboseToFile("$cachePath/log.txt"); +} -/** - * Load, process and output the image - */ + /** + * Load, process and output the image + */ $img->log("Incoming arguments: " . print_r(verbose(), 1)) ->setSaveFolder($cachePath) ->useCache($useCache)