1
0
mirror of https://github.com/mosbth/cimage.git synced 2025-08-28 09:59:54 +02:00

Compare commits

..

42 Commits

Author SHA1 Message Date
Mikael Roos
b44be78f06 Fix deprecation notice on "Creation of dynamic property" for PHP 8.2. 2023-10-27 10:20:16 +02:00
Mikael Roos
1056f0a5ee Spelling in README 2022-11-17 16:13:56 +01:00
Mikael Roos
1666ea1412 Build to prepare to tag 2022-11-17 16:08:48 +01:00
Mikael Roos
bb57af697b Remove build status from README (since it is not up to date) 2022-11-17 16:06:25 +01:00
Mikael Roos
55ce23ae5e Add fix for WINDOWS2WSL 2022-11-17 16:05:25 +01:00
Mikael Roos
4589b3b3cd Enable configuration fix for solving Windows 2 WSL2 issue with is_readable/is_writable #189 2022-11-17 15:40:43 +01:00
Mikael Roos
d5ca10cebc Add a webpage with links useful to test various aspects of img.php 2022-11-17 15:31:40 +01:00
Mikael Roos
9d7343a2df Merge pull request #188 from niciz/patch-1
Update CHttpGet.php for php 8.1 deprecated notice
2022-11-08 13:50:12 +01:00
niciz
3d7adcdbde Update CHttpGet.php for php 8.1 deprecated notice 2022-11-08 12:23:07 +01:00
Mikael Roos
80cd4e092f v0.8.4 (2022-05-30) 2022-05-30 15:32:20 +02:00
Mikael Roos
4c0ac8ed23 Support PHP 8.1 and remove deprecated messages when run in in development mode 2022-05-24 16:41:01 +02:00
Mikael Roos
39b86628db Generate prebuilt all include files for various settings 2022-05-24 16:38:48 +02:00
Mikael Roos
5f4280d387 Fix deprecated for PHP 8.1 2022-05-24 16:37:50 +02:00
Mikael Roos
dd315dbd21 Fix deprecated for PHP 8.1 2022-05-24 16:33:08 +02:00
Mikael Roos
493118e1c5 Add php version as output in verbose mode 2022-05-24 12:57:27 +02:00
Mikael Roos
e41b3d9877 Add PHP 81 as test environment 2022-05-24 12:57:08 +02:00
Mikael Roos
bb60001c36 Prepare to tag 2021-10-27 11:40:40 +02:00
Mikael Roos
adeca3f9f9 Prepare to tag 2021-10-27 11:40:18 +02:00
Mikael Roos
a5662690fe Remove bad configuration 2021-10-27 11:21:29 +02:00
Mikael Roos
3cfa9a6a98 Add htmlentities to escape input, fix #183 2021-09-13 08:17:47 +02:00
Mikael Roos
4ecebcd5b4 Add a security policy #183 2021-09-09 13:51:13 +02:00
Mikael Roos
9196d1ee41 Update the docker-compose.yaml to include PHP 8.0, #181 2021-05-10 16:01:23 +02:00
Mikael Roos
0249056761 Updated version number in define.php. 2020-06-08 12:38:44 +02:00
Mikael Roos
4ea72be49a Enable to set JPEG image as interlaced, implement feature #177. 2020-06-08 12:26:40 +02:00
Mikael Roos
2ce1f18fe5 Set PHP 7.0 as precondition (to prepare to update the codebase). 2020-06-08 12:26:01 +02:00
Mikael Roos
0f1f537b62 Add function getValue() to read from querystring. 2020-06-08 12:25:47 +02:00
Mikael Roos
1411adc828 Fix error in composer.json 2020-05-06 09:51:12 +02:00
Mikael Roos
86737af69e Update composer.json and move ext-gd from required to suggested to ease installation where cli does not have all extensions installed. 2020-05-06 09:06:46 +02:00
Mikael Roos
c563275ed5 Support PHP 7.4, some minor fixes with notices. 2020-01-15 16:51:39 +01:00
Mikael Roos
8fec09b195 Merge pull request #176 from SpaceLenore/patch-1
fixed markdown syntax
2018-10-28 19:08:45 +01:00
Lenore
ac16343cd7 fixed markdown syntax
added spaces so the markdown gets parsed correctly
2018-10-28 17:49:35 +01:00
Mikael Roos
cd142c5880 prepare to tag 2017-11-06 10:24:47 +01:00
Mikael Roos
91dd92d483 Remove webroot/img/{round8.PNG,wider.JPEG,wider.JPG} to avoid unzip warning message when installing with composer. 2017-11-06 10:24:16 +01:00
Mikael Roos
4b64d921d1 Adding docker-compose.yml #169. 2017-06-26 10:30:21 +02:00
Mikael Roos
4211d7e0e6 Adding docker-compose.yml #169. 2017-06-26 10:30:08 +02:00
Mikael Roos
dd8878c8bd add issue number 2017-03-31 00:55:38 +02:00
Mikael Roos
f9604518e4 prepare to tag v0.7.19 2017-03-31 00:47:55 +02:00
Mikael Roos
61aa52854e Move exception handler from functions.php to img.php. 2017-03-31 00:46:43 +02:00
Mikael Roos
401478c839 Correct XSS injection in check_system.php. 2016-08-31 15:26:14 +02:00
Mikael Roos
f0ab9479d6 read lena.tif, will need it in the future 2016-08-13 18:33:09 +02:00
Mikael Roos
9ff7a61ca9 remove tif version of lena 2016-08-13 17:49:36 +02:00
Mikael Roos
3170beb832 Composer suggests ext-imagick and ext-curl. 2016-08-11 17:39:45 +02:00
21 changed files with 664 additions and 192 deletions

View File

@@ -51,6 +51,15 @@ class CCache
return $path; return $path;
} }
if ($create && defined('WINDOWS2WSL')) {
// Special case to solve Windows 2 WSL integration
$path = $this->path . "/" . $subdir;
if (mkdir($path)) {
return realpath($path);
}
}
if ($create && is_writable($this->path)) { if ($create && is_writable($this->path)) {
$path = $this->path . "/" . $subdir; $path = $this->path . "/" . $subdir;

View File

@@ -215,7 +215,7 @@ class CHttpGet
{ {
$type = isset($this->response['header']['Content-Type']) $type = isset($this->response['header']['Content-Type'])
? $this->response['header']['Content-Type'] ? $this->response['header']['Content-Type']
: null; : '';
return preg_match('#[a-z]+/[a-z]+#', $type) return preg_match('#[a-z]+/[a-z]+#', $type)
? $type ? $type

View File

@@ -6,6 +6,7 @@
* @example http://dbwebb.se/opensource/cimage * @example http://dbwebb.se/opensource/cimage
* @link https://github.com/mosbth/cimage * @link https://github.com/mosbth/cimage
*/ */
#[AllowDynamicProperties]
class CImage class CImage
{ {
@@ -423,6 +424,13 @@ class CImage
/*
* Use interlaced progressive mode for JPEG images.
*/
private $interlace = false;
/* /*
* Image copy strategy, defaults to RESAMPLE. * Image copy strategy, defaults to RESAMPLE.
*/ */
@@ -672,9 +680,9 @@ class CImage
* *
* @return string $extension as a normalized file extension. * @return string $extension as a normalized file extension.
*/ */
private function normalizeFileExtension($extension = null) private function normalizeFileExtension($extension = "")
{ {
$extension = strtolower($extension ? $extension : $this->extension); $extension = strtolower($extension ? $extension : $this->extension ?? "");
if ($extension == 'jpeg') { if ($extension == 'jpeg') {
$extension = 'jpg'; $extension = 'jpg';
@@ -838,6 +846,7 @@ class CImage
'blur' => null, 'blur' => null,
'convolve' => null, 'convolve' => null,
'rotateAfter' => null, 'rotateAfter' => null,
'interlace' => null,
// Output format // Output format
'outputFormat' => null, 'outputFormat' => null,
@@ -956,8 +965,11 @@ class CImage
{ {
$file = $file ? $file : $this->pathToImage; $file = $file ? $file : $this->pathToImage;
// Special case to solve Windows 2 WSL integration
if (!defined('WINDOWS2WSL')) {
is_readable($file) is_readable($file)
or $this->raiseError('Image file does not exist.'); or $this->raiseError('Image file does not exist.');
}
$info = list($this->width, $this->height, $this->fileType) = getimagesize($file); $info = list($this->width, $this->height, $this->fileType) = getimagesize($file);
if (empty($info)) { if (empty($info)) {
@@ -1023,13 +1035,15 @@ class CImage
$this->log("Init dimension (before) newWidth x newHeight is {$this->newWidth} x {$this->newHeight}."); $this->log("Init dimension (before) newWidth x newHeight is {$this->newWidth} x {$this->newHeight}.");
// width as % // width as %
if ($this->newWidth[strlen($this->newWidth)-1] == '%') { if ($this->newWidth
&& $this->newWidth[strlen($this->newWidth)-1] == '%') {
$this->newWidth = $this->width * substr($this->newWidth, 0, -1) / 100; $this->newWidth = $this->width * substr($this->newWidth, 0, -1) / 100;
$this->log("Setting new width based on % to {$this->newWidth}"); $this->log("Setting new width based on % to {$this->newWidth}");
} }
// height as % // height as %
if ($this->newHeight[strlen($this->newHeight)-1] == '%') { if ($this->newHeight
&& $this->newHeight[strlen($this->newHeight)-1] == '%') {
$this->newHeight = $this->height * substr($this->newHeight, 0, -1) / 100; $this->newHeight = $this->height * substr($this->newHeight, 0, -1) / 100;
$this->log("Setting new height based on % to {$this->newHeight}"); $this->log("Setting new height based on % to {$this->newHeight}");
} }
@@ -1400,6 +1414,7 @@ class CImage
$rotateBefore = $this->rotateBefore ? "_rb{$this->rotateBefore}" : null; $rotateBefore = $this->rotateBefore ? "_rb{$this->rotateBefore}" : null;
$rotateAfter = $this->rotateAfter ? "_ra{$this->rotateAfter}" : null; $rotateAfter = $this->rotateAfter ? "_ra{$this->rotateAfter}" : null;
$lossy = $this->lossy ? "_l" : null; $lossy = $this->lossy ? "_l" : null;
$interlace = $this->interlace ? "_i" : null;
$saveAs = $this->normalizeFileExtension(); $saveAs = $this->normalizeFileExtension();
$saveAs = $saveAs ? "_$saveAs" : null; $saveAs = $saveAs ? "_$saveAs" : null;
@@ -1466,7 +1481,7 @@ class CImage
. $quality . $filters . $sharpen . $emboss . $blur . $palette . $quality . $filters . $sharpen . $emboss . $blur . $palette
. $optimize . $compress . $optimize . $compress
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor . $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor
. $convolve . $copyStrat . $lossy . $saveAs; . $convolve . $copyStrat . $lossy . $interlace . $saveAs;
return $this->setTarget($file, $base); return $this->setTarget($file, $base);
} }
@@ -2429,8 +2444,10 @@ class CImage
return; return;
} }
if (!defined("WINDOWS2WSL")) {
is_writable($this->saveFolder) is_writable($this->saveFolder)
or $this->raiseError('Target directory is not writable.'); or $this->raiseError('Target directory is not writable.');
}
$type = $this->getTargetImageExtension(); $type = $this->getTargetImageExtension();
$this->Log("Saving image as " . $type); $this->Log("Saving image as " . $type);
@@ -2438,6 +2455,12 @@ class CImage
case 'jpeg': case 'jpeg':
case 'jpg': case 'jpg':
// Set as interlaced progressive JPEG
if ($this->interlace) {
$this->Log("Set JPEG image to be interlaced.");
$res = imageinterlace($this->image, true);
}
$this->Log("Saving image as JPEG to cache using quality = {$this->quality}."); $this->Log("Saving image as JPEG to cache using quality = {$this->quality}.");
imagejpeg($this->image, $this->cacheFileName, $this->quality); imagejpeg($this->image, $this->cacheFileName, $this->quality);
@@ -2776,18 +2799,18 @@ class CImage
$lastModified = filemtime($this->pathToImage); $lastModified = filemtime($this->pathToImage);
$details['srcGmdate'] = gmdate("D, d M Y H:i:s", $lastModified); $details['srcGmdate'] = gmdate("D, d M Y H:i:s", $lastModified);
$details['cache'] = basename($this->cacheFileName); $details['cache'] = basename($this->cacheFileName ?? "");
$lastModified = filemtime($this->cacheFileName); $lastModified = filemtime($this->cacheFileName ?? "");
$details['cacheGmdate'] = gmdate("D, d M Y H:i:s", $lastModified); $details['cacheGmdate'] = gmdate("D, d M Y H:i:s", $lastModified);
$this->load($file); $this->load($file);
$details['filename'] = basename($file); $details['filename'] = basename($file ?? "");
$details['mimeType'] = $this->getMimeType($this->fileType); $details['mimeType'] = $this->getMimeType($this->fileType);
$details['width'] = $this->width; $details['width'] = $this->width;
$details['height'] = $this->height; $details['height'] = $this->height;
$details['aspectRatio'] = round($this->width / $this->height, 3); $details['aspectRatio'] = round($this->width / $this->height, 3);
$details['size'] = filesize($file); $details['size'] = filesize($file ?? "");
$details['colors'] = $this->colorsTotal($this->image); $details['colors'] = $this->colorsTotal($this->image);
$details['includedFiles'] = count(get_included_files()); $details['includedFiles'] = count(get_included_files());
$details['memoryPeek'] = round(memory_get_peak_usage()/1024/1024, 3) . " MB" ; $details['memoryPeek'] = round(memory_get_peak_usage()/1024/1024, 3) . " MB" ;

View File

@@ -2,8 +2,10 @@ Image conversion on the fly using PHP
===================================== =====================================
[![Join the chat at https://gitter.im/mosbth/cimage](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mosbth/cimage?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the chat at https://gitter.im/mosbth/cimage](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mosbth/cimage?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
<!--
[![Build Status](https://travis-ci.org/mosbth/cimage.svg?branch=master)](https://travis-ci.org/mosbth/cimage) [![Build Status](https://travis-ci.org/mosbth/cimage.svg?branch=master)](https://travis-ci.org/mosbth/cimage)
[![Build Status](https://scrutinizer-ci.com/g/mosbth/cimage/badges/build.png?b=master)](https://scrutinizer-ci.com/g/mosbth/cimage/build-status/master) [![Build Status](https://scrutinizer-ci.com/g/mosbth/cimage/badges/build.png?b=master)](https://scrutinizer-ci.com/g/mosbth/cimage/build-status/master)
-->
About About
------------------------------------- -------------------------------------

View File

@@ -1,8 +1,102 @@
Revision history Revision history
===================================== =====================================
<!--
[![Build Status](https://travis-ci.org/mosbth/cimage.svg?branch=master)](https://travis-ci.org/mosbth/cimage) [![Build Status](https://travis-ci.org/mosbth/cimage.svg?branch=master)](https://travis-ci.org/mosbth/cimage)
[![Build Status](https://scrutinizer-ci.com/g/mosbth/cimage/badges/build.png?b=master)](https://scrutinizer-ci.com/g/mosbth/cimage/build-status/master) [![Build Status](https://scrutinizer-ci.com/g/mosbth/cimage/badges/build.png?b=master)](https://scrutinizer-ci.com/g/mosbth/cimage/build-status/master)
--->
v0.8.6 (2023-10-27)
-------------------------------------
* Fix deprecation notice on "Creation of dynamic property" for PHP 8.2.
v0.8.5 (2022-11-17)
-------------------------------------
* Enable configuration fix for solving Windows 2 WSL2 issue with is_readable/is_writable #189.
* Update CHttpGet.php for php 8.1 deprecated notice #188.
* Remove build status from README (since it is not up to date).
v0.8.4 (2022-05-30)
-------------------------------------
* Support PHP 8.1 and remove (more) deprecated messages when run in in development mode.
v0.8.3 (2022-05-24)
-------------------------------------
* Support PHP 8.1 and remove deprecated messages when run in in development mode.
* Generate prebuilt all include files for various settings
* Fix deprecated for PHP 8.1
* Fix deprecated for PHP 8.1
* Add php version as output in verbose mode
* Add PHP 81 as test environment
v0.8.2 (2021-10-27)
-------------------------------------
* Remove bad configuration.
v0.8.1 (2020-06-08)
-------------------------------------
* Updated version number in define.php.
v0.8.0 (2020-06-08)
-------------------------------------
* Enable to set JPEG image as interlaced, implement feature #177.
* Add function getValue() to read from querystring.
* Set PHP 7.0 as precondition (to prepare to update the codebase).
v0.7.23 (2020-05-06)
-------------------------------------
* Fix error in composer.json
v0.7.22 (2020-05-06)
-------------------------------------
* Update composer.json and move ext-gd from required to suggested to ease installation where cli does not have all extensions installed.
v0.7.21 (2020-01-15)
-------------------------------------
* Support PHP 7.4, some minor fixes with notices.
v0.7.20 (2017-11-06)
-------------------------------------
* Remove webroot/img/{round8.PNG,wider.JPEG,wider.JPG} to avoid unzip warning message when installing with composer.
* Adding docker-compose.yml #169.
v0.7.19 (2017-03-31)
-------------------------------------
* Move exception handler from functions.php to img.php #166.
* Correct XSS injection in `check_system.php`.
* Composer suggests ext-imagick and ext-curl.
v0.7.18 (2016-08-09) v0.7.18 (2016-08-09)

6
SECURITY.md Normal file
View File

@@ -0,0 +1,6 @@
Security policy
======================
To report security vulnerabilities in the project, send en email to mikael.t.h.roos@gmail.com.
For other security related issues, please open an issue on the project.

View File

@@ -18,11 +18,13 @@
"docs": "http://dbwebb.se/opensource/cimage" "docs": "http://dbwebb.se/opensource/cimage"
}, },
"require": { "require": {
"php": ">=5.3", "php": ">=7.0"
"ext-gd": "*"
}, },
"suggest": { "suggest": {
"ext-exif": "*" "ext-curl": "*",
"ext-exif": "*",
"ext-gd": "*",
"ext-imagick": "*"
}, },
"autoload": { "autoload": {
"files": [ "files": [

View File

@@ -1,6 +1,6 @@
<?php <?php
// Version of cimage and img.php // Version of cimage and img.php
define("CIMAGE_VERSION", "v0.7.18 (2016-08-09)"); define("CIMAGE_VERSION", "v0.8.6 (2023-10-27)");
// For CRemoteImage // For CRemoteImage
define("CIMAGE_USER_AGENT", "CImage/" . CIMAGE_VERSION); define("CIMAGE_USER_AGENT", "CImage/" . CIMAGE_VERSION);

97
docker-compose.yaml Normal file
View File

@@ -0,0 +1,97 @@
version: "3"
services:
cli:
image: anax/dev
volumes: [ ".:/home/anax/repo" ]
apache:
image: anax/dev:apache
volumes: [ ".:/home/anax/repo" ]
ports: [ "11000:80" ]
remserver:
image: anax/dev:apache
ports:
- "8090:80"
volumes: [ ".:/home/anax/repo" ]
php82:
image: anax/dev:php82
volumes: [ ".:/home/anax/repo" ]
php82-apache:
image: anax/dev:php82-apache
ports: [ "11082:80" ]
volumes: [ ".:/home/anax/repo" ]
php81:
image: anax/dev:php81
volumes: [ ".:/home/anax/repo" ]
php81-apache:
image: anax/dev:php81-apache
ports: [ "11081:80" ]
volumes: [ ".:/home/anax/repo" ]
php80:
image: anax/dev:php80
volumes: [ ".:/home/anax/repo" ]
php80-apache:
image: anax/dev:php80-apache
ports: [ "11080:80" ]
volumes: [ ".:/home/anax/repo" ]
php74:
image: anax/dev:php74
volumes: [ ".:/home/anax/repo" ]
php74-apache:
image: anax/dev:php74-apache
ports: [ "11074:80" ]
volumes: [ ".:/home/anax/repo" ]
php73:
image: anax/dev:php73
volumes: [ ".:/home/anax/repo" ]
php73-apache:
image: anax/dev:php73-apache
ports: [ "11073:80" ]
volumes: [ ".:/home/anax/repo" ]
php72:
image: anax/dev:php72
volumes: [ ".:/home/anax/repo" ]
php72-apache:
image: anax/dev:php72-apache
ports: [ "11072:80" ]
volumes: [ ".:/home/anax/repo" ]
php71:
image: anax/dev:php71
volumes: [ ".:/home/anax/repo" ]
php71-apache:
image: anax/dev:php71-apache
ports: [ "11071:80" ]
volumes: [ ".:/home/anax/repo" ]
php70:
image: anax/dev:php70
volumes: [ ".:/home/anax/repo" ]
php70:
image: anax/dev:php70-apache
ports: [ "11070:80" ]
volumes: [ ".:/home/anax/repo" ]
php56:
image: anax/dev:php56
volumes: [ ".:/home/anax/repo" ]
php56:
image: anax/dev:php56-apache
ports: [ "11056:80" ]
volumes: [ ".:/home/anax/repo" ]

View File

@@ -67,22 +67,6 @@ function errorPage($msg, $type = 500)
/**
* Custom exception handler.
*/
set_exception_handler(function ($exception) {
errorPage(
"<p><b>img.php: Uncaught exception:</b> <p>"
. $exception->getMessage()
. "</p><pre>"
. $exception->getTraceAsString()
. "</pre>",
500
);
});
/** /**
* Get input from query string or return default value if not set. * Get input from query string or return default value if not set.
* *
@@ -123,6 +107,25 @@ function getDefined($key, $defined, $undefined)
/**
* Get value of input from query string or else $undefined.
*
* @param mixed $key as string or array of string values to look for in $_GET.
* @param mixed $undefined value to return when $key has no, or empty value in $_GET.
*
* @return mixed value as or $undefined.
*/
function getValue($key, $undefined)
{
$val = get($key);
if (is_null($val) || $val === "") {
return $undefined;
}
return $val;
}
/** /**
* Get value from config array or default if key is not set in config array. * Get value from config array or default if key is not set in config array.
* *
@@ -148,7 +151,7 @@ function getConfig($key, $default)
* *
* @return void or array. * @return void or array.
*/ */
function verbose($msg = null) function verbose($msg = null, $arg = "")
{ {
global $verbose, $verboseFile; global $verbose, $verboseFile;
static $log = array(); static $log = array();
@@ -161,7 +164,15 @@ function verbose($msg = null)
return $log; return $log;
} }
$log[] = $msg; if (is_null($arg)) {
$arg = "null";
} elseif ($arg === false) {
$arg = "false";
} elseif ($arg === true) {
$arg = "true";
}
$log[] = $msg . $arg;
} }

View File

@@ -2,7 +2,7 @@
echo 'Current PHP version: ' . phpversion() . '<br><br>'; echo 'Current PHP version: ' . phpversion() . '<br><br>';
echo 'Running on: ' . $_SERVER['SERVER_SOFTWARE'] . '<br><br>'; echo 'Running on: ' . htmlentities($_SERVER['SERVER_SOFTWARE']) . '<br><br>';
$no = extension_loaded('exif') ? null : 'NOT'; $no = extension_loaded('exif') ? null : 'NOT';
echo "Extension exif is $no loaded.<br>"; echo "Extension exif is $no loaded.<br>";

View File

@@ -3,6 +3,12 @@
<head> <head>
<style> <style>
<?php
function e($str) {
return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}
?>
body { body {
} }
@@ -128,15 +134,15 @@ if (isset($_GET['input1'])) {
// Use incoming from querystring as defaults // Use incoming from querystring as defaults
?> ?>
CImage.compare({ CImage.compare({
"input1": "<?=$_GET['input1']?>", "input1": "<?=e($_GET['input1'])?>",
"input2": "<?=$_GET['input2']?>", "input2": "<?=e($_GET['input2'])?>",
"input3": "<?=$_GET['input3']?>", "input3": "<?=e($_GET['input3'])?>",
"input4": "<?=$_GET['input4']?>", "input4": "<?=e($_GET['input4'])?>",
"input5": "<?=$_GET['input5']?>", "input5": "<?=e($_GET['input5'])?>",
"input6": "<?=$_GET['input6']?>", "input6": "<?=e($_GET['input6'])?>",
"json": <?=$_GET['json']?>, "json": <?=e($_GET['json'])?>,
"stack": <?=$_GET['stack']?>, "stack": <?=e($_GET['stack'])?>,
"bg": <?=$_GET['bg']?> "bg": <?=e($_GET['bg'])?>
}); });
<?php <?php
} elseif (isset($script)) { } elseif (isset($script)) {

View File

@@ -8,6 +8,22 @@
* *
*/ */
/**
* Custom exception handler.
*/
set_exception_handler(function ($exception) {
errorPage(
"<p><b>img.php: Uncaught exception:</b> <p>"
. $exception->getMessage()
. "</p><pre>"
. $exception->getTraceAsString()
. "</pre>",
500
);
});
/** /**
* Get configuration options from file, if the file exists, else use $config * Get configuration options from file, if the file exists, else use $config
* if its defined or create an empty $config. * if its defined or create an empty $config.
@@ -170,7 +186,7 @@ $hotlinkingWhitelist = getConfig('hotlinking_whitelist', array());
$serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null; $serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null;
$referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null; $referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
$refererHost = parse_url($referer, PHP_URL_HOST); $refererHost = parse_url($referer ?? "", PHP_URL_HOST);
if (!$allowHotlinking) { if (!$allowHotlinking) {
if ($passwordMatch) { if ($passwordMatch) {
@@ -303,11 +319,11 @@ if (isset($shortcut)
/** /**
* src - the source image file. * src - the source image file.
*/ */
$srcImage = urldecode(get('src')) $srcImage = urldecode(get('src', ""))
or errorPage('Must set src-attribute.', 404); or errorPage('Must set src-attribute.', 404);
// Get settings for src-alt as backup image // Get settings for src-alt as backup image
$srcAltImage = urldecode(get('src-alt', null)); $srcAltImage = urldecode(get('src-alt', ""));
$srcAltConfig = getConfig('src_alt', null); $srcAltConfig = getConfig('src_alt', null);
if (empty($srcAltImage)) { if (empty($srcAltImage)) {
$srcAltImage = $srcAltConfig; $srcAltImage = $srcAltConfig;
@@ -424,7 +440,7 @@ if (isset($sizes[$newWidth])) {
} }
// Support width as % of original width // Support width as % of original width
if ($newWidth[strlen($newWidth)-1] == '%') { if ($newWidth && $newWidth[strlen($newWidth)-1] == '%') {
is_numeric(substr($newWidth, 0, -1)) is_numeric(substr($newWidth, 0, -1))
or errorPage('Width % not numeric.', 404); or errorPage('Width % not numeric.', 404);
} else { } else {
@@ -449,7 +465,7 @@ if (isset($sizes[$newHeight])) {
} }
// height // height
if ($newHeight[strlen($newHeight)-1] == '%') { if ($newHeight && $newHeight[strlen($newHeight)-1] == '%') {
is_numeric(substr($newHeight, 0, -1)) is_numeric(substr($newHeight, 0, -1))
or errorPage('Height % out of range.', 404); or errorPage('Height % out of range.', 404);
} else { } else {
@@ -480,7 +496,7 @@ $aspectRatioConstant = getConfig('aspect_ratio_constant', function () {
// Check to replace predefined aspect ratio // Check to replace predefined aspect ratio
$aspectRatios = call_user_func($aspectRatioConstant); $aspectRatios = call_user_func($aspectRatioConstant);
$negateAspectRatio = ($aspectRatio[0] == '!') ? true : false; $negateAspectRatio = ($aspectRatio && $aspectRatio[0] == '!') ? true : false;
$aspectRatio = $negateAspectRatio ? substr($aspectRatio, 1) : $aspectRatio; $aspectRatio = $negateAspectRatio ? substr($aspectRatio, 1) : $aspectRatio;
if (isset($aspectRatios[$aspectRatio])) { if (isset($aspectRatios[$aspectRatio])) {
@@ -904,6 +920,18 @@ if ($cacheControl) {
/**
* interlace - Enable configuration for interlaced progressive JPEG images.
*/
$interlaceConfig = getConfig('interlace', null);
$interlaceValue = getValue('interlace', null);
$interlaceDefined = getDefined('interlace', true, null);
$interlace = $interlaceValue ?? $interlaceDefined ?? $interlaceConfig;
verbose("interlace (configfile) = ", $interlaceConfig);
verbose("interlace = ", $interlace);
/** /**
* Prepare a dummy image and use it as source image. * Prepare a dummy image and use it as source image.
*/ */
@@ -1065,6 +1093,7 @@ if (is_callable($hookBeforeCImage)) {
'blur' => $blur, 'blur' => $blur,
'convolve' => $convolve, 'convolve' => $convolve,
'rotateAfter' => $rotateAfter, 'rotateAfter' => $rotateAfter,
'interlace' => $interlace,
// Output format // Output format
'outputFormat' => $outputFormat, 'outputFormat' => $outputFormat,
@@ -1120,7 +1149,8 @@ EOD;
/** /**
* Load, process and output the image * Load, process and output the image
*/ */
$img->log("Incoming arguments: " . print_r(verbose(), 1)) $img->log("PHP version: " . phpversion())
->log("Incoming arguments: " . print_r(verbose(), 1))
->setSaveFolder($cachePath) ->setSaveFolder($cachePath)
->useCache($useCache) ->useCache($useCache)
->setSource($srcImage, $imagePath) ->setSource($srcImage, $imagePath)
@@ -1153,6 +1183,7 @@ $img->log("Incoming arguments: " . print_r(verbose(), 1))
'blur' => $blur, 'blur' => $blur,
'convolve' => $convolve, 'convolve' => $convolve,
'rotateAfter' => $rotateAfter, 'rotateAfter' => $rotateAfter,
'interlace' => $interlace,
// Output format // Output format
'outputFormat' => $outputFormat, 'outputFormat' => $outputFormat,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

View File

@@ -21,6 +21,15 @@ if (!defined("CIMAGE_DEBUG")) {
define("CIMAGE_DEBUG_FILE", "/tmp/cimage"); define("CIMAGE_DEBUG_FILE", "/tmp/cimage");
} }
/**
* Set this if you work with a webserver in Windows and try to access files
* within WSL2.
* The issue seems to be with functions like `is_writable()` and
* `is_readable()`.
* When WINDOWS2WSL is defined (to any value) it ignores these functions.
*/
#define('WINDOWS2WSL', 1);
return array( return array(
@@ -41,7 +50,7 @@ return array(
* mode: 'production' * mode: 'production'
*/ */
//'mode' => 'production', //'mode' => 'production',
//'mode' => 'development', 'mode' => 'development',
//'mode' => 'strict', //'mode' => 'strict',
@@ -67,7 +76,7 @@ return array(
*/ */
'image_path' => __DIR__ . '/img/', 'image_path' => __DIR__ . '/img/',
'cache_path' => __DIR__ . '/../cache/', 'cache_path' => __DIR__ . '/../cache/',
//'alias_path' => __DIR__ . '/img/alias/', 'alias_path' => __DIR__ . '/img/alias/',
@@ -116,7 +125,7 @@ return array(
* password_type: 'text' // use plain password, not encoded, * password_type: 'text' // use plain password, not encoded,
*/ */
//'password_always' => false, // always require password, //'password_always' => false, // always require password,
//'password' => false, // "secret-password", //'password' => "moped", // "secret-password",
//'password_type' => 'text', // supports 'text', 'md5', 'hash', //'password_type' => 'text', // supports 'text', 'md5', 'hash',
@@ -485,6 +494,18 @@ return array(
"scale" => 14, "scale" => 14,
"luminanceStrategy" => 3, "luminanceStrategy" => 3,
"customCharacterSet" => null, "customCharacterSet" => null,
); ), */
},*/
/**
* Default options for creating interlaced progressive JPEG images. Set
* to true to always render jpeg images as interlaced. This setting can
* be overridden by using `?interlace`, `?interlace=true` or
* `?interlace=false`.
*
* Default values are:
* interlace: false
*/
/*'interlace' => false,*/
); );

View File

@@ -38,7 +38,7 @@ $config = array(
// Version of cimage and img.php // Version of cimage and img.php
define("CIMAGE_VERSION", "v0.7.18 (2016-08-09)"); define("CIMAGE_VERSION", "v0.8.6 (2023-10-27)");
// For CRemoteImage // For CRemoteImage
define("CIMAGE_USER_AGENT", "CImage/" . CIMAGE_VERSION); define("CIMAGE_USER_AGENT", "CImage/" . CIMAGE_VERSION);
@@ -118,22 +118,6 @@ function errorPage($msg, $type = 500)
/**
* Custom exception handler.
*/
set_exception_handler(function ($exception) {
errorPage(
"<p><b>img.php: Uncaught exception:</b> <p>"
. $exception->getMessage()
. "</p><pre>"
. $exception->getTraceAsString()
. "</pre>",
500
);
});
/** /**
* Get input from query string or return default value if not set. * Get input from query string or return default value if not set.
* *
@@ -174,6 +158,25 @@ function getDefined($key, $defined, $undefined)
/**
* Get value of input from query string or else $undefined.
*
* @param mixed $key as string or array of string values to look for in $_GET.
* @param mixed $undefined value to return when $key has no, or empty value in $_GET.
*
* @return mixed value as or $undefined.
*/
function getValue($key, $undefined)
{
$val = get($key);
if (is_null($val) || $val === "") {
return $undefined;
}
return $val;
}
/** /**
* Get value from config array or default if key is not set in config array. * Get value from config array or default if key is not set in config array.
* *
@@ -199,7 +202,7 @@ function getConfig($key, $default)
* *
* @return void or array. * @return void or array.
*/ */
function verbose($msg = null) function verbose($msg = null, $arg = "")
{ {
global $verbose, $verboseFile; global $verbose, $verboseFile;
static $log = array(); static $log = array();
@@ -212,7 +215,15 @@ function verbose($msg = null)
return $log; return $log;
} }
$log[] = $msg; if (is_null($arg)) {
$arg = "null";
} elseif ($arg === false) {
$arg = "false";
} elseif ($arg === true) {
$arg = "true";
}
$log[] = $msg . $arg;
} }
@@ -454,7 +465,7 @@ class CHttpGet
{ {
$type = isset($this->response['header']['Content-Type']) $type = isset($this->response['header']['Content-Type'])
? $this->response['header']['Content-Type'] ? $this->response['header']['Content-Type']
: null; : '';
return preg_match('#[a-z]+/[a-z]+#', $type) return preg_match('#[a-z]+/[a-z]+#', $type)
? $type ? $type
@@ -1132,6 +1143,7 @@ class CAsciiArt
* @example http://dbwebb.se/opensource/cimage * @example http://dbwebb.se/opensource/cimage
* @link https://github.com/mosbth/cimage * @link https://github.com/mosbth/cimage
*/ */
#[AllowDynamicProperties]
class CImage class CImage
{ {
@@ -1549,6 +1561,13 @@ class CImage
/*
* Use interlaced progressive mode for JPEG images.
*/
private $interlace = false;
/* /*
* Image copy strategy, defaults to RESAMPLE. * Image copy strategy, defaults to RESAMPLE.
*/ */
@@ -1798,9 +1817,9 @@ class CImage
* *
* @return string $extension as a normalized file extension. * @return string $extension as a normalized file extension.
*/ */
private function normalizeFileExtension($extension = null) private function normalizeFileExtension($extension = "")
{ {
$extension = strtolower($extension ? $extension : $this->extension); $extension = strtolower($extension ? $extension : $this->extension ?? "");
if ($extension == 'jpeg') { if ($extension == 'jpeg') {
$extension = 'jpg'; $extension = 'jpg';
@@ -1964,6 +1983,7 @@ class CImage
'blur' => null, 'blur' => null,
'convolve' => null, 'convolve' => null,
'rotateAfter' => null, 'rotateAfter' => null,
'interlace' => null,
// Output format // Output format
'outputFormat' => null, 'outputFormat' => null,
@@ -2082,8 +2102,11 @@ class CImage
{ {
$file = $file ? $file : $this->pathToImage; $file = $file ? $file : $this->pathToImage;
// Special case to solve Windows 2 WSL integration
if (!defined('WINDOWS2WSL')) {
is_readable($file) is_readable($file)
or $this->raiseError('Image file does not exist.'); or $this->raiseError('Image file does not exist.');
}
$info = list($this->width, $this->height, $this->fileType) = getimagesize($file); $info = list($this->width, $this->height, $this->fileType) = getimagesize($file);
if (empty($info)) { if (empty($info)) {
@@ -2149,13 +2172,15 @@ class CImage
$this->log("Init dimension (before) newWidth x newHeight is {$this->newWidth} x {$this->newHeight}."); $this->log("Init dimension (before) newWidth x newHeight is {$this->newWidth} x {$this->newHeight}.");
// width as % // width as %
if ($this->newWidth[strlen($this->newWidth)-1] == '%') { if ($this->newWidth
&& $this->newWidth[strlen($this->newWidth)-1] == '%') {
$this->newWidth = $this->width * substr($this->newWidth, 0, -1) / 100; $this->newWidth = $this->width * substr($this->newWidth, 0, -1) / 100;
$this->log("Setting new width based on % to {$this->newWidth}"); $this->log("Setting new width based on % to {$this->newWidth}");
} }
// height as % // height as %
if ($this->newHeight[strlen($this->newHeight)-1] == '%') { if ($this->newHeight
&& $this->newHeight[strlen($this->newHeight)-1] == '%') {
$this->newHeight = $this->height * substr($this->newHeight, 0, -1) / 100; $this->newHeight = $this->height * substr($this->newHeight, 0, -1) / 100;
$this->log("Setting new height based on % to {$this->newHeight}"); $this->log("Setting new height based on % to {$this->newHeight}");
} }
@@ -2526,6 +2551,7 @@ class CImage
$rotateBefore = $this->rotateBefore ? "_rb{$this->rotateBefore}" : null; $rotateBefore = $this->rotateBefore ? "_rb{$this->rotateBefore}" : null;
$rotateAfter = $this->rotateAfter ? "_ra{$this->rotateAfter}" : null; $rotateAfter = $this->rotateAfter ? "_ra{$this->rotateAfter}" : null;
$lossy = $this->lossy ? "_l" : null; $lossy = $this->lossy ? "_l" : null;
$interlace = $this->interlace ? "_i" : null;
$saveAs = $this->normalizeFileExtension(); $saveAs = $this->normalizeFileExtension();
$saveAs = $saveAs ? "_$saveAs" : null; $saveAs = $saveAs ? "_$saveAs" : null;
@@ -2592,7 +2618,7 @@ class CImage
. $quality . $filters . $sharpen . $emboss . $blur . $palette . $quality . $filters . $sharpen . $emboss . $blur . $palette
. $optimize . $compress . $optimize . $compress
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor . $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor
. $convolve . $copyStrat . $lossy . $saveAs; . $convolve . $copyStrat . $lossy . $interlace . $saveAs;
return $this->setTarget($file, $base); return $this->setTarget($file, $base);
} }
@@ -3555,8 +3581,10 @@ class CImage
return; return;
} }
if (!defined("WINDOWS2WSL")) {
is_writable($this->saveFolder) is_writable($this->saveFolder)
or $this->raiseError('Target directory is not writable.'); or $this->raiseError('Target directory is not writable.');
}
$type = $this->getTargetImageExtension(); $type = $this->getTargetImageExtension();
$this->Log("Saving image as " . $type); $this->Log("Saving image as " . $type);
@@ -3564,6 +3592,12 @@ class CImage
case 'jpeg': case 'jpeg':
case 'jpg': case 'jpg':
// Set as interlaced progressive JPEG
if ($this->interlace) {
$this->Log("Set JPEG image to be interlaced.");
$res = imageinterlace($this->image, true);
}
$this->Log("Saving image as JPEG to cache using quality = {$this->quality}."); $this->Log("Saving image as JPEG to cache using quality = {$this->quality}.");
imagejpeg($this->image, $this->cacheFileName, $this->quality); imagejpeg($this->image, $this->cacheFileName, $this->quality);
@@ -3902,18 +3936,18 @@ class CImage
$lastModified = filemtime($this->pathToImage); $lastModified = filemtime($this->pathToImage);
$details['srcGmdate'] = gmdate("D, d M Y H:i:s", $lastModified); $details['srcGmdate'] = gmdate("D, d M Y H:i:s", $lastModified);
$details['cache'] = basename($this->cacheFileName); $details['cache'] = basename($this->cacheFileName ?? "");
$lastModified = filemtime($this->cacheFileName); $lastModified = filemtime($this->cacheFileName ?? "");
$details['cacheGmdate'] = gmdate("D, d M Y H:i:s", $lastModified); $details['cacheGmdate'] = gmdate("D, d M Y H:i:s", $lastModified);
$this->load($file); $this->load($file);
$details['filename'] = basename($file); $details['filename'] = basename($file ?? "");
$details['mimeType'] = $this->getMimeType($this->fileType); $details['mimeType'] = $this->getMimeType($this->fileType);
$details['width'] = $this->width; $details['width'] = $this->width;
$details['height'] = $this->height; $details['height'] = $this->height;
$details['aspectRatio'] = round($this->width / $this->height, 3); $details['aspectRatio'] = round($this->width / $this->height, 3);
$details['size'] = filesize($file); $details['size'] = filesize($file ?? "");
$details['colors'] = $this->colorsTotal($this->image); $details['colors'] = $this->colorsTotal($this->image);
$details['includedFiles'] = count(get_included_files()); $details['includedFiles'] = count(get_included_files());
$details['memoryPeek'] = round(memory_get_peak_usage()/1024/1024, 3) . " MB" ; $details['memoryPeek'] = round(memory_get_peak_usage()/1024/1024, 3) . " MB" ;
@@ -4112,6 +4146,15 @@ class CCache
return $path; return $path;
} }
if ($create && defined('WINDOWS2WSL')) {
// Special case to solve Windows 2 WSL integration
$path = $this->path . "/" . $subdir;
if (mkdir($path)) {
return realpath($path);
}
}
if ($create && is_writable($this->path)) { if ($create && is_writable($this->path)) {
$path = $this->path . "/" . $subdir; $path = $this->path . "/" . $subdir;
@@ -4418,6 +4461,22 @@ class CFastTrackCache
* *
*/ */
/**
* Custom exception handler.
*/
set_exception_handler(function ($exception) {
errorPage(
"<p><b>img.php: Uncaught exception:</b> <p>"
. $exception->getMessage()
. "</p><pre>"
. $exception->getTraceAsString()
. "</pre>",
500
);
});
/** /**
* Get configuration options from file, if the file exists, else use $config * Get configuration options from file, if the file exists, else use $config
* if its defined or create an empty $config. * if its defined or create an empty $config.
@@ -4580,7 +4639,7 @@ $hotlinkingWhitelist = getConfig('hotlinking_whitelist', array());
$serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null; $serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null;
$referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null; $referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
$refererHost = parse_url($referer, PHP_URL_HOST); $refererHost = parse_url($referer ?? "", PHP_URL_HOST);
if (!$allowHotlinking) { if (!$allowHotlinking) {
if ($passwordMatch) { if ($passwordMatch) {
@@ -4713,11 +4772,11 @@ if (isset($shortcut)
/** /**
* src - the source image file. * src - the source image file.
*/ */
$srcImage = urldecode(get('src')) $srcImage = urldecode(get('src', ""))
or errorPage('Must set src-attribute.', 404); or errorPage('Must set src-attribute.', 404);
// Get settings for src-alt as backup image // Get settings for src-alt as backup image
$srcAltImage = urldecode(get('src-alt', null)); $srcAltImage = urldecode(get('src-alt', ""));
$srcAltConfig = getConfig('src_alt', null); $srcAltConfig = getConfig('src_alt', null);
if (empty($srcAltImage)) { if (empty($srcAltImage)) {
$srcAltImage = $srcAltConfig; $srcAltImage = $srcAltConfig;
@@ -4834,7 +4893,7 @@ if (isset($sizes[$newWidth])) {
} }
// Support width as % of original width // Support width as % of original width
if ($newWidth[strlen($newWidth)-1] == '%') { if ($newWidth && $newWidth[strlen($newWidth)-1] == '%') {
is_numeric(substr($newWidth, 0, -1)) is_numeric(substr($newWidth, 0, -1))
or errorPage('Width % not numeric.', 404); or errorPage('Width % not numeric.', 404);
} else { } else {
@@ -4859,7 +4918,7 @@ if (isset($sizes[$newHeight])) {
} }
// height // height
if ($newHeight[strlen($newHeight)-1] == '%') { if ($newHeight && $newHeight[strlen($newHeight)-1] == '%') {
is_numeric(substr($newHeight, 0, -1)) is_numeric(substr($newHeight, 0, -1))
or errorPage('Height % out of range.', 404); or errorPage('Height % out of range.', 404);
} else { } else {
@@ -4890,7 +4949,7 @@ $aspectRatioConstant = getConfig('aspect_ratio_constant', function () {
// Check to replace predefined aspect ratio // Check to replace predefined aspect ratio
$aspectRatios = call_user_func($aspectRatioConstant); $aspectRatios = call_user_func($aspectRatioConstant);
$negateAspectRatio = ($aspectRatio[0] == '!') ? true : false; $negateAspectRatio = ($aspectRatio && $aspectRatio[0] == '!') ? true : false;
$aspectRatio = $negateAspectRatio ? substr($aspectRatio, 1) : $aspectRatio; $aspectRatio = $negateAspectRatio ? substr($aspectRatio, 1) : $aspectRatio;
if (isset($aspectRatios[$aspectRatio])) { if (isset($aspectRatios[$aspectRatio])) {
@@ -5314,6 +5373,18 @@ if ($cacheControl) {
/**
* interlace - Enable configuration for interlaced progressive JPEG images.
*/
$interlaceConfig = getConfig('interlace', null);
$interlaceValue = getValue('interlace', null);
$interlaceDefined = getDefined('interlace', true, null);
$interlace = $interlaceValue ?? $interlaceDefined ?? $interlaceConfig;
verbose("interlace (configfile) = ", $interlaceConfig);
verbose("interlace = ", $interlace);
/** /**
* Prepare a dummy image and use it as source image. * Prepare a dummy image and use it as source image.
*/ */
@@ -5475,6 +5546,7 @@ if (is_callable($hookBeforeCImage)) {
'blur' => $blur, 'blur' => $blur,
'convolve' => $convolve, 'convolve' => $convolve,
'rotateAfter' => $rotateAfter, 'rotateAfter' => $rotateAfter,
'interlace' => $interlace,
// Output format // Output format
'outputFormat' => $outputFormat, 'outputFormat' => $outputFormat,
@@ -5530,7 +5602,8 @@ EOD;
/** /**
* Load, process and output the image * Load, process and output the image
*/ */
$img->log("Incoming arguments: " . print_r(verbose(), 1)) $img->log("PHP version: " . phpversion())
->log("Incoming arguments: " . print_r(verbose(), 1))
->setSaveFolder($cachePath) ->setSaveFolder($cachePath)
->useCache($useCache) ->useCache($useCache)
->setSource($srcImage, $imagePath) ->setSource($srcImage, $imagePath)
@@ -5563,6 +5636,7 @@ $img->log("Incoming arguments: " . print_r(verbose(), 1))
'blur' => $blur, 'blur' => $blur,
'convolve' => $convolve, 'convolve' => $convolve,
'rotateAfter' => $rotateAfter, 'rotateAfter' => $rotateAfter,
'interlace' => $interlace,
// Output format // Output format
'outputFormat' => $outputFormat, 'outputFormat' => $outputFormat,

View File

@@ -38,7 +38,7 @@ $config = array(
// Version of cimage and img.php // Version of cimage and img.php
define("CIMAGE_VERSION", "v0.7.18 (2016-08-09)"); define("CIMAGE_VERSION", "v0.8.6 (2023-10-27)");
// For CRemoteImage // For CRemoteImage
define("CIMAGE_USER_AGENT", "CImage/" . CIMAGE_VERSION); define("CIMAGE_USER_AGENT", "CImage/" . CIMAGE_VERSION);
@@ -118,22 +118,6 @@ function errorPage($msg, $type = 500)
/**
* Custom exception handler.
*/
set_exception_handler(function ($exception) {
errorPage(
"<p><b>img.php: Uncaught exception:</b> <p>"
. $exception->getMessage()
. "</p><pre>"
. $exception->getTraceAsString()
. "</pre>",
500
);
});
/** /**
* Get input from query string or return default value if not set. * Get input from query string or return default value if not set.
* *
@@ -174,6 +158,25 @@ function getDefined($key, $defined, $undefined)
/**
* Get value of input from query string or else $undefined.
*
* @param mixed $key as string or array of string values to look for in $_GET.
* @param mixed $undefined value to return when $key has no, or empty value in $_GET.
*
* @return mixed value as or $undefined.
*/
function getValue($key, $undefined)
{
$val = get($key);
if (is_null($val) || $val === "") {
return $undefined;
}
return $val;
}
/** /**
* Get value from config array or default if key is not set in config array. * Get value from config array or default if key is not set in config array.
* *
@@ -199,7 +202,7 @@ function getConfig($key, $default)
* *
* @return void or array. * @return void or array.
*/ */
function verbose($msg = null) function verbose($msg = null, $arg = "")
{ {
global $verbose, $verboseFile; global $verbose, $verboseFile;
static $log = array(); static $log = array();
@@ -212,7 +215,15 @@ function verbose($msg = null)
return $log; return $log;
} }
$log[] = $msg; if (is_null($arg)) {
$arg = "null";
} elseif ($arg === false) {
$arg = "false";
} elseif ($arg === true) {
$arg = "true";
}
$log[] = $msg . $arg;
} }
@@ -454,7 +465,7 @@ class CHttpGet
{ {
$type = isset($this->response['header']['Content-Type']) $type = isset($this->response['header']['Content-Type'])
? $this->response['header']['Content-Type'] ? $this->response['header']['Content-Type']
: null; : '';
return preg_match('#[a-z]+/[a-z]+#', $type) return preg_match('#[a-z]+/[a-z]+#', $type)
? $type ? $type
@@ -1132,6 +1143,7 @@ class CAsciiArt
* @example http://dbwebb.se/opensource/cimage * @example http://dbwebb.se/opensource/cimage
* @link https://github.com/mosbth/cimage * @link https://github.com/mosbth/cimage
*/ */
#[AllowDynamicProperties]
class CImage class CImage
{ {
@@ -1549,6 +1561,13 @@ class CImage
/*
* Use interlaced progressive mode for JPEG images.
*/
private $interlace = false;
/* /*
* Image copy strategy, defaults to RESAMPLE. * Image copy strategy, defaults to RESAMPLE.
*/ */
@@ -1798,9 +1817,9 @@ class CImage
* *
* @return string $extension as a normalized file extension. * @return string $extension as a normalized file extension.
*/ */
private function normalizeFileExtension($extension = null) private function normalizeFileExtension($extension = "")
{ {
$extension = strtolower($extension ? $extension : $this->extension); $extension = strtolower($extension ? $extension : $this->extension ?? "");
if ($extension == 'jpeg') { if ($extension == 'jpeg') {
$extension = 'jpg'; $extension = 'jpg';
@@ -1964,6 +1983,7 @@ class CImage
'blur' => null, 'blur' => null,
'convolve' => null, 'convolve' => null,
'rotateAfter' => null, 'rotateAfter' => null,
'interlace' => null,
// Output format // Output format
'outputFormat' => null, 'outputFormat' => null,
@@ -2082,8 +2102,11 @@ class CImage
{ {
$file = $file ? $file : $this->pathToImage; $file = $file ? $file : $this->pathToImage;
// Special case to solve Windows 2 WSL integration
if (!defined('WINDOWS2WSL')) {
is_readable($file) is_readable($file)
or $this->raiseError('Image file does not exist.'); or $this->raiseError('Image file does not exist.');
}
$info = list($this->width, $this->height, $this->fileType) = getimagesize($file); $info = list($this->width, $this->height, $this->fileType) = getimagesize($file);
if (empty($info)) { if (empty($info)) {
@@ -2149,13 +2172,15 @@ class CImage
$this->log("Init dimension (before) newWidth x newHeight is {$this->newWidth} x {$this->newHeight}."); $this->log("Init dimension (before) newWidth x newHeight is {$this->newWidth} x {$this->newHeight}.");
// width as % // width as %
if ($this->newWidth[strlen($this->newWidth)-1] == '%') { if ($this->newWidth
&& $this->newWidth[strlen($this->newWidth)-1] == '%') {
$this->newWidth = $this->width * substr($this->newWidth, 0, -1) / 100; $this->newWidth = $this->width * substr($this->newWidth, 0, -1) / 100;
$this->log("Setting new width based on % to {$this->newWidth}"); $this->log("Setting new width based on % to {$this->newWidth}");
} }
// height as % // height as %
if ($this->newHeight[strlen($this->newHeight)-1] == '%') { if ($this->newHeight
&& $this->newHeight[strlen($this->newHeight)-1] == '%') {
$this->newHeight = $this->height * substr($this->newHeight, 0, -1) / 100; $this->newHeight = $this->height * substr($this->newHeight, 0, -1) / 100;
$this->log("Setting new height based on % to {$this->newHeight}"); $this->log("Setting new height based on % to {$this->newHeight}");
} }
@@ -2526,6 +2551,7 @@ class CImage
$rotateBefore = $this->rotateBefore ? "_rb{$this->rotateBefore}" : null; $rotateBefore = $this->rotateBefore ? "_rb{$this->rotateBefore}" : null;
$rotateAfter = $this->rotateAfter ? "_ra{$this->rotateAfter}" : null; $rotateAfter = $this->rotateAfter ? "_ra{$this->rotateAfter}" : null;
$lossy = $this->lossy ? "_l" : null; $lossy = $this->lossy ? "_l" : null;
$interlace = $this->interlace ? "_i" : null;
$saveAs = $this->normalizeFileExtension(); $saveAs = $this->normalizeFileExtension();
$saveAs = $saveAs ? "_$saveAs" : null; $saveAs = $saveAs ? "_$saveAs" : null;
@@ -2592,7 +2618,7 @@ class CImage
. $quality . $filters . $sharpen . $emboss . $blur . $palette . $quality . $filters . $sharpen . $emboss . $blur . $palette
. $optimize . $compress . $optimize . $compress
. $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor . $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor
. $convolve . $copyStrat . $lossy . $saveAs; . $convolve . $copyStrat . $lossy . $interlace . $saveAs;
return $this->setTarget($file, $base); return $this->setTarget($file, $base);
} }
@@ -3555,8 +3581,10 @@ class CImage
return; return;
} }
if (!defined("WINDOWS2WSL")) {
is_writable($this->saveFolder) is_writable($this->saveFolder)
or $this->raiseError('Target directory is not writable.'); or $this->raiseError('Target directory is not writable.');
}
$type = $this->getTargetImageExtension(); $type = $this->getTargetImageExtension();
$this->Log("Saving image as " . $type); $this->Log("Saving image as " . $type);
@@ -3564,6 +3592,12 @@ class CImage
case 'jpeg': case 'jpeg':
case 'jpg': case 'jpg':
// Set as interlaced progressive JPEG
if ($this->interlace) {
$this->Log("Set JPEG image to be interlaced.");
$res = imageinterlace($this->image, true);
}
$this->Log("Saving image as JPEG to cache using quality = {$this->quality}."); $this->Log("Saving image as JPEG to cache using quality = {$this->quality}.");
imagejpeg($this->image, $this->cacheFileName, $this->quality); imagejpeg($this->image, $this->cacheFileName, $this->quality);
@@ -3902,18 +3936,18 @@ class CImage
$lastModified = filemtime($this->pathToImage); $lastModified = filemtime($this->pathToImage);
$details['srcGmdate'] = gmdate("D, d M Y H:i:s", $lastModified); $details['srcGmdate'] = gmdate("D, d M Y H:i:s", $lastModified);
$details['cache'] = basename($this->cacheFileName); $details['cache'] = basename($this->cacheFileName ?? "");
$lastModified = filemtime($this->cacheFileName); $lastModified = filemtime($this->cacheFileName ?? "");
$details['cacheGmdate'] = gmdate("D, d M Y H:i:s", $lastModified); $details['cacheGmdate'] = gmdate("D, d M Y H:i:s", $lastModified);
$this->load($file); $this->load($file);
$details['filename'] = basename($file); $details['filename'] = basename($file ?? "");
$details['mimeType'] = $this->getMimeType($this->fileType); $details['mimeType'] = $this->getMimeType($this->fileType);
$details['width'] = $this->width; $details['width'] = $this->width;
$details['height'] = $this->height; $details['height'] = $this->height;
$details['aspectRatio'] = round($this->width / $this->height, 3); $details['aspectRatio'] = round($this->width / $this->height, 3);
$details['size'] = filesize($file); $details['size'] = filesize($file ?? "");
$details['colors'] = $this->colorsTotal($this->image); $details['colors'] = $this->colorsTotal($this->image);
$details['includedFiles'] = count(get_included_files()); $details['includedFiles'] = count(get_included_files());
$details['memoryPeek'] = round(memory_get_peak_usage()/1024/1024, 3) . " MB" ; $details['memoryPeek'] = round(memory_get_peak_usage()/1024/1024, 3) . " MB" ;
@@ -4112,6 +4146,15 @@ class CCache
return $path; return $path;
} }
if ($create && defined('WINDOWS2WSL')) {
// Special case to solve Windows 2 WSL integration
$path = $this->path . "/" . $subdir;
if (mkdir($path)) {
return realpath($path);
}
}
if ($create && is_writable($this->path)) { if ($create && is_writable($this->path)) {
$path = $this->path . "/" . $subdir; $path = $this->path . "/" . $subdir;
@@ -4418,6 +4461,22 @@ class CFastTrackCache
* *
*/ */
/**
* Custom exception handler.
*/
set_exception_handler(function ($exception) {
errorPage(
"<p><b>img.php: Uncaught exception:</b> <p>"
. $exception->getMessage()
. "</p><pre>"
. $exception->getTraceAsString()
. "</pre>",
500
);
});
/** /**
* Get configuration options from file, if the file exists, else use $config * Get configuration options from file, if the file exists, else use $config
* if its defined or create an empty $config. * if its defined or create an empty $config.
@@ -4580,7 +4639,7 @@ $hotlinkingWhitelist = getConfig('hotlinking_whitelist', array());
$serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null; $serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null;
$referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null; $referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
$refererHost = parse_url($referer, PHP_URL_HOST); $refererHost = parse_url($referer ?? "", PHP_URL_HOST);
if (!$allowHotlinking) { if (!$allowHotlinking) {
if ($passwordMatch) { if ($passwordMatch) {
@@ -4713,11 +4772,11 @@ if (isset($shortcut)
/** /**
* src - the source image file. * src - the source image file.
*/ */
$srcImage = urldecode(get('src')) $srcImage = urldecode(get('src', ""))
or errorPage('Must set src-attribute.', 404); or errorPage('Must set src-attribute.', 404);
// Get settings for src-alt as backup image // Get settings for src-alt as backup image
$srcAltImage = urldecode(get('src-alt', null)); $srcAltImage = urldecode(get('src-alt', ""));
$srcAltConfig = getConfig('src_alt', null); $srcAltConfig = getConfig('src_alt', null);
if (empty($srcAltImage)) { if (empty($srcAltImage)) {
$srcAltImage = $srcAltConfig; $srcAltImage = $srcAltConfig;
@@ -4834,7 +4893,7 @@ if (isset($sizes[$newWidth])) {
} }
// Support width as % of original width // Support width as % of original width
if ($newWidth[strlen($newWidth)-1] == '%') { if ($newWidth && $newWidth[strlen($newWidth)-1] == '%') {
is_numeric(substr($newWidth, 0, -1)) is_numeric(substr($newWidth, 0, -1))
or errorPage('Width % not numeric.', 404); or errorPage('Width % not numeric.', 404);
} else { } else {
@@ -4859,7 +4918,7 @@ if (isset($sizes[$newHeight])) {
} }
// height // height
if ($newHeight[strlen($newHeight)-1] == '%') { if ($newHeight && $newHeight[strlen($newHeight)-1] == '%') {
is_numeric(substr($newHeight, 0, -1)) is_numeric(substr($newHeight, 0, -1))
or errorPage('Height % out of range.', 404); or errorPage('Height % out of range.', 404);
} else { } else {
@@ -4890,7 +4949,7 @@ $aspectRatioConstant = getConfig('aspect_ratio_constant', function () {
// Check to replace predefined aspect ratio // Check to replace predefined aspect ratio
$aspectRatios = call_user_func($aspectRatioConstant); $aspectRatios = call_user_func($aspectRatioConstant);
$negateAspectRatio = ($aspectRatio[0] == '!') ? true : false; $negateAspectRatio = ($aspectRatio && $aspectRatio[0] == '!') ? true : false;
$aspectRatio = $negateAspectRatio ? substr($aspectRatio, 1) : $aspectRatio; $aspectRatio = $negateAspectRatio ? substr($aspectRatio, 1) : $aspectRatio;
if (isset($aspectRatios[$aspectRatio])) { if (isset($aspectRatios[$aspectRatio])) {
@@ -5314,6 +5373,18 @@ if ($cacheControl) {
/**
* interlace - Enable configuration for interlaced progressive JPEG images.
*/
$interlaceConfig = getConfig('interlace', null);
$interlaceValue = getValue('interlace', null);
$interlaceDefined = getDefined('interlace', true, null);
$interlace = $interlaceValue ?? $interlaceDefined ?? $interlaceConfig;
verbose("interlace (configfile) = ", $interlaceConfig);
verbose("interlace = ", $interlace);
/** /**
* Prepare a dummy image and use it as source image. * Prepare a dummy image and use it as source image.
*/ */
@@ -5475,6 +5546,7 @@ if (is_callable($hookBeforeCImage)) {
'blur' => $blur, 'blur' => $blur,
'convolve' => $convolve, 'convolve' => $convolve,
'rotateAfter' => $rotateAfter, 'rotateAfter' => $rotateAfter,
'interlace' => $interlace,
// Output format // Output format
'outputFormat' => $outputFormat, 'outputFormat' => $outputFormat,
@@ -5530,7 +5602,8 @@ EOD;
/** /**
* Load, process and output the image * Load, process and output the image
*/ */
$img->log("Incoming arguments: " . print_r(verbose(), 1)) $img->log("PHP version: " . phpversion())
->log("Incoming arguments: " . print_r(verbose(), 1))
->setSaveFolder($cachePath) ->setSaveFolder($cachePath)
->useCache($useCache) ->useCache($useCache)
->setSource($srcImage, $imagePath) ->setSource($srcImage, $imagePath)
@@ -5563,6 +5636,7 @@ $img->log("Incoming arguments: " . print_r(verbose(), 1))
'blur' => $blur, 'blur' => $blur,
'convolve' => $convolve, 'convolve' => $convolve,
'rotateAfter' => $rotateAfter, 'rotateAfter' => $rotateAfter,
'interlace' => $interlace,
// Output format // Output format
'outputFormat' => $outputFormat, 'outputFormat' => $outputFormat,

File diff suppressed because one or more lines are too long

22
webroot/tests.php Normal file
View File

@@ -0,0 +1,22 @@
<?php
$links = [
"img.php?src=car.png&v",
"img.php?src=car.png&w=700&v",
];
?><!doctype html>
<html>
<head>
<title>Links to use for testing</title>
</head>
<body>
<h1>Links useful for testing</h1>
<p>A collection of linkt to use to test various aspects of the cimage process.</p>
<ul>
<?php foreach ($links as $link) : ?>
<li><a href="<?= $link ?>"><?= $link ?></a></li>
<?php endforeach; ?>
</ul>
</body>
</html>