1 | <?php |
||||||||||
2 | /** |
||||||||||
3 | * Resize and crop images on the fly, store generated images in a cache. |
||||||||||
4 | * |
||||||||||
5 | * This version is a all-in-one version of img.php, it is not dependant an any other file |
||||||||||
6 | * so you can simply copy it to any place you want it. |
||||||||||
7 | * |
||||||||||
8 | * @author Mikael Roos [email protected] |
||||||||||
9 | * @example http://dbwebb.se/opensource/cimage |
||||||||||
10 | * @link https://github.com/mosbth/cimage |
||||||||||
11 | * |
||||||||||
12 | */ |
||||||||||
13 | define("CIMAGE_BUNDLE", true); |
||||||||||
14 | |||||||||||
15 | |||||||||||
16 | /** |
||||||||||
17 | * Change configuration details in the array below or create a separate file |
||||||||||
18 | * where you store the configuration details. |
||||||||||
19 | * |
||||||||||
20 | * The configuration file should be named the same name as this file and then |
||||||||||
21 | * add '_config.php'. If this file is named 'img.php' then name the |
||||||||||
22 | * config file should be named 'img_config.php'. |
||||||||||
23 | * |
||||||||||
24 | * The settings below are only a few of the available ones. Check the file in |
||||||||||
25 | * webroot/img_config.php for a complete list of configuration options. |
||||||||||
26 | */ |
||||||||||
27 | $config = array( |
||||||||||
28 | |||||||||||
29 | //'mode' => 'production', // 'production', 'development', 'strict' |
||||||||||
30 | //'image_path' => __DIR__ . '/img/', |
||||||||||
31 | //'cache_path' => __DIR__ . '/../cache/', |
||||||||||
32 | //'alias_path' => __DIR__ . '/img/alias/', |
||||||||||
33 | //'remote_allow' => true, |
||||||||||
34 | //'password' => false, // "secret-password", |
||||||||||
35 | |||||||||||
36 | ); |
||||||||||
37 | |||||||||||
38 | |||||||||||
39 | |||||||||||
40 | // Version of cimage and img.php |
||||||||||
41 | define("CIMAGE_VERSION", "v0.7.23 (2020-05-06)"); |
||||||||||
42 | |||||||||||
43 | // For CRemoteImage |
||||||||||
44 | define("CIMAGE_USER_AGENT", "CImage/" . CIMAGE_VERSION); |
||||||||||
45 | |||||||||||
46 | // Image type IMG_WEBP is only defined from 5.6.25 |
||||||||||
47 | if (!defined("IMG_WEBP")) { |
||||||||||
48 | define("IMG_WEBP", -1); |
||||||||||
49 | } |
||||||||||
50 | |||||||||||
51 | |||||||||||
52 | |||||||||||
53 | /** |
||||||||||
54 | * General functions to use in img.php. |
||||||||||
55 | */ |
||||||||||
56 | |||||||||||
57 | |||||||||||
58 | |||||||||||
59 | /** |
||||||||||
60 | * Trace and log execution to logfile, useful for debugging and development. |
||||||||||
61 | * |
||||||||||
62 | * @param string $msg message to log to file. |
||||||||||
63 | * |
||||||||||
64 | * @return void |
||||||||||
65 | */ |
||||||||||
66 | function trace($msg) |
||||||||||
67 | { |
||||||||||
68 | $file = CIMAGE_DEBUG_FILE; |
||||||||||
69 | if (!is_writable($file)) { |
||||||||||
70 | return; |
||||||||||
71 | } |
||||||||||
72 | |||||||||||
73 | $timer = number_format((microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"]), 6); |
||||||||||
74 | $details = "{$timer}ms"; |
||||||||||
75 | $details .= ":" . round(memory_get_peak_usage()/1024/1024, 3) . "MB"; |
||||||||||
76 | $details .= ":" . count(get_included_files()); |
||||||||||
77 | file_put_contents($file, "$details:$msg\n", FILE_APPEND); |
||||||||||
78 | } |
||||||||||
79 | |||||||||||
80 | |||||||||||
81 | |||||||||||
82 | /** |
||||||||||
83 | * Display error message. |
||||||||||
84 | * |
||||||||||
85 | * @param string $msg to display. |
||||||||||
86 | * @param int $type of HTTP error to display. |
||||||||||
87 | * |
||||||||||
88 | * @return void |
||||||||||
89 | */ |
||||||||||
90 | function errorPage($msg, $type = 500) |
||||||||||
91 | { |
||||||||||
92 | global $mode; |
||||||||||
93 | |||||||||||
94 | switch ($type) { |
||||||||||
95 | case 403: |
||||||||||
96 | $header = "403 Forbidden"; |
||||||||||
97 | break; |
||||||||||
98 | case 404: |
||||||||||
99 | $header = "404 Not Found"; |
||||||||||
100 | break; |
||||||||||
101 | default: |
||||||||||
102 | $header = "500 Internal Server Error"; |
||||||||||
103 | } |
||||||||||
104 | |||||||||||
105 | if ($mode == "strict") { |
||||||||||
106 | $header = "404 Not Found"; |
||||||||||
107 | } |
||||||||||
108 | |||||||||||
109 | header("HTTP/1.0 $header"); |
||||||||||
110 | |||||||||||
111 | if ($mode == "development") { |
||||||||||
112 | die("[img.php] $msg"); |
||||||||||
0 ignored issues
–
show
|
|||||||||||
113 | } |
||||||||||
114 | |||||||||||
115 | error_log("[img.php] $msg"); |
||||||||||
116 | die("HTTP/1.0 $header"); |
||||||||||
0 ignored issues
–
show
|
|||||||||||
117 | } |
||||||||||
118 | |||||||||||
119 | |||||||||||
120 | |||||||||||
121 | /** |
||||||||||
122 | * Get input from query string or return default value if not set. |
||||||||||
123 | * |
||||||||||
124 | * @param mixed $key as string or array of string values to look for in $_GET. |
||||||||||
125 | * @param mixed $default value to return when $key is not set in $_GET. |
||||||||||
126 | * |
||||||||||
127 | * @return mixed value from $_GET or default value. |
||||||||||
128 | */ |
||||||||||
129 | function get($key, $default = null) |
||||||||||
130 | { |
||||||||||
131 | if (is_array($key)) { |
||||||||||
132 | foreach ($key as $val) { |
||||||||||
133 | if (isset($_GET[$val])) { |
||||||||||
134 | return $_GET[$val]; |
||||||||||
135 | } |
||||||||||
136 | } |
||||||||||
137 | } elseif (isset($_GET[$key])) { |
||||||||||
138 | return $_GET[$key]; |
||||||||||
139 | } |
||||||||||
140 | return $default; |
||||||||||
141 | } |
||||||||||
142 | |||||||||||
143 | |||||||||||
144 | |||||||||||
145 | /** |
||||||||||
146 | * Get input from query string and set to $defined if defined or else $undefined. |
||||||||||
147 | * |
||||||||||
148 | * @param mixed $key as string or array of string values to look for in $_GET. |
||||||||||
149 | * @param mixed $defined value to return when $key is set in $_GET. |
||||||||||
150 | * @param mixed $undefined value to return when $key is not set in $_GET. |
||||||||||
151 | * |
||||||||||
152 | * @return mixed value as $defined or $undefined. |
||||||||||
153 | */ |
||||||||||
154 | function getDefined($key, $defined, $undefined) |
||||||||||
155 | { |
||||||||||
156 | return get($key) === null ? $undefined : $defined; |
||||||||||
157 | } |
||||||||||
158 | |||||||||||
159 | |||||||||||
160 | |||||||||||
161 | /** |
||||||||||
162 | * Get value from config array or default if key is not set in config array. |
||||||||||
163 | * |
||||||||||
164 | * @param string $key the key in the config array. |
||||||||||
165 | * @param mixed $default value to be default if $key is not set in config. |
||||||||||
166 | * |
||||||||||
167 | * @return mixed value as $config[$key] or $default. |
||||||||||
168 | */ |
||||||||||
169 | function getConfig($key, $default) |
||||||||||
170 | { |
||||||||||
171 | global $config; |
||||||||||
172 | return isset($config[$key]) |
||||||||||
173 | ? $config[$key] |
||||||||||
174 | : $default; |
||||||||||
175 | } |
||||||||||
176 | |||||||||||
177 | |||||||||||
178 | |||||||||||
179 | /** |
||||||||||
180 | * Log when verbose mode, when used without argument it returns the result. |
||||||||||
181 | * |
||||||||||
182 | * @param string $msg to log. |
||||||||||
183 | * |
||||||||||
184 | * @return void or array. |
||||||||||
185 | */ |
||||||||||
186 | function verbose($msg = null) |
||||||||||
187 | { |
||||||||||
188 | global $verbose, $verboseFile; |
||||||||||
189 | static $log = array(); |
||||||||||
190 | |||||||||||
191 | if (!($verbose || $verboseFile)) { |
||||||||||
192 | return; |
||||||||||
193 | } |
||||||||||
194 | |||||||||||
195 | if (is_null($msg)) { |
||||||||||
196 | return $log; |
||||||||||
197 | } |
||||||||||
198 | |||||||||||
199 | $log[] = $msg; |
||||||||||
200 | } |
||||||||||
201 | |||||||||||
202 | |||||||||||
203 | |||||||||||
204 | /** |
||||||||||
205 | * Log when verbose mode, when used without argument it returns the result. |
||||||||||
206 | * |
||||||||||
207 | * @param string $msg to log. |
||||||||||
208 | * |
||||||||||
209 | * @return void or array. |
||||||||||
210 | */ |
||||||||||
211 | function checkExternalCommand($what, $enabled, $commandString) |
||||||||||
212 | { |
||||||||||
213 | $no = $enabled ? null : 'NOT'; |
||||||||||
214 | $text = "Post processing $what is $no enabled.<br>"; |
||||||||||
215 | |||||||||||
216 | list($command) = explode(" ", $commandString); |
||||||||||
217 | $no = is_executable($command) ? null : 'NOT'; |
||||||||||
218 | $text .= "The command for $what is $no an executable.<br>"; |
||||||||||
219 | |||||||||||
220 | return $text; |
||||||||||
0 ignored issues
–
show
|
|||||||||||
221 | } |
||||||||||
222 | |||||||||||
223 | |||||||||||
224 | |||||||||||
225 | /** |
||||||||||
226 | * Get a image from a remote server using HTTP GET and If-Modified-Since. |
||||||||||
227 | * |
||||||||||
228 | */ |
||||||||||
229 | class CHttpGet |
||||||||||
230 | { |
||||||||||
231 | private $request = array(); |
||||||||||
232 | private $response = array(); |
||||||||||
233 | |||||||||||
234 | |||||||||||
235 | |||||||||||
236 | /** |
||||||||||
237 | * Constructor |
||||||||||
238 | * |
||||||||||
239 | */ |
||||||||||
240 | public function __construct() |
||||||||||
241 | { |
||||||||||
242 | $this->request['header'] = array(); |
||||||||||
243 | } |
||||||||||
244 | |||||||||||
245 | |||||||||||
246 | |||||||||||
247 | /** |
||||||||||
248 | * Build an encoded url. |
||||||||||
249 | * |
||||||||||
250 | * @param string $baseUrl This is the original url which will be merged. |
||||||||||
251 | * @param string $merge Thse parts should be merged into the baseUrl, |
||||||||||
252 | * the format is as parse_url. |
||||||||||
253 | * |
||||||||||
254 | * @return string $url as the modified url. |
||||||||||
255 | */ |
||||||||||
256 | public function buildUrl($baseUrl, $merge) |
||||||||||
257 | { |
||||||||||
258 | $parts = parse_url($baseUrl); |
||||||||||
259 | $parts = array_merge($parts, $merge); |
||||||||||
0 ignored issues
–
show
$merge of type string is incompatible with the type array expected by parameter $arrays of array_merge() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
260 | |||||||||||
261 | $url = $parts['scheme']; |
||||||||||
262 | $url .= "://"; |
||||||||||
263 | $url .= $parts['host']; |
||||||||||
264 | $url .= isset($parts['port']) |
||||||||||
265 | ? ":" . $parts['port'] |
||||||||||
266 | : "" ; |
||||||||||
267 | $url .= $parts['path']; |
||||||||||
268 | |||||||||||
269 | return $url; |
||||||||||
270 | } |
||||||||||
271 | |||||||||||
272 | |||||||||||
273 | |||||||||||
274 | /** |
||||||||||
275 | * Set the url for the request. |
||||||||||
276 | * |
||||||||||
277 | * @param string $url |
||||||||||
278 | * |
||||||||||
279 | * @return $this |
||||||||||
280 | */ |
||||||||||
281 | public function setUrl($url) |
||||||||||
282 | { |
||||||||||
283 | $parts = parse_url($url); |
||||||||||
284 | |||||||||||
285 | $path = ""; |
||||||||||
286 | if (isset($parts['path'])) { |
||||||||||
287 | $pathParts = explode('/', $parts['path']); |
||||||||||
288 | unset($pathParts[0]); |
||||||||||
289 | foreach ($pathParts as $value) { |
||||||||||
290 | $path .= "/" . rawurlencode($value); |
||||||||||
291 | } |
||||||||||
292 | } |
||||||||||
293 | $url = $this->buildUrl($url, array("path" => $path)); |
||||||||||
0 ignored issues
–
show
array('path' => $path) of type array<string,string> is incompatible with the type string expected by parameter $merge of CHttpGet::buildUrl() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
294 | |||||||||||
295 | $this->request['url'] = $url; |
||||||||||
296 | return $this; |
||||||||||
297 | } |
||||||||||
298 | |||||||||||
299 | |||||||||||
300 | |||||||||||
301 | /** |
||||||||||
302 | * Set custom header field for the request. |
||||||||||
303 | * |
||||||||||
304 | * @param string $field |
||||||||||
305 | * @param string $value |
||||||||||
306 | * |
||||||||||
307 | * @return $this |
||||||||||
308 | */ |
||||||||||
309 | public function setHeader($field, $value) |
||||||||||
310 | { |
||||||||||
311 | $this->request['header'][] = "$field: $value"; |
||||||||||
312 | return $this; |
||||||||||
313 | } |
||||||||||
314 | |||||||||||
315 | |||||||||||
316 | |||||||||||
317 | /** |
||||||||||
318 | * Set header fields for the request. |
||||||||||
319 | * |
||||||||||
320 | * @param string $field |
||||||||||
321 | * @param string $value |
||||||||||
322 | * |
||||||||||
323 | * @return $this |
||||||||||
324 | */ |
||||||||||
325 | public function parseHeader() |
||||||||||
326 | { |
||||||||||
327 | //$header = explode("\r\n", rtrim($this->response['headerRaw'], "\r\n")); |
||||||||||
328 | |||||||||||
329 | $rawHeaders = rtrim($this->response['headerRaw'], "\r\n"); |
||||||||||
330 | # Handle multiple responses e.g. with redirections (proxies too) |
||||||||||
331 | $headerGroups = explode("\r\n\r\n", $rawHeaders); |
||||||||||
332 | # We're only interested in the last one |
||||||||||
333 | $header = explode("\r\n", end($headerGroups)); |
||||||||||
334 | |||||||||||
335 | $output = array(); |
||||||||||
336 | |||||||||||
337 | if ('HTTP' === substr($header[0], 0, 4)) { |
||||||||||
338 | list($output['version'], $output['status']) = explode(' ', $header[0]); |
||||||||||
339 | unset($header[0]); |
||||||||||
340 | } |
||||||||||
341 | |||||||||||
342 | foreach ($header as $entry) { |
||||||||||
343 | $pos = strpos($entry, ':'); |
||||||||||
344 | $output[trim(substr($entry, 0, $pos))] = trim(substr($entry, $pos + 1)); |
||||||||||
345 | } |
||||||||||
346 | |||||||||||
347 | $this->response['header'] = $output; |
||||||||||
348 | return $this; |
||||||||||
349 | } |
||||||||||
350 | |||||||||||
351 | |||||||||||
352 | |||||||||||
353 | /** |
||||||||||
354 | * Perform the request. |
||||||||||
355 | * |
||||||||||
356 | * @param boolean $debug set to true to dump headers. |
||||||||||
357 | * |
||||||||||
358 | * @throws Exception when curl fails to retrieve url. |
||||||||||
359 | * |
||||||||||
360 | * @return boolean |
||||||||||
361 | */ |
||||||||||
362 | public function doGet($debug = false) |
||||||||||
363 | { |
||||||||||
364 | $options = array( |
||||||||||
365 | CURLOPT_URL => $this->request['url'], |
||||||||||
366 | CURLOPT_HEADER => 1, |
||||||||||
367 | CURLOPT_HTTPHEADER => $this->request['header'], |
||||||||||
368 | CURLOPT_AUTOREFERER => true, |
||||||||||
369 | CURLOPT_RETURNTRANSFER => true, |
||||||||||
370 | CURLINFO_HEADER_OUT => $debug, |
||||||||||
371 | CURLOPT_CONNECTTIMEOUT => 5, |
||||||||||
372 | CURLOPT_TIMEOUT => 5, |
||||||||||
373 | CURLOPT_FOLLOWLOCATION => true, |
||||||||||
374 | CURLOPT_MAXREDIRS => 2, |
||||||||||
375 | ); |
||||||||||
376 | |||||||||||
377 | $ch = curl_init(); |
||||||||||
378 | curl_setopt_array($ch, $options); |
||||||||||
379 | $response = curl_exec($ch); |
||||||||||
380 | |||||||||||
381 | if (!$response) { |
||||||||||
382 | throw new Exception("Failed retrieving url, details follows: " . curl_error($ch)); |
||||||||||
383 | } |
||||||||||
384 | |||||||||||
385 | $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); |
||||||||||
386 | $this->response['headerRaw'] = substr($response, 0, $headerSize); |
||||||||||
0 ignored issues
–
show
It seems like
$response can also be of type true ; however, parameter $string of substr() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
387 | $this->response['body'] = substr($response, $headerSize); |
||||||||||
388 | |||||||||||
389 | $this->parseHeader(); |
||||||||||
390 | |||||||||||
391 | if ($debug) { |
||||||||||
392 | $info = curl_getinfo($ch); |
||||||||||
393 | echo "Request header<br><pre>", var_dump($info['request_header']), "</pre>"; |
||||||||||
0 ignored issues
–
show
Are you sure the usage of
var_dump($info['request_header']) is correct as it seems to always return null .
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. ![]() Are you sure
var_dump($info['request_header']) of type void can be used in echo ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
394 | echo "Response header (raw)<br><pre>", var_dump($this->response['headerRaw']), "</pre>"; |
||||||||||
0 ignored issues
–
show
Are you sure the usage of
var_dump($this->response['headerRaw']) is correct as it seems to always return null .
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. ![]() Are you sure
var_dump($this->response['headerRaw']) of type void can be used in echo ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
395 | echo "Response header (parsed)<br><pre>", var_dump($this->response['header']), "</pre>"; |
||||||||||
0 ignored issues
–
show
Are you sure
var_dump($this->response['header']) of type void can be used in echo ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() Are you sure the usage of
var_dump($this->response['header']) is correct as it seems to always return null .
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. ![]() |
|||||||||||
396 | } |
||||||||||
397 | |||||||||||
398 | curl_close($ch); |
||||||||||
399 | return true; |
||||||||||
400 | } |
||||||||||
401 | |||||||||||
402 | |||||||||||
403 | |||||||||||
404 | /** |
||||||||||
405 | * Get HTTP code of response. |
||||||||||
406 | * |
||||||||||
407 | * @return integer as HTTP status code or null if not available. |
||||||||||
408 | */ |
||||||||||
409 | public function getStatus() |
||||||||||
410 | { |
||||||||||
411 | return isset($this->response['header']['status']) |
||||||||||
412 | ? (int) $this->response['header']['status'] |
||||||||||
413 | : null; |
||||||||||
414 | } |
||||||||||
415 | |||||||||||
416 | |||||||||||
417 | |||||||||||
418 | /** |
||||||||||
419 | * Get file modification time of response. |
||||||||||
420 | * |
||||||||||
421 | * @return int as timestamp. |
||||||||||
422 | */ |
||||||||||
423 | public function getLastModified() |
||||||||||
424 | { |
||||||||||
425 | return isset($this->response['header']['Last-Modified']) |
||||||||||
426 | ? strtotime($this->response['header']['Last-Modified']) |
||||||||||
427 | : null; |
||||||||||
428 | } |
||||||||||
429 | |||||||||||
430 | |||||||||||
431 | |||||||||||
432 | /** |
||||||||||
433 | * Get content type. |
||||||||||
434 | * |
||||||||||
435 | * @return string as the content type or null if not existing or invalid. |
||||||||||
436 | */ |
||||||||||
437 | public function getContentType() |
||||||||||
438 | { |
||||||||||
439 | $type = isset($this->response['header']['Content-Type']) |
||||||||||
440 | ? $this->response['header']['Content-Type'] |
||||||||||
441 | : null; |
||||||||||
442 | |||||||||||
443 | return preg_match('#[a-z]+/[a-z]+#', $type) |
||||||||||
0 ignored issues
–
show
It seems like
$type can also be of type null ; however, parameter $subject of preg_match() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
444 | ? $type |
||||||||||
445 | : null; |
||||||||||
446 | } |
||||||||||
447 | |||||||||||
448 | |||||||||||
449 | |||||||||||
450 | /** |
||||||||||
451 | * Get file modification time of response. |
||||||||||
452 | * |
||||||||||
453 | * @param mixed $default as default value (int seconds) if date is |
||||||||||
454 | * missing in response header. |
||||||||||
455 | * |
||||||||||
456 | * @return int as timestamp or $default if Date is missing in |
||||||||||
457 | * response header. |
||||||||||
458 | */ |
||||||||||
459 | public function getDate($default = false) |
||||||||||
460 | { |
||||||||||
461 | return isset($this->response['header']['Date']) |
||||||||||
0 ignored issues
–
show
The expression
return IssetNode ? strto...r']['Date']) : $default could also return false which is incompatible with the documented return type integer . Did you maybe forget to handle an error condition?
If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled. ![]() |
|||||||||||
462 | ? strtotime($this->response['header']['Date']) |
||||||||||
463 | : $default; |
||||||||||
464 | } |
||||||||||
465 | |||||||||||
466 | |||||||||||
467 | |||||||||||
468 | /** |
||||||||||
469 | * Get max age of cachable item. |
||||||||||
470 | * |
||||||||||
471 | * @param mixed $default as default value if date is missing in response |
||||||||||
472 | * header. |
||||||||||
473 | * |
||||||||||
474 | * @return int as timestamp or false if not available. |
||||||||||
475 | */ |
||||||||||
476 | public function getMaxAge($default = false) |
||||||||||
477 | { |
||||||||||
478 | $cacheControl = isset($this->response['header']['Cache-Control']) |
||||||||||
479 | ? $this->response['header']['Cache-Control'] |
||||||||||
480 | : null; |
||||||||||
481 | |||||||||||
482 | $maxAge = null; |
||||||||||
483 | if ($cacheControl) { |
||||||||||
484 | // max-age=2592000 |
||||||||||
485 | $part = explode('=', $cacheControl); |
||||||||||
486 | $maxAge = ($part[0] == "max-age") |
||||||||||
487 | ? (int) $part[1] |
||||||||||
488 | : null; |
||||||||||
489 | } |
||||||||||
490 | |||||||||||
491 | if ($maxAge) { |
||||||||||
0 ignored issues
–
show
The expression
$maxAge of type integer|null is loosely compared to true ; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For 0 == false // true
0 == null // true
123 == false // false
123 == null // false
// It is often better to use strict comparison
0 === false // false
0 === null // false
![]() |
|||||||||||
492 | return $maxAge; |
||||||||||
493 | } |
||||||||||
494 | |||||||||||
495 | $expire = isset($this->response['header']['Expires']) |
||||||||||
496 | ? strtotime($this->response['header']['Expires']) |
||||||||||
497 | : null; |
||||||||||
498 | |||||||||||
499 | return $expire ? $expire : $default; |
||||||||||
0 ignored issues
–
show
The expression
return $expire ? $expire : $default could also return false which is incompatible with the documented return type integer . Did you maybe forget to handle an error condition?
If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled. ![]() |
|||||||||||
500 | } |
||||||||||
501 | |||||||||||
502 | |||||||||||
503 | |||||||||||
504 | /** |
||||||||||
505 | * Get body of response. |
||||||||||
506 | * |
||||||||||
507 | * @return string as body. |
||||||||||
508 | */ |
||||||||||
509 | public function getBody() |
||||||||||
510 | { |
||||||||||
511 | return $this->response['body']; |
||||||||||
512 | } |
||||||||||
513 | } |
||||||||||
514 | |||||||||||
515 | |||||||||||
516 | |||||||||||
517 | /** |
||||||||||
518 | * Get a image from a remote server using HTTP GET and If-Modified-Since. |
||||||||||
519 | * |
||||||||||
520 | */ |
||||||||||
521 | class CRemoteImage |
||||||||||
522 | { |
||||||||||
523 | /** |
||||||||||
524 | * Path to cache files. |
||||||||||
525 | */ |
||||||||||
526 | private $saveFolder = null; |
||||||||||
527 | |||||||||||
528 | |||||||||||
529 | |||||||||||
530 | /** |
||||||||||
531 | * Use cache or not. |
||||||||||
532 | */ |
||||||||||
533 | private $useCache = true; |
||||||||||
534 | |||||||||||
535 | |||||||||||
536 | |||||||||||
537 | /** |
||||||||||
538 | * HTTP object to aid in download file. |
||||||||||
539 | */ |
||||||||||
540 | private $http; |
||||||||||
541 | |||||||||||
542 | |||||||||||
543 | |||||||||||
544 | /** |
||||||||||
545 | * Status of the HTTP request. |
||||||||||
546 | */ |
||||||||||
547 | private $status; |
||||||||||
548 | |||||||||||
549 | |||||||||||
550 | |||||||||||
551 | /** |
||||||||||
552 | * Defalt age for cached items 60*60*24*7. |
||||||||||
553 | */ |
||||||||||
554 | private $defaultMaxAge = 604800; |
||||||||||
555 | |||||||||||
556 | |||||||||||
557 | |||||||||||
558 | /** |
||||||||||
559 | * Url of downloaded item. |
||||||||||
560 | */ |
||||||||||
561 | private $url; |
||||||||||
562 | |||||||||||
563 | |||||||||||
564 | |||||||||||
565 | /** |
||||||||||
566 | * Base name of cache file for downloaded item and name of image. |
||||||||||
567 | */ |
||||||||||
568 | private $fileName; |
||||||||||
569 | |||||||||||
570 | |||||||||||
571 | |||||||||||
572 | /** |
||||||||||
573 | * Filename for json-file with details of cached item. |
||||||||||
574 | */ |
||||||||||
575 | private $fileJson; |
||||||||||
576 | |||||||||||
577 | |||||||||||
578 | |||||||||||
579 | /** |
||||||||||
580 | * Cache details loaded from file. |
||||||||||
581 | */ |
||||||||||
582 | private $cache; |
||||||||||
583 | |||||||||||
584 | |||||||||||
585 | |||||||||||
586 | /** |
||||||||||
587 | * Get status of last HTTP request. |
||||||||||
588 | * |
||||||||||
589 | * @return int as status |
||||||||||
590 | */ |
||||||||||
591 | public function getStatus() |
||||||||||
592 | { |
||||||||||
593 | return $this->status; |
||||||||||
594 | } |
||||||||||
595 | |||||||||||
596 | |||||||||||
597 | |||||||||||
598 | /** |
||||||||||
599 | * Get JSON details for cache item. |
||||||||||
600 | * |
||||||||||
601 | * @return array with json details on cache. |
||||||||||
602 | */ |
||||||||||
603 | public function getDetails() |
||||||||||
604 | { |
||||||||||
605 | return $this->cache; |
||||||||||
606 | } |
||||||||||
607 | |||||||||||
608 | |||||||||||
609 | |||||||||||
610 | /** |
||||||||||
611 | * Set the path to the cache directory. |
||||||||||
612 | * |
||||||||||
613 | * @param boolean $use true to use the cache and false to ignore cache. |
||||||||||
614 | * |
||||||||||
615 | * @return $this |
||||||||||
616 | */ |
||||||||||
617 | public function setCache($path) |
||||||||||
618 | { |
||||||||||
619 | $this->saveFolder = rtrim($path, "/") . "/"; |
||||||||||
620 | return $this; |
||||||||||
621 | } |
||||||||||
622 | |||||||||||
623 | |||||||||||
624 | |||||||||||
625 | /** |
||||||||||
626 | * Check if cache is writable or throw exception. |
||||||||||
627 | * |
||||||||||
628 | * @return $this |
||||||||||
629 | * |
||||||||||
630 | * @throws Exception if cahce folder is not writable. |
||||||||||
631 | */ |
||||||||||
632 | public function isCacheWritable() |
||||||||||
633 | { |
||||||||||
634 | if (!is_writable($this->saveFolder)) { |
||||||||||
635 | throw new Exception("Cache folder is not writable for downloaded files."); |
||||||||||
636 | } |
||||||||||
637 | return $this; |
||||||||||
638 | } |
||||||||||
639 | |||||||||||
640 | |||||||||||
641 | |||||||||||
642 | /** |
||||||||||
643 | * Decide if the cache should be used or not before trying to download |
||||||||||
644 | * a remote file. |
||||||||||
645 | * |
||||||||||
646 | * @param boolean $use true to use the cache and false to ignore cache. |
||||||||||
647 | * |
||||||||||
648 | * @return $this |
||||||||||
649 | */ |
||||||||||
650 | public function useCache($use = true) |
||||||||||
651 | { |
||||||||||
652 | $this->useCache = $use; |
||||||||||
653 | return $this; |
||||||||||
654 | } |
||||||||||
655 | |||||||||||
656 | |||||||||||
657 | |||||||||||
658 | /** |
||||||||||
659 | * Set header fields. |
||||||||||
660 | * |
||||||||||
661 | * @return $this |
||||||||||
662 | */ |
||||||||||
663 | public function setHeaderFields() |
||||||||||
664 | { |
||||||||||
665 | $cimageVersion = "CImage"; |
||||||||||
666 | if (defined("CIMAGE_USER_AGENT")) { |
||||||||||
667 | $cimageVersion = CIMAGE_USER_AGENT; |
||||||||||
668 | } |
||||||||||
669 | |||||||||||
670 | $this->http->setHeader("User-Agent", "$cimageVersion (PHP/". phpversion() . " cURL)"); |
||||||||||
671 | $this->http->setHeader("Accept", "image/jpeg,image/png,image/gif"); |
||||||||||
672 | |||||||||||
673 | if ($this->useCache) { |
||||||||||
674 | $this->http->setHeader("Cache-Control", "max-age=0"); |
||||||||||
675 | } else { |
||||||||||
676 | $this->http->setHeader("Cache-Control", "no-cache"); |
||||||||||
677 | $this->http->setHeader("Pragma", "no-cache"); |
||||||||||
678 | } |
||||||||||
679 | } |
||||||||||
680 | |||||||||||
681 | |||||||||||
682 | |||||||||||
683 | /** |
||||||||||
684 | * Save downloaded resource to cache. |
||||||||||
685 | * |
||||||||||
686 | * @return string as path to saved file or false if not saved. |
||||||||||
687 | */ |
||||||||||
688 | public function save() |
||||||||||
689 | { |
||||||||||
690 | $this->cache = array(); |
||||||||||
691 | $date = $this->http->getDate(time()); |
||||||||||
692 | $maxAge = $this->http->getMaxAge($this->defaultMaxAge); |
||||||||||
693 | $lastModified = $this->http->getLastModified(); |
||||||||||
694 | $type = $this->http->getContentType(); |
||||||||||
695 | |||||||||||
696 | $this->cache['Date'] = gmdate("D, d M Y H:i:s T", $date); |
||||||||||
697 | $this->cache['Max-Age'] = $maxAge; |
||||||||||
698 | $this->cache['Content-Type'] = $type; |
||||||||||
699 | $this->cache['Url'] = $this->url; |
||||||||||
700 | |||||||||||
701 | if ($lastModified) { |
||||||||||
702 | $this->cache['Last-Modified'] = gmdate("D, d M Y H:i:s T", $lastModified); |
||||||||||
703 | } |
||||||||||
704 | |||||||||||
705 | // Save only if body is a valid image |
||||||||||
706 | $body = $this->http->getBody(); |
||||||||||
707 | $img = imagecreatefromstring($body); |
||||||||||
708 | |||||||||||
709 | if ($img !== false) { |
||||||||||
710 | file_put_contents($this->fileName, $body); |
||||||||||
711 | file_put_contents($this->fileJson, json_encode($this->cache)); |
||||||||||
712 | return $this->fileName; |
||||||||||
713 | } |
||||||||||
714 | |||||||||||
715 | return false; |
||||||||||
0 ignored issues
–
show
|
|||||||||||
716 | } |
||||||||||
717 | |||||||||||
718 | |||||||||||
719 | |||||||||||
720 | /** |
||||||||||
721 | * Got a 304 and updates cache with new age. |
||||||||||
722 | * |
||||||||||
723 | * @return string as path to cached file. |
||||||||||
724 | */ |
||||||||||
725 | public function updateCacheDetails() |
||||||||||
726 | { |
||||||||||
727 | $date = $this->http->getDate(time()); |
||||||||||
728 | $maxAge = $this->http->getMaxAge($this->defaultMaxAge); |
||||||||||
729 | $lastModified = $this->http->getLastModified(); |
||||||||||
730 | |||||||||||
731 | $this->cache['Date'] = gmdate("D, d M Y H:i:s T", $date); |
||||||||||
732 | $this->cache['Max-Age'] = $maxAge; |
||||||||||
733 | |||||||||||
734 | if ($lastModified) { |
||||||||||
735 | $this->cache['Last-Modified'] = gmdate("D, d M Y H:i:s T", $lastModified); |
||||||||||
736 | } |
||||||||||
737 | |||||||||||
738 | file_put_contents($this->fileJson, json_encode($this->cache)); |
||||||||||
739 | return $this->fileName; |
||||||||||
740 | } |
||||||||||
741 | |||||||||||
742 | |||||||||||
743 | |||||||||||
744 | /** |
||||||||||
745 | * Download a remote file and keep a cache of downloaded files. |
||||||||||
746 | * |
||||||||||
747 | * @param string $url a remote url. |
||||||||||
748 | * |
||||||||||
749 | * @throws Exception when status code does not match 200 or 304. |
||||||||||
750 | * |
||||||||||
751 | * @return string as path to downloaded file or false if failed. |
||||||||||
752 | */ |
||||||||||
753 | public function download($url) |
||||||||||
754 | { |
||||||||||
755 | $this->http = new CHttpGet(); |
||||||||||
756 | $this->url = $url; |
||||||||||
757 | |||||||||||
758 | // First check if the cache is valid and can be used |
||||||||||
759 | $this->loadCacheDetails(); |
||||||||||
760 | |||||||||||
761 | if ($this->useCache) { |
||||||||||
762 | $src = $this->getCachedSource(); |
||||||||||
763 | if ($src) { |
||||||||||
764 | $this->status = 1; |
||||||||||
765 | return $src; |
||||||||||
766 | } |
||||||||||
767 | } |
||||||||||
768 | |||||||||||
769 | // Do a HTTP request to download item |
||||||||||
770 | $this->setHeaderFields(); |
||||||||||
771 | $this->http->setUrl($this->url); |
||||||||||
772 | $this->http->doGet(); |
||||||||||
773 | |||||||||||
774 | $this->status = $this->http->getStatus(); |
||||||||||
775 | if ($this->status === 200) { |
||||||||||
776 | $this->isCacheWritable(); |
||||||||||
777 | return $this->save(); |
||||||||||
778 | } elseif ($this->status === 304) { |
||||||||||
779 | $this->isCacheWritable(); |
||||||||||
780 | return $this->updateCacheDetails(); |
||||||||||
781 | } |
||||||||||
782 | |||||||||||
783 | throw new Exception("Unknown statuscode when downloading remote image: " . $this->status); |
||||||||||
784 | } |
||||||||||
785 | |||||||||||
786 | |||||||||||
787 | |||||||||||
788 | /** |
||||||||||
789 | * Get the path to the cached image file if the cache is valid. |
||||||||||
790 | * |
||||||||||
791 | * @return $this |
||||||||||
792 | */ |
||||||||||
793 | public function loadCacheDetails() |
||||||||||
794 | { |
||||||||||
795 | $cacheFile = md5($this->url); |
||||||||||
796 | $this->fileName = $this->saveFolder . $cacheFile; |
||||||||||
797 | $this->fileJson = $this->fileName . ".json"; |
||||||||||
798 | if (is_readable($this->fileJson)) { |
||||||||||
799 | $this->cache = json_decode(file_get_contents($this->fileJson), true); |
||||||||||
800 | } |
||||||||||
801 | } |
||||||||||
802 | |||||||||||
803 | |||||||||||
804 | |||||||||||
805 | /** |
||||||||||
806 | * Get the path to the cached image file if the cache is valid. |
||||||||||
807 | * |
||||||||||
808 | * @return string as the path ot the image file or false if no cache. |
||||||||||
809 | */ |
||||||||||
810 | public function getCachedSource() |
||||||||||
811 | { |
||||||||||
812 | $imageExists = is_readable($this->fileName); |
||||||||||
813 | |||||||||||
814 | // Is cache valid? |
||||||||||
815 | $date = strtotime($this->cache['Date']); |
||||||||||
816 | $maxAge = $this->cache['Max-Age']; |
||||||||||
817 | $now = time(); |
||||||||||
818 | |||||||||||
819 | if ($imageExists && $date + $maxAge > $now) { |
||||||||||
820 | return $this->fileName; |
||||||||||
821 | } |
||||||||||
822 | |||||||||||
823 | // Prepare for a 304 if available |
||||||||||
824 | if ($imageExists && isset($this->cache['Last-Modified'])) { |
||||||||||
825 | $this->http->setHeader("If-Modified-Since", $this->cache['Last-Modified']); |
||||||||||
826 | } |
||||||||||
827 | |||||||||||
828 | return false; |
||||||||||
0 ignored issues
–
show
|
|||||||||||
829 | } |
||||||||||
830 | } |
||||||||||
831 | |||||||||||
832 | |||||||||||
833 | |||||||||||
834 | /** |
||||||||||
835 | * Act as whitelist (or blacklist). |
||||||||||
836 | * |
||||||||||
837 | */ |
||||||||||
838 | class CWhitelist |
||||||||||
839 | { |
||||||||||
840 | /** |
||||||||||
841 | * Array to contain the whitelist options. |
||||||||||
842 | */ |
||||||||||
843 | private $whitelist = array(); |
||||||||||
844 | |||||||||||
845 | |||||||||||
846 | |||||||||||
847 | /** |
||||||||||
848 | * Set the whitelist from an array of strings, each item in the |
||||||||||
849 | * whitelist should be a regexp without the surrounding / or #. |
||||||||||
850 | * |
||||||||||
851 | * @param array $whitelist with all valid options, |
||||||||||
852 | * default is to clear the whitelist. |
||||||||||
853 | * |
||||||||||
854 | * @return $this |
||||||||||
855 | */ |
||||||||||
856 | public function set($whitelist = array()) |
||||||||||
857 | { |
||||||||||
858 | if (!is_array($whitelist)) { |
||||||||||
0 ignored issues
–
show
|
|||||||||||
859 | throw new Exception("Whitelist is not of a supported format."); |
||||||||||
860 | } |
||||||||||
861 | |||||||||||
862 | $this->whitelist = $whitelist; |
||||||||||
863 | return $this; |
||||||||||
864 | } |
||||||||||
865 | |||||||||||
866 | |||||||||||
867 | |||||||||||
868 | /** |
||||||||||
869 | * Check if item exists in the whitelist. |
||||||||||
870 | * |
||||||||||
871 | * @param string $item string to check. |
||||||||||
872 | * @param array $whitelist optional with all valid options, default is null. |
||||||||||
873 | * |
||||||||||
874 | * @return boolean true if item is in whitelist, else false. |
||||||||||
875 | */ |
||||||||||
876 | public function check($item, $whitelist = null) |
||||||||||
877 | { |
||||||||||
878 | if ($whitelist !== null) { |
||||||||||
879 | $this->set($whitelist); |
||||||||||
880 | } |
||||||||||
881 | |||||||||||
882 | if (empty($item) or empty($this->whitelist)) { |
||||||||||
883 | return false; |
||||||||||
884 | } |
||||||||||
885 | |||||||||||
886 | foreach ($this->whitelist as $regexp) { |
||||||||||
887 | if (preg_match("#$regexp#", $item)) { |
||||||||||
888 | return true; |
||||||||||
889 | } |
||||||||||
890 | } |
||||||||||
891 | |||||||||||
892 | return false; |
||||||||||
893 | } |
||||||||||
894 | } |
||||||||||
895 | |||||||||||
896 | |||||||||||
897 | |||||||||||
898 | /** |
||||||||||
899 | * Create an ASCII version of an image. |
||||||||||
900 | * |
||||||||||
901 | */ |
||||||||||
902 | class CAsciiArt |
||||||||||
903 | { |
||||||||||
904 | /** |
||||||||||
905 | * Character set to use. |
||||||||||
906 | */ |
||||||||||
907 | private $characterSet = array( |
||||||||||
908 | 'one' => "#0XT|:,.' ", |
||||||||||
909 | 'two' => "@%#*+=-:. ", |
||||||||||
910 | 'three' => "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. " |
||||||||||
911 | ); |
||||||||||
912 | |||||||||||
913 | |||||||||||
914 | |||||||||||
915 | /** |
||||||||||
916 | * Current character set. |
||||||||||
917 | */ |
||||||||||
918 | private $characters = null; |
||||||||||
919 | |||||||||||
920 | |||||||||||
921 | |||||||||||
922 | /** |
||||||||||
923 | * Length of current character set. |
||||||||||
924 | */ |
||||||||||
925 | private $charCount = null; |
||||||||||
926 | |||||||||||
927 | |||||||||||
928 | |||||||||||
929 | /** |
||||||||||
930 | * Scale of the area to swap to a character. |
||||||||||
931 | */ |
||||||||||
932 | private $scale = null; |
||||||||||
933 | |||||||||||
934 | |||||||||||
935 | |||||||||||
936 | /** |
||||||||||
937 | * Strategy to calculate luminance. |
||||||||||
938 | */ |
||||||||||
939 | private $luminanceStrategy = null; |
||||||||||
940 | |||||||||||
941 | |||||||||||
942 | |||||||||||
943 | /** |
||||||||||
944 | * Constructor which sets default options. |
||||||||||
945 | */ |
||||||||||
946 | public function __construct() |
||||||||||
947 | { |
||||||||||
948 | $this->setOptions(); |
||||||||||
949 | } |
||||||||||
950 | |||||||||||
951 | |||||||||||
952 | |||||||||||
953 | /** |
||||||||||
954 | * Add a custom character set. |
||||||||||
955 | * |
||||||||||
956 | * @param string $key for the character set. |
||||||||||
957 | * @param string $value for the character set. |
||||||||||
958 | * |
||||||||||
959 | * @return $this |
||||||||||
960 | */ |
||||||||||
961 | public function addCharacterSet($key, $value) |
||||||||||
962 | { |
||||||||||
963 | $this->characterSet[$key] = $value; |
||||||||||
964 | return $this; |
||||||||||
965 | } |
||||||||||
966 | |||||||||||
967 | |||||||||||
968 | |||||||||||
969 | /** |
||||||||||
970 | * Set options for processing, defaults are available. |
||||||||||
971 | * |
||||||||||
972 | * @param array $options to use as default settings. |
||||||||||
973 | * |
||||||||||
974 | * @return $this |
||||||||||
975 | */ |
||||||||||
976 | public function setOptions($options = array()) |
||||||||||
977 | { |
||||||||||
978 | $default = array( |
||||||||||
979 | "characterSet" => 'two', |
||||||||||
980 | "scale" => 14, |
||||||||||
981 | "luminanceStrategy" => 3, |
||||||||||
982 | "customCharacterSet" => null, |
||||||||||
983 | ); |
||||||||||
984 | $default = array_merge($default, $options); |
||||||||||
985 | |||||||||||
986 | if (!is_null($default['customCharacterSet'])) { |
||||||||||
987 | $this->addCharacterSet('custom', $default['customCharacterSet']); |
||||||||||
988 | $default['characterSet'] = 'custom'; |
||||||||||
989 | } |
||||||||||
990 | |||||||||||
991 | $this->scale = $default['scale']; |
||||||||||
992 | $this->characters = $this->characterSet[$default['characterSet']]; |
||||||||||
993 | $this->charCount = strlen($this->characters); |
||||||||||
994 | $this->luminanceStrategy = $default['luminanceStrategy']; |
||||||||||
995 | |||||||||||
996 | return $this; |
||||||||||
997 | } |
||||||||||
998 | |||||||||||
999 | |||||||||||
1000 | |||||||||||
1001 | /** |
||||||||||
1002 | * Create an Ascii image from an image file. |
||||||||||
1003 | * |
||||||||||
1004 | * @param string $filename of the image to use. |
||||||||||
1005 | * |
||||||||||
1006 | * @return string $ascii with the ASCII image. |
||||||||||
1007 | */ |
||||||||||
1008 | public function createFromFile($filename) |
||||||||||
1009 | { |
||||||||||
1010 | $img = imagecreatefromstring(file_get_contents($filename)); |
||||||||||
1011 | list($width, $height) = getimagesize($filename); |
||||||||||
1012 | |||||||||||
1013 | $ascii = null; |
||||||||||
1014 | $incY = $this->scale; |
||||||||||
1015 | $incX = $this->scale / 2; |
||||||||||
1016 | |||||||||||
1017 | for ($y = 0; $y < $height - 1; $y += $incY) { |
||||||||||
1018 | for ($x = 0; $x < $width - 1; $x += $incX) { |
||||||||||
1019 | $toX = min($x + $this->scale / 2, $width - 1); |
||||||||||
1020 | $toY = min($y + $this->scale, $height - 1); |
||||||||||
1021 | $luminance = $this->luminanceAreaAverage($img, $x, $y, $toX, $toY); |
||||||||||
0 ignored issues
–
show
$img of type GdImage|resource is incompatible with the type string expected by parameter $img of CAsciiArt::luminanceAreaAverage() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
1022 | $ascii .= $this->luminance2character($luminance); |
||||||||||
1023 | } |
||||||||||
1024 | $ascii .= PHP_EOL; |
||||||||||
1025 | } |
||||||||||
1026 | |||||||||||
1027 | return $ascii; |
||||||||||
1028 | } |
||||||||||
1029 | |||||||||||
1030 | |||||||||||
1031 | |||||||||||
1032 | /** |
||||||||||
1033 | * Get the luminance from a region of an image using average color value. |
||||||||||
1034 | * |
||||||||||
1035 | * @param string $img the image. |
||||||||||
1036 | * @param integer $x1 the area to get pixels from. |
||||||||||
1037 | * @param integer $y1 the area to get pixels from. |
||||||||||
1038 | * @param integer $x2 the area to get pixels from. |
||||||||||
1039 | * @param integer $y2 the area to get pixels from. |
||||||||||
1040 | * |
||||||||||
1041 | * @return integer $luminance with a value between 0 and 100. |
||||||||||
1042 | */ |
||||||||||
1043 | public function luminanceAreaAverage($img, $x1, $y1, $x2, $y2) |
||||||||||
1044 | { |
||||||||||
1045 | $numPixels = ($x2 - $x1 + 1) * ($y2 - $y1 + 1); |
||||||||||
1046 | $luminance = 0; |
||||||||||
1047 | |||||||||||
1048 | for ($x = $x1; $x <= $x2; $x++) { |
||||||||||
1049 | for ($y = $y1; $y <= $y2; $y++) { |
||||||||||
1050 | $rgb = imagecolorat($img, $x, $y); |
||||||||||
0 ignored issues
–
show
$img of type string is incompatible with the type GdImage|resource expected by parameter $image of imagecolorat() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
1051 | $red = (($rgb >> 16) & 0xFF); |
||||||||||
1052 | $green = (($rgb >> 8) & 0xFF); |
||||||||||
1053 | $blue = ($rgb & 0xFF); |
||||||||||
1054 | $luminance += $this->getLuminance($red, $green, $blue); |
||||||||||
1055 | } |
||||||||||
1056 | } |
||||||||||
1057 | |||||||||||
1058 | return $luminance / $numPixels; |
||||||||||
1059 | } |
||||||||||
1060 | |||||||||||
1061 | |||||||||||
1062 | |||||||||||
1063 | /** |
||||||||||
1064 | * Calculate luminance value with different strategies. |
||||||||||
1065 | * |
||||||||||
1066 | * @param integer $red The color red. |
||||||||||
1067 | * @param integer $green The color green. |
||||||||||
1068 | * @param integer $blue The color blue. |
||||||||||
1069 | * |
||||||||||
1070 | * @return float $luminance with a value between 0 and 1. |
||||||||||
1071 | */ |
||||||||||
1072 | public function getLuminance($red, $green, $blue) |
||||||||||
1073 | { |
||||||||||
1074 | switch ($this->luminanceStrategy) { |
||||||||||
1075 | case 1: |
||||||||||
1076 | $luminance = ($red * 0.2126 + $green * 0.7152 + $blue * 0.0722) / 255; |
||||||||||
1077 | break; |
||||||||||
1078 | case 2: |
||||||||||
1079 | $luminance = ($red * 0.299 + $green * 0.587 + $blue * 0.114) / 255; |
||||||||||
1080 | break; |
||||||||||
1081 | case 3: |
||||||||||
1082 | $luminance = sqrt(0.299 * pow($red, 2) + 0.587 * pow($green, 2) + 0.114 * pow($blue, 2)) / 255; |
||||||||||
1083 | break; |
||||||||||
1084 | case 0: |
||||||||||
1085 | default: |
||||||||||
1086 | $luminance = ($red + $green + $blue) / (255 * 3); |
||||||||||
1087 | } |
||||||||||
1088 | |||||||||||
1089 | return $luminance; |
||||||||||
1090 | } |
||||||||||
1091 | |||||||||||
1092 | |||||||||||
1093 | |||||||||||
1094 | /** |
||||||||||
1095 | * Translate the luminance value to a character. |
||||||||||
1096 | * |
||||||||||
1097 | * @param string $position a value between 0-100 representing the |
||||||||||
1098 | * luminance. |
||||||||||
1099 | * |
||||||||||
1100 | * @return string with the ascii character. |
||||||||||
1101 | */ |
||||||||||
1102 | public function luminance2character($luminance) |
||||||||||
1103 | { |
||||||||||
1104 | $position = (int) round($luminance * ($this->charCount - 1)); |
||||||||||
1105 | $char = $this->characters[$position]; |
||||||||||
1106 | return $char; |
||||||||||
1107 | } |
||||||||||
1108 | } |
||||||||||
1109 | |||||||||||
1110 | |||||||||||
1111 | |||||||||||
1112 | /** |
||||||||||
1113 | * Resize and crop images on the fly, store generated images in a cache. |
||||||||||
1114 | * |
||||||||||
1115 | * @author Mikael Roos [email protected] |
||||||||||
1116 | * @example http://dbwebb.se/opensource/cimage |
||||||||||
1117 | * @link https://github.com/mosbth/cimage |
||||||||||
1118 | */ |
||||||||||
1119 | class CImage |
||||||||||
1120 | { |
||||||||||
1121 | |||||||||||
1122 | /** |
||||||||||
1123 | * Constants type of PNG image |
||||||||||
1124 | */ |
||||||||||
1125 | const PNG_GREYSCALE = 0; |
||||||||||
1126 | const PNG_RGB = 2; |
||||||||||
1127 | const PNG_RGB_PALETTE = 3; |
||||||||||
1128 | const PNG_GREYSCALE_ALPHA = 4; |
||||||||||
1129 | const PNG_RGB_ALPHA = 6; |
||||||||||
1130 | |||||||||||
1131 | |||||||||||
1132 | |||||||||||
1133 | /** |
||||||||||
1134 | * Constant for default image quality when not set |
||||||||||
1135 | */ |
||||||||||
1136 | const JPEG_QUALITY_DEFAULT = 60; |
||||||||||
1137 | |||||||||||
1138 | |||||||||||
1139 | |||||||||||
1140 | /** |
||||||||||
1141 | * Quality level for JPEG images. |
||||||||||
1142 | */ |
||||||||||
1143 | private $quality; |
||||||||||
1144 | |||||||||||
1145 | |||||||||||
1146 | |||||||||||
1147 | /** |
||||||||||
1148 | * Is the quality level set from external use (true) or is it default (false)? |
||||||||||
1149 | */ |
||||||||||
1150 | private $useQuality = false; |
||||||||||
1151 | |||||||||||
1152 | |||||||||||
1153 | |||||||||||
1154 | /** |
||||||||||
1155 | * Constant for default image quality when not set |
||||||||||
1156 | */ |
||||||||||
1157 | const PNG_COMPRESSION_DEFAULT = -1; |
||||||||||
1158 | |||||||||||
1159 | |||||||||||
1160 | |||||||||||
1161 | /** |
||||||||||
1162 | * Compression level for PNG images. |
||||||||||
1163 | */ |
||||||||||
1164 | private $compress; |
||||||||||
1165 | |||||||||||
1166 | |||||||||||
1167 | |||||||||||
1168 | /** |
||||||||||
1169 | * Is the compress level set from external use (true) or is it default (false)? |
||||||||||
1170 | */ |
||||||||||
1171 | private $useCompress = false; |
||||||||||
1172 | |||||||||||
1173 | |||||||||||
1174 | |||||||||||
1175 | |||||||||||
1176 | /** |
||||||||||
1177 | * Add HTTP headers for outputing image. |
||||||||||
1178 | */ |
||||||||||
1179 | private $HTTPHeader = array(); |
||||||||||
1180 | |||||||||||
1181 | |||||||||||
1182 | |||||||||||
1183 | /** |
||||||||||
1184 | * Default background color, red, green, blue, alpha. |
||||||||||
1185 | * |
||||||||||
1186 | * @todo remake when upgrading to PHP 5.5 |
||||||||||
1187 | */ |
||||||||||
1188 | /* |
||||||||||
1189 | const BACKGROUND_COLOR = array( |
||||||||||
1190 | 'red' => 0, |
||||||||||
1191 | 'green' => 0, |
||||||||||
1192 | 'blue' => 0, |
||||||||||
1193 | 'alpha' => null, |
||||||||||
1194 | );*/ |
||||||||||
1195 | |||||||||||
1196 | |||||||||||
1197 | |||||||||||
1198 | /** |
||||||||||
1199 | * Default background color to use. |
||||||||||
1200 | * |
||||||||||
1201 | * @todo remake when upgrading to PHP 5.5 |
||||||||||
1202 | */ |
||||||||||
1203 | //private $bgColorDefault = self::BACKGROUND_COLOR; |
||||||||||
1204 | private $bgColorDefault = array( |
||||||||||
1205 | 'red' => 0, |
||||||||||
1206 | 'green' => 0, |
||||||||||
1207 | 'blue' => 0, |
||||||||||
1208 | 'alpha' => null, |
||||||||||
1209 | ); |
||||||||||
1210 | |||||||||||
1211 | |||||||||||
1212 | /** |
||||||||||
1213 | * Background color to use, specified as part of options. |
||||||||||
1214 | */ |
||||||||||
1215 | private $bgColor; |
||||||||||
1216 | |||||||||||
1217 | |||||||||||
1218 | |||||||||||
1219 | /** |
||||||||||
1220 | * Where to save the target file. |
||||||||||
1221 | */ |
||||||||||
1222 | private $saveFolder; |
||||||||||
1223 | |||||||||||
1224 | |||||||||||
1225 | |||||||||||
1226 | /** |
||||||||||
1227 | * The working image object. |
||||||||||
1228 | */ |
||||||||||
1229 | private $image; |
||||||||||
1230 | |||||||||||
1231 | |||||||||||
1232 | |||||||||||
1233 | /** |
||||||||||
1234 | * Image filename, may include subdirectory, relative from $imageFolder |
||||||||||
1235 | */ |
||||||||||
1236 | private $imageSrc; |
||||||||||
1237 | |||||||||||
1238 | |||||||||||
1239 | |||||||||||
1240 | /** |
||||||||||
1241 | * Actual path to the image, $imageFolder . '/' . $imageSrc |
||||||||||
1242 | */ |
||||||||||
1243 | private $pathToImage; |
||||||||||
1244 | |||||||||||
1245 | |||||||||||
1246 | |||||||||||
1247 | /** |
||||||||||
1248 | * File type for source image, as provided by getimagesize() |
||||||||||
1249 | */ |
||||||||||
1250 | private $fileType; |
||||||||||
1251 | |||||||||||
1252 | |||||||||||
1253 | |||||||||||
1254 | /** |
||||||||||
1255 | * File extension to use when saving image. |
||||||||||
1256 | */ |
||||||||||
1257 | private $extension; |
||||||||||
1258 | |||||||||||
1259 | |||||||||||
1260 | |||||||||||
1261 | /** |
||||||||||
1262 | * Output format, supports null (image) or json. |
||||||||||
1263 | */ |
||||||||||
1264 | private $outputFormat = null; |
||||||||||
1265 | |||||||||||
1266 | |||||||||||
1267 | |||||||||||
1268 | /** |
||||||||||
1269 | * Do lossy output using external postprocessing tools. |
||||||||||
1270 | */ |
||||||||||
1271 | private $lossy = null; |
||||||||||
1272 | |||||||||||
1273 | |||||||||||
1274 | |||||||||||
1275 | /** |
||||||||||
1276 | * Verbose mode to print out a trace and display the created image |
||||||||||
1277 | */ |
||||||||||
1278 | private $verbose = false; |
||||||||||
1279 | |||||||||||
1280 | |||||||||||
1281 | |||||||||||
1282 | /** |
||||||||||
1283 | * Keep a log/trace on what happens |
||||||||||
1284 | */ |
||||||||||
1285 | private $log = array(); |
||||||||||
1286 | |||||||||||
1287 | |||||||||||
1288 | |||||||||||
1289 | /** |
||||||||||
1290 | * Handle image as palette image |
||||||||||
1291 | */ |
||||||||||
1292 | private $palette; |
||||||||||
1293 | |||||||||||
1294 | |||||||||||
1295 | |||||||||||
1296 | /** |
||||||||||
1297 | * Target filename, with path, to save resulting image in. |
||||||||||
1298 | */ |
||||||||||
1299 | private $cacheFileName; |
||||||||||
1300 | |||||||||||
1301 | |||||||||||
1302 | |||||||||||
1303 | /** |
||||||||||
1304 | * Set a format to save image as, or null to use original format. |
||||||||||
1305 | */ |
||||||||||
1306 | private $saveAs; |
||||||||||
1307 | |||||||||||
1308 | |||||||||||
1309 | /** |
||||||||||
1310 | * Path to command for lossy optimize, for example pngquant. |
||||||||||
1311 | */ |
||||||||||
1312 | private $pngLossy; |
||||||||||
1313 | private $pngLossyCmd; |
||||||||||
1314 | |||||||||||
1315 | |||||||||||
1316 | |||||||||||
1317 | /** |
||||||||||
1318 | * Path to command for filter optimize, for example optipng. |
||||||||||
1319 | */ |
||||||||||
1320 | private $pngFilter; |
||||||||||
1321 | private $pngFilterCmd; |
||||||||||
1322 | |||||||||||
1323 | |||||||||||
1324 | |||||||||||
1325 | /** |
||||||||||
1326 | * Path to command for deflate optimize, for example pngout. |
||||||||||
1327 | */ |
||||||||||
1328 | private $pngDeflate; |
||||||||||
1329 | private $pngDeflateCmd; |
||||||||||
1330 | |||||||||||
1331 | |||||||||||
1332 | |||||||||||
1333 | /** |
||||||||||
1334 | * Path to command to optimize jpeg images, for example jpegtran or null. |
||||||||||
1335 | */ |
||||||||||
1336 | private $jpegOptimize; |
||||||||||
1337 | private $jpegOptimizeCmd; |
||||||||||
1338 | |||||||||||
1339 | |||||||||||
1340 | |||||||||||
1341 | /** |
||||||||||
1342 | * Image dimensions, calculated from loaded image. |
||||||||||
1343 | */ |
||||||||||
1344 | private $width; // Calculated from source image |
||||||||||
1345 | private $height; // Calculated from source image |
||||||||||
1346 | |||||||||||
1347 | |||||||||||
1348 | /** |
||||||||||
1349 | * New image dimensions, incoming as argument or calculated. |
||||||||||
1350 | */ |
||||||||||
1351 | private $newWidth; |
||||||||||
1352 | private $newWidthOrig; // Save original value |
||||||||||
1353 | private $newHeight; |
||||||||||
1354 | private $newHeightOrig; // Save original value |
||||||||||
1355 | |||||||||||
1356 | |||||||||||
1357 | /** |
||||||||||
1358 | * Change target height & width when different dpr, dpr 2 means double image dimensions. |
||||||||||
1359 | */ |
||||||||||
1360 | private $dpr = 1; |
||||||||||
1361 | |||||||||||
1362 | |||||||||||
1363 | /** |
||||||||||
1364 | * Always upscale images, even if they are smaller than target image. |
||||||||||
1365 | */ |
||||||||||
1366 | const UPSCALE_DEFAULT = true; |
||||||||||
1367 | private $upscale = self::UPSCALE_DEFAULT; |
||||||||||
1368 | |||||||||||
1369 | |||||||||||
1370 | |||||||||||
1371 | /** |
||||||||||
1372 | * Array with details on how to crop, incoming as argument and calculated. |
||||||||||
1373 | */ |
||||||||||
1374 | public $crop; |
||||||||||
1375 | public $cropOrig; // Save original value |
||||||||||
1376 | |||||||||||
1377 | |||||||||||
1378 | /** |
||||||||||
1379 | * String with details on how to do image convolution. String |
||||||||||
1380 | * should map a key in the $convolvs array or be a string of |
||||||||||
1381 | * 11 float values separated by comma. The first nine builds |
||||||||||
1382 | * up the matrix, then divisor and last offset. |
||||||||||
1383 | */ |
||||||||||
1384 | private $convolve; |
||||||||||
1385 | |||||||||||
1386 | |||||||||||
1387 | /** |
||||||||||
1388 | * Custom convolution expressions, matrix 3x3, divisor and offset. |
||||||||||
1389 | */ |
||||||||||
1390 | private $convolves = array( |
||||||||||
1391 | 'lighten' => '0,0,0, 0,12,0, 0,0,0, 9, 0', |
||||||||||
1392 | 'darken' => '0,0,0, 0,6,0, 0,0,0, 9, 0', |
||||||||||
1393 | 'sharpen' => '-1,-1,-1, -1,16,-1, -1,-1,-1, 8, 0', |
||||||||||
1394 | 'sharpen-alt' => '0,-1,0, -1,5,-1, 0,-1,0, 1, 0', |
||||||||||
1395 | 'emboss' => '1,1,-1, 1,3,-1, 1,-1,-1, 3, 0', |
||||||||||
1396 | 'emboss-alt' => '-2,-1,0, -1,1,1, 0,1,2, 1, 0', |
||||||||||
1397 | 'blur' => '1,1,1, 1,15,1, 1,1,1, 23, 0', |
||||||||||
1398 | 'gblur' => '1,2,1, 2,4,2, 1,2,1, 16, 0', |
||||||||||
1399 | 'edge' => '-1,-1,-1, -1,8,-1, -1,-1,-1, 9, 0', |
||||||||||
1400 | 'edge-alt' => '0,1,0, 1,-4,1, 0,1,0, 1, 0', |
||||||||||
1401 | 'draw' => '0,-1,0, -1,5,-1, 0,-1,0, 0, 0', |
||||||||||
1402 | 'mean' => '1,1,1, 1,1,1, 1,1,1, 9, 0', |
||||||||||
1403 | 'motion' => '1,0,0, 0,1,0, 0,0,1, 3, 0', |
||||||||||
1404 | ); |
||||||||||
1405 | |||||||||||
1406 | |||||||||||
1407 | /** |
||||||||||
1408 | * Resize strategy to fill extra area with background color. |
||||||||||
1409 | * True or false. |
||||||||||
1410 | */ |
||||||||||
1411 | private $fillToFit; |
||||||||||
1412 | |||||||||||
1413 | |||||||||||
1414 | |||||||||||
1415 | /** |
||||||||||
1416 | * To store value for option scale. |
||||||||||
1417 | */ |
||||||||||
1418 | private $scale; |
||||||||||
1419 | |||||||||||
1420 | |||||||||||
1421 | |||||||||||
1422 | /** |
||||||||||
1423 | * To store value for option. |
||||||||||
1424 | */ |
||||||||||
1425 | private $rotateBefore; |
||||||||||
1426 | |||||||||||
1427 | |||||||||||
1428 | |||||||||||
1429 | /** |
||||||||||
1430 | * To store value for option. |
||||||||||
1431 | */ |
||||||||||
1432 | private $rotateAfter; |
||||||||||
1433 | |||||||||||
1434 | |||||||||||
1435 | |||||||||||
1436 | /** |
||||||||||
1437 | * To store value for option. |
||||||||||
1438 | */ |
||||||||||
1439 | private $autoRotate; |
||||||||||
1440 | |||||||||||
1441 | |||||||||||
1442 | |||||||||||
1443 | /** |
||||||||||
1444 | * To store value for option. |
||||||||||
1445 | */ |
||||||||||
1446 | private $sharpen; |
||||||||||
1447 | |||||||||||
1448 | |||||||||||
1449 | |||||||||||
1450 | /** |
||||||||||
1451 | * To store value for option. |
||||||||||
1452 | */ |
||||||||||
1453 | private $emboss; |
||||||||||
1454 | |||||||||||
1455 | |||||||||||
1456 | |||||||||||
1457 | /** |
||||||||||
1458 | * To store value for option. |
||||||||||
1459 | */ |
||||||||||
1460 | private $blur; |
||||||||||
1461 | |||||||||||
1462 | |||||||||||
1463 | |||||||||||
1464 | /** |
||||||||||
1465 | * Used with option area to set which parts of the image to use. |
||||||||||
1466 | */ |
||||||||||
1467 | private $offset; |
||||||||||
1468 | |||||||||||
1469 | |||||||||||
1470 | |||||||||||
1471 | /** |
||||||||||
1472 | * Calculate target dimension for image when using fill-to-fit resize strategy. |
||||||||||
1473 | */ |
||||||||||
1474 | private $fillWidth; |
||||||||||
1475 | private $fillHeight; |
||||||||||
1476 | |||||||||||
1477 | |||||||||||
1478 | |||||||||||
1479 | /** |
||||||||||
1480 | * Allow remote file download, default is to disallow remote file download. |
||||||||||
1481 | */ |
||||||||||
1482 | private $allowRemote = false; |
||||||||||
1483 | |||||||||||
1484 | |||||||||||
1485 | |||||||||||
1486 | /** |
||||||||||
1487 | * Path to cache for remote download. |
||||||||||
1488 | */ |
||||||||||
1489 | private $remoteCache; |
||||||||||
1490 | |||||||||||
1491 | |||||||||||
1492 | |||||||||||
1493 | /** |
||||||||||
1494 | * Pattern to recognize a remote file. |
||||||||||
1495 | */ |
||||||||||
1496 | //private $remotePattern = '#^[http|https]://#'; |
||||||||||
1497 | private $remotePattern = '#^https?://#'; |
||||||||||
1498 | |||||||||||
1499 | |||||||||||
1500 | |||||||||||
1501 | /** |
||||||||||
1502 | * Use the cache if true, set to false to ignore the cached file. |
||||||||||
1503 | */ |
||||||||||
1504 | private $useCache = true; |
||||||||||
1505 | |||||||||||
1506 | |||||||||||
1507 | /** |
||||||||||
1508 | * Disable the fasttrackCacke to start with, inject an object to enable it. |
||||||||||
1509 | */ |
||||||||||
1510 | private $fastTrackCache = null; |
||||||||||
1511 | |||||||||||
1512 | |||||||||||
1513 | |||||||||||
1514 | /* |
||||||||||
1515 | * Set whitelist for valid hostnames from where remote source can be |
||||||||||
1516 | * downloaded. |
||||||||||
1517 | */ |
||||||||||
1518 | private $remoteHostWhitelist = null; |
||||||||||
1519 | |||||||||||
1520 | |||||||||||
1521 | |||||||||||
1522 | /* |
||||||||||
1523 | * Do verbose logging to file by setting this to a filename. |
||||||||||
1524 | */ |
||||||||||
1525 | private $verboseFileName = null; |
||||||||||
1526 | |||||||||||
1527 | |||||||||||
1528 | |||||||||||
1529 | /* |
||||||||||
1530 | * Output to ascii can take som options as an array. |
||||||||||
1531 | */ |
||||||||||
1532 | private $asciiOptions = array(); |
||||||||||
1533 | |||||||||||
1534 | |||||||||||
1535 | |||||||||||
1536 | /* |
||||||||||
1537 | * Image copy strategy, defaults to RESAMPLE. |
||||||||||
1538 | */ |
||||||||||
1539 | const RESIZE = 1; |
||||||||||
1540 | const RESAMPLE = 2; |
||||||||||
1541 | private $copyStrategy = NULL; |
||||||||||
1542 | |||||||||||
1543 | |||||||||||
1544 | |||||||||||
1545 | /** |
||||||||||
1546 | * Properties, the class is mutable and the method setOptions() |
||||||||||
1547 | * decides (partly) what properties are created. |
||||||||||
1548 | * |
||||||||||
1549 | * @todo Clean up these and check if and how they are used |
||||||||||
1550 | */ |
||||||||||
1551 | |||||||||||
1552 | public $keepRatio; |
||||||||||
1553 | public $cropToFit; |
||||||||||
1554 | private $cropWidth; |
||||||||||
1555 | private $cropHeight; |
||||||||||
1556 | public $crop_x; |
||||||||||
1557 | public $crop_y; |
||||||||||
1558 | public $filters; |
||||||||||
1559 | private $attr; // Calculated from source image |
||||||||||
1560 | |||||||||||
1561 | |||||||||||
1562 | |||||||||||
1563 | |||||||||||
1564 | /** |
||||||||||
1565 | * Constructor, can take arguments to init the object. |
||||||||||
1566 | * |
||||||||||
1567 | * @param string $imageSrc filename which may contain subdirectory. |
||||||||||
1568 | * @param string $imageFolder path to root folder for images. |
||||||||||
1569 | * @param string $saveFolder path to folder where to save the new file or null to skip saving. |
||||||||||
1570 | * @param string $saveName name of target file when saveing. |
||||||||||
1571 | */ |
||||||||||
1572 | public function __construct($imageSrc = null, $imageFolder = null, $saveFolder = null, $saveName = null) |
||||||||||
1573 | { |
||||||||||
1574 | $this->setSource($imageSrc, $imageFolder); |
||||||||||
1575 | $this->setTarget($saveFolder, $saveName); |
||||||||||
1576 | } |
||||||||||
1577 | |||||||||||
1578 | |||||||||||
1579 | |||||||||||
1580 | /** |
||||||||||
1581 | * Inject object and use it, must be available as member. |
||||||||||
1582 | * |
||||||||||
1583 | * @param string $property to set as object. |
||||||||||
1584 | * @param object $object to set to property. |
||||||||||
1585 | * |
||||||||||
1586 | * @return $this |
||||||||||
1587 | */ |
||||||||||
1588 | public function injectDependency($property, $object) |
||||||||||
1589 | { |
||||||||||
1590 | if (!property_exists($this, $property)) { |
||||||||||
1591 | $this->raiseError("Injecting unknown property."); |
||||||||||
1592 | } |
||||||||||
1593 | $this->$property = $object; |
||||||||||
1594 | return $this; |
||||||||||
1595 | } |
||||||||||
1596 | |||||||||||
1597 | |||||||||||
1598 | |||||||||||
1599 | /** |
||||||||||
1600 | * Set verbose mode. |
||||||||||
1601 | * |
||||||||||
1602 | * @param boolean $mode true or false to enable and disable verbose mode, |
||||||||||
1603 | * default is true. |
||||||||||
1604 | * |
||||||||||
1605 | * @return $this |
||||||||||
1606 | */ |
||||||||||
1607 | public function setVerbose($mode = true) |
||||||||||
1608 | { |
||||||||||
1609 | $this->verbose = $mode; |
||||||||||
1610 | return $this; |
||||||||||
1611 | } |
||||||||||
1612 | |||||||||||
1613 | |||||||||||
1614 | |||||||||||
1615 | /** |
||||||||||
1616 | * Set save folder, base folder for saving cache files. |
||||||||||
1617 | * |
||||||||||
1618 | * @todo clean up how $this->saveFolder is used in other methods. |
||||||||||
1619 | * |
||||||||||
1620 | * @param string $path where to store cached files. |
||||||||||
1621 | * |
||||||||||
1622 | * @return $this |
||||||||||
1623 | */ |
||||||||||
1624 | public function setSaveFolder($path) |
||||||||||
1625 | { |
||||||||||
1626 | $this->saveFolder = $path; |
||||||||||
1627 | return $this; |
||||||||||
1628 | } |
||||||||||
1629 | |||||||||||
1630 | |||||||||||
1631 | |||||||||||
1632 | /** |
||||||||||
1633 | * Use cache or not. |
||||||||||
1634 | * |
||||||||||
1635 | * @param boolean $use true or false to use cache. |
||||||||||
1636 | * |
||||||||||
1637 | * @return $this |
||||||||||
1638 | */ |
||||||||||
1639 | public function useCache($use = true) |
||||||||||
1640 | { |
||||||||||
1641 | $this->useCache = $use; |
||||||||||
1642 | return $this; |
||||||||||
1643 | } |
||||||||||
1644 | |||||||||||
1645 | |||||||||||
1646 | |||||||||||
1647 | /** |
||||||||||
1648 | * Create and save a dummy image. Use dimensions as stated in |
||||||||||
1649 | * $this->newWidth, or $width or default to 100 (same for height. |
||||||||||
1650 | * |
||||||||||
1651 | * @param integer $width use specified width for image dimension. |
||||||||||
1652 | * @param integer $height use specified width for image dimension. |
||||||||||
1653 | * |
||||||||||
1654 | * @return $this |
||||||||||
1655 | */ |
||||||||||
1656 | public function createDummyImage($width = null, $height = null) |
||||||||||
1657 | { |
||||||||||
1658 | $this->newWidth = $this->newWidth ?: $width ?: 100; |
||||||||||
1659 | $this->newHeight = $this->newHeight ?: $height ?: 100; |
||||||||||
1660 | |||||||||||
1661 | $this->image = $this->CreateImageKeepTransparency($this->newWidth, $this->newHeight); |
||||||||||
1662 | |||||||||||
1663 | return $this; |
||||||||||
1664 | } |
||||||||||
1665 | |||||||||||
1666 | |||||||||||
1667 | |||||||||||
1668 | /** |
||||||||||
1669 | * Allow or disallow remote image download. |
||||||||||
1670 | * |
||||||||||
1671 | * @param boolean $allow true or false to enable and disable. |
||||||||||
1672 | * @param string $cache path to cache dir. |
||||||||||
1673 | * @param string $pattern to use to detect if its a remote file. |
||||||||||
1674 | * |
||||||||||
1675 | * @return $this |
||||||||||
1676 | */ |
||||||||||
1677 | public function setRemoteDownload($allow, $cache, $pattern = null) |
||||||||||
1678 | { |
||||||||||
1679 | $this->allowRemote = $allow; |
||||||||||
1680 | $this->remoteCache = $cache; |
||||||||||
1681 | $this->remotePattern = is_null($pattern) ? $this->remotePattern : $pattern; |
||||||||||
1682 | |||||||||||
1683 | $this->log( |
||||||||||
1684 | "Set remote download to: " |
||||||||||
1685 | . ($this->allowRemote ? "true" : "false") |
||||||||||
1686 | . " using pattern " |
||||||||||
1687 | . $this->remotePattern |
||||||||||
1688 | ); |
||||||||||
1689 | |||||||||||
1690 | return $this; |
||||||||||
1691 | } |
||||||||||
1692 | |||||||||||
1693 | |||||||||||
1694 | |||||||||||
1695 | /** |
||||||||||
1696 | * Check if the image resource is a remote file or not. |
||||||||||
1697 | * |
||||||||||
1698 | * @param string $src check if src is remote. |
||||||||||
1699 | * |
||||||||||
1700 | * @return boolean true if $src is a remote file, else false. |
||||||||||
1701 | */ |
||||||||||
1702 | public function isRemoteSource($src) |
||||||||||
1703 | { |
||||||||||
1704 | $remote = preg_match($this->remotePattern, $src); |
||||||||||
1705 | $this->log("Detected remote image: " . ($remote ? "true" : "false")); |
||||||||||
1706 | return !!$remote; |
||||||||||
1707 | } |
||||||||||
1708 | |||||||||||
1709 | |||||||||||
1710 | |||||||||||
1711 | /** |
||||||||||
1712 | * Set whitelist for valid hostnames from where remote source can be |
||||||||||
1713 | * downloaded. |
||||||||||
1714 | * |
||||||||||
1715 | * @param array $whitelist with regexp hostnames to allow download from. |
||||||||||
1716 | * |
||||||||||
1717 | * @return $this |
||||||||||
1718 | */ |
||||||||||
1719 | public function setRemoteHostWhitelist($whitelist = null) |
||||||||||
1720 | { |
||||||||||
1721 | $this->remoteHostWhitelist = $whitelist; |
||||||||||
1722 | $this->log( |
||||||||||
1723 | "Setting remote host whitelist to: " |
||||||||||
1724 | . (is_null($whitelist) ? "null" : print_r($whitelist, 1)) |
||||||||||
0 ignored issues
–
show
Are you sure
is_null($whitelist) ? 'n... print_r($whitelist, 1) of type string|true can be used in concatenation ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
1725 | ); |
||||||||||
1726 | return $this; |
||||||||||
1727 | } |
||||||||||
1728 | |||||||||||
1729 | |||||||||||
1730 | |||||||||||
1731 | /** |
||||||||||
1732 | * Check if the hostname for the remote image, is on a whitelist, |
||||||||||
1733 | * if the whitelist is defined. |
||||||||||
1734 | * |
||||||||||
1735 | * @param string $src the remote source. |
||||||||||
1736 | * |
||||||||||
1737 | * @return boolean true if hostname on $src is in the whitelist, else false. |
||||||||||
1738 | */ |
||||||||||
1739 | public function isRemoteSourceOnWhitelist($src) |
||||||||||
1740 | { |
||||||||||
1741 | if (is_null($this->remoteHostWhitelist)) { |
||||||||||
1742 | $this->log("Remote host on whitelist not configured - allowing."); |
||||||||||
1743 | return true; |
||||||||||
1744 | } |
||||||||||
1745 | |||||||||||
1746 | $whitelist = new CWhitelist(); |
||||||||||
1747 | $hostname = parse_url($src, PHP_URL_HOST); |
||||||||||
1748 | $allow = $whitelist->check($hostname, $this->remoteHostWhitelist); |
||||||||||
1749 | |||||||||||
1750 | $this->log( |
||||||||||
1751 | "Remote host is on whitelist: " |
||||||||||
1752 | . ($allow ? "true" : "false") |
||||||||||
1753 | ); |
||||||||||
1754 | return $allow; |
||||||||||
1755 | } |
||||||||||
1756 | |||||||||||
1757 | |||||||||||
1758 | |||||||||||
1759 | /** |
||||||||||
1760 | * Check if file extension is valid as a file extension. |
||||||||||
1761 | * |
||||||||||
1762 | * @param string $extension of image file. |
||||||||||
1763 | * |
||||||||||
1764 | * @return $this |
||||||||||
1765 | */ |
||||||||||
1766 | private function checkFileExtension($extension) |
||||||||||
1767 | { |
||||||||||
1768 | $valid = array('jpg', 'jpeg', 'png', 'gif', 'webp'); |
||||||||||
1769 | |||||||||||
1770 | in_array(strtolower($extension), $valid) |
||||||||||
1771 | or $this->raiseError('Not a valid file extension.'); |
||||||||||
1772 | |||||||||||
1773 | return $this; |
||||||||||
1774 | } |
||||||||||
1775 | |||||||||||
1776 | |||||||||||
1777 | |||||||||||
1778 | /** |
||||||||||
1779 | * Normalize the file extension. |
||||||||||
1780 | * |
||||||||||
1781 | * @param string $extension of image file or skip to use internal. |
||||||||||
1782 | * |
||||||||||
1783 | * @return string $extension as a normalized file extension. |
||||||||||
1784 | */ |
||||||||||
1785 | private function normalizeFileExtension($extension = null) |
||||||||||
1786 | { |
||||||||||
1787 | $extension = strtolower($extension ? $extension : $this->extension); |
||||||||||
1788 | |||||||||||
1789 | if ($extension == 'jpeg') { |
||||||||||
1790 | $extension = 'jpg'; |
||||||||||
1791 | } |
||||||||||
1792 | |||||||||||
1793 | return $extension; |
||||||||||
1794 | } |
||||||||||
1795 | |||||||||||
1796 | |||||||||||
1797 | |||||||||||
1798 | /** |
||||||||||
1799 | * Download a remote image and return path to its local copy. |
||||||||||
1800 | * |
||||||||||
1801 | * @param string $src remote path to image. |
||||||||||
1802 | * |
||||||||||
1803 | * @return string as path to downloaded remote source. |
||||||||||
1804 | */ |
||||||||||
1805 | public function downloadRemoteSource($src) |
||||||||||
1806 | { |
||||||||||
1807 | if (!$this->isRemoteSourceOnWhitelist($src)) { |
||||||||||
1808 | throw new Exception("Hostname is not on whitelist for remote sources."); |
||||||||||
1809 | } |
||||||||||
1810 | |||||||||||
1811 | $remote = new CRemoteImage(); |
||||||||||
1812 | |||||||||||
1813 | if (!is_writable($this->remoteCache)) { |
||||||||||
1814 | $this->log("The remote cache is not writable."); |
||||||||||
1815 | } |
||||||||||
1816 | |||||||||||
1817 | $remote->setCache($this->remoteCache); |
||||||||||
1818 | $remote->useCache($this->useCache); |
||||||||||
1819 | $src = $remote->download($src); |
||||||||||
1820 | |||||||||||
1821 | $this->log("Remote HTTP status: " . $remote->getStatus()); |
||||||||||
1822 | $this->log("Remote item is in local cache: $src"); |
||||||||||
1823 | $this->log("Remote details on cache:" . print_r($remote->getDetails(), true)); |
||||||||||
0 ignored issues
–
show
Are you sure
print_r($remote->getDetails(), true) of type string|true can be used in concatenation ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
1824 | |||||||||||
1825 | return $src; |
||||||||||
1826 | } |
||||||||||
1827 | |||||||||||
1828 | |||||||||||
1829 | |||||||||||
1830 | /** |
||||||||||
1831 | * Set source file to use as image source. |
||||||||||
1832 | * |
||||||||||
1833 | * @param string $src of image. |
||||||||||
1834 | * @param string $dir as optional base directory where images are. |
||||||||||
1835 | * |
||||||||||
1836 | * @return $this |
||||||||||
1837 | */ |
||||||||||
1838 | public function setSource($src, $dir = null) |
||||||||||
1839 | { |
||||||||||
1840 | if (!isset($src)) { |
||||||||||
1841 | $this->imageSrc = null; |
||||||||||
1842 | $this->pathToImage = null; |
||||||||||
1843 | return $this; |
||||||||||
1844 | } |
||||||||||
1845 | |||||||||||
1846 | if ($this->allowRemote && $this->isRemoteSource($src)) { |
||||||||||
1847 | $src = $this->downloadRemoteSource($src); |
||||||||||
1848 | $dir = null; |
||||||||||
1849 | } |
||||||||||
1850 | |||||||||||
1851 | if (!isset($dir)) { |
||||||||||
1852 | $dir = dirname($src); |
||||||||||
1853 | $src = basename($src); |
||||||||||
1854 | } |
||||||||||
1855 | |||||||||||
1856 | $this->imageSrc = ltrim($src, '/'); |
||||||||||
1857 | $imageFolder = rtrim($dir, '/'); |
||||||||||
1858 | $this->pathToImage = $imageFolder . '/' . $this->imageSrc; |
||||||||||
1859 | |||||||||||
1860 | return $this; |
||||||||||
1861 | } |
||||||||||
1862 | |||||||||||
1863 | |||||||||||
1864 | |||||||||||
1865 | /** |
||||||||||
1866 | * Set target file. |
||||||||||
1867 | * |
||||||||||
1868 | * @param string $src of target image. |
||||||||||
1869 | * @param string $dir as optional base directory where images are stored. |
||||||||||
1870 | * Uses $this->saveFolder if null. |
||||||||||
1871 | * |
||||||||||
1872 | * @return $this |
||||||||||
1873 | */ |
||||||||||
1874 | public function setTarget($src = null, $dir = null) |
||||||||||
1875 | { |
||||||||||
1876 | if (!isset($src)) { |
||||||||||
1877 | $this->cacheFileName = null; |
||||||||||
1878 | return $this; |
||||||||||
1879 | } |
||||||||||
1880 | |||||||||||
1881 | if (isset($dir)) { |
||||||||||
1882 | $this->saveFolder = rtrim($dir, '/'); |
||||||||||
1883 | } |
||||||||||
1884 | |||||||||||
1885 | $this->cacheFileName = $this->saveFolder . '/' . $src; |
||||||||||
1886 | |||||||||||
1887 | // Sanitize filename |
||||||||||
1888 | $this->cacheFileName = preg_replace('/^a-zA-Z0-9\.-_/', '', $this->cacheFileName); |
||||||||||
1889 | $this->log("The cache file name is: " . $this->cacheFileName); |
||||||||||
1890 | |||||||||||
1891 | return $this; |
||||||||||
1892 | } |
||||||||||
1893 | |||||||||||
1894 | |||||||||||
1895 | |||||||||||
1896 | /** |
||||||||||
1897 | * Get filename of target file. |
||||||||||
1898 | * |
||||||||||
1899 | * @return Boolean|String as filename of target or false if not set. |
||||||||||
1900 | */ |
||||||||||
1901 | public function getTarget() |
||||||||||
1902 | { |
||||||||||
1903 | return $this->cacheFileName; |
||||||||||
1904 | } |
||||||||||
1905 | |||||||||||
1906 | |||||||||||
1907 | |||||||||||
1908 | /** |
||||||||||
1909 | * Set options to use when processing image. |
||||||||||
1910 | * |
||||||||||
1911 | * @param array $args used when processing image. |
||||||||||
1912 | * |
||||||||||
1913 | * @return $this |
||||||||||
1914 | */ |
||||||||||
1915 | public function setOptions($args) |
||||||||||
1916 | { |
||||||||||
1917 | $this->log("Set new options for processing image."); |
||||||||||
1918 | |||||||||||
1919 | $defaults = array( |
||||||||||
1920 | // Options for calculate dimensions |
||||||||||
1921 | 'newWidth' => null, |
||||||||||
1922 | 'newHeight' => null, |
||||||||||
1923 | 'aspectRatio' => null, |
||||||||||
1924 | 'keepRatio' => true, |
||||||||||
1925 | 'cropToFit' => false, |
||||||||||
1926 | 'fillToFit' => null, |
||||||||||
1927 | 'crop' => null, //array('width'=>null, 'height'=>null, 'start_x'=>0, 'start_y'=>0), |
||||||||||
1928 | 'area' => null, //'0,0,0,0', |
||||||||||
1929 | 'upscale' => self::UPSCALE_DEFAULT, |
||||||||||
1930 | |||||||||||
1931 | // Options for caching or using original |
||||||||||
1932 | 'useCache' => true, |
||||||||||
1933 | 'useOriginal' => true, |
||||||||||
1934 | |||||||||||
1935 | // Pre-processing, before resizing is done |
||||||||||
1936 | 'scale' => null, |
||||||||||
1937 | 'rotateBefore' => null, |
||||||||||
1938 | 'autoRotate' => false, |
||||||||||
1939 | |||||||||||
1940 | // General options |
||||||||||
1941 | 'bgColor' => null, |
||||||||||
1942 | |||||||||||
1943 | // Post-processing, after resizing is done |
||||||||||
1944 | 'palette' => null, |
||||||||||
1945 | 'filters' => null, |
||||||||||
1946 | 'sharpen' => null, |
||||||||||
1947 | 'emboss' => null, |
||||||||||
1948 | 'blur' => null, |
||||||||||
1949 | 'convolve' => null, |
||||||||||
1950 | 'rotateAfter' => null, |
||||||||||
1951 | |||||||||||
1952 | // Output format |
||||||||||
1953 | 'outputFormat' => null, |
||||||||||
1954 | 'dpr' => 1, |
||||||||||
1955 | |||||||||||
1956 | // Postprocessing using external tools |
||||||||||
1957 | 'lossy' => null, |
||||||||||
1958 | ); |
||||||||||
1959 | |||||||||||
1960 | // Convert crop settings from string to array |
||||||||||
1961 | if (isset($args['crop']) && !is_array($args['crop'])) { |
||||||||||
1962 | $pices = explode(',', $args['crop']); |
||||||||||
1963 | $args['crop'] = array( |
||||||||||
1964 | 'width' => $pices[0], |
||||||||||
1965 | 'height' => $pices[1], |
||||||||||
1966 | 'start_x' => $pices[2], |
||||||||||
1967 | 'start_y' => $pices[3], |
||||||||||
1968 | ); |
||||||||||
1969 | } |
||||||||||
1970 | |||||||||||
1971 | // Convert area settings from string to array |
||||||||||
1972 | if (isset($args['area']) && !is_array($args['area'])) { |
||||||||||
1973 | $pices = explode(',', $args['area']); |
||||||||||
1974 | $args['area'] = array( |
||||||||||
1975 | 'top' => $pices[0], |
||||||||||
1976 | 'right' => $pices[1], |
||||||||||
1977 | 'bottom' => $pices[2], |
||||||||||
1978 | 'left' => $pices[3], |
||||||||||
1979 | ); |
||||||||||
1980 | } |
||||||||||
1981 | |||||||||||
1982 | // Convert filter settings from array of string to array of array |
||||||||||
1983 | if (isset($args['filters']) && is_array($args['filters'])) { |
||||||||||
1984 | foreach ($args['filters'] as $key => $filterStr) { |
||||||||||
1985 | $parts = explode(',', $filterStr); |
||||||||||
1986 | $filter = $this->mapFilter($parts[0]); |
||||||||||
1987 | $filter['str'] = $filterStr; |
||||||||||
1988 | for ($i=1; $i<=$filter['argc']; $i++) { |
||||||||||
1989 | if (isset($parts[$i])) { |
||||||||||
1990 | $filter["arg{$i}"] = $parts[$i]; |
||||||||||
1991 | } else { |
||||||||||
1992 | throw new Exception( |
||||||||||
1993 | 'Missing arg to filter, review how many arguments are needed at |
||||||||||
1994 | http://php.net/manual/en/function.imagefilter.php' |
||||||||||
1995 | ); |
||||||||||
1996 | } |
||||||||||
1997 | } |
||||||||||
1998 | $args['filters'][$key] = $filter; |
||||||||||
1999 | } |
||||||||||
2000 | } |
||||||||||
2001 | |||||||||||
2002 | // Merge default arguments with incoming and set properties. |
||||||||||
2003 | //$args = array_merge_recursive($defaults, $args); |
||||||||||
2004 | $args = array_merge($defaults, $args); |
||||||||||
2005 | foreach ($defaults as $key => $val) { |
||||||||||
2006 | $this->{$key} = $args[$key]; |
||||||||||
2007 | } |
||||||||||
2008 | |||||||||||
2009 | if ($this->bgColor) { |
||||||||||
2010 | $this->setDefaultBackgroundColor($this->bgColor); |
||||||||||
2011 | } |
||||||||||
2012 | |||||||||||
2013 | // Save original values to enable re-calculating |
||||||||||
2014 | $this->newWidthOrig = $this->newWidth; |
||||||||||
2015 | $this->newHeightOrig = $this->newHeight; |
||||||||||
2016 | $this->cropOrig = $this->crop; |
||||||||||
2017 | |||||||||||
2018 | return $this; |
||||||||||
2019 | } |
||||||||||
2020 | |||||||||||
2021 | |||||||||||
2022 | |||||||||||
2023 | /** |
||||||||||
2024 | * Map filter name to PHP filter and id. |
||||||||||
2025 | * |
||||||||||
2026 | * @param string $name the name of the filter. |
||||||||||
2027 | * |
||||||||||
2028 | * @return array with filter settings |
||||||||||
2029 | * @throws Exception |
||||||||||
2030 | */ |
||||||||||
2031 | private function mapFilter($name) |
||||||||||
2032 | { |
||||||||||
2033 | $map = array( |
||||||||||
2034 | 'negate' => array('id'=>0, 'argc'=>0, 'type'=>IMG_FILTER_NEGATE), |
||||||||||
2035 | 'grayscale' => array('id'=>1, 'argc'=>0, 'type'=>IMG_FILTER_GRAYSCALE), |
||||||||||
2036 | 'brightness' => array('id'=>2, 'argc'=>1, 'type'=>IMG_FILTER_BRIGHTNESS), |
||||||||||
2037 | 'contrast' => array('id'=>3, 'argc'=>1, 'type'=>IMG_FILTER_CONTRAST), |
||||||||||
2038 | 'colorize' => array('id'=>4, 'argc'=>4, 'type'=>IMG_FILTER_COLORIZE), |
||||||||||
2039 | 'edgedetect' => array('id'=>5, 'argc'=>0, 'type'=>IMG_FILTER_EDGEDETECT), |
||||||||||
2040 | 'emboss' => array('id'=>6, 'argc'=>0, 'type'=>IMG_FILTER_EMBOSS), |
||||||||||
2041 | 'gaussian_blur' => array('id'=>7, 'argc'=>0, 'type'=>IMG_FILTER_GAUSSIAN_BLUR), |
||||||||||
2042 | 'selective_blur' => array('id'=>8, 'argc'=>0, 'type'=>IMG_FILTER_SELECTIVE_BLUR), |
||||||||||
2043 | 'mean_removal' => array('id'=>9, 'argc'=>0, 'type'=>IMG_FILTER_MEAN_REMOVAL), |
||||||||||
2044 | 'smooth' => array('id'=>10, 'argc'=>1, 'type'=>IMG_FILTER_SMOOTH), |
||||||||||
2045 | 'pixelate' => array('id'=>11, 'argc'=>2, 'type'=>IMG_FILTER_PIXELATE), |
||||||||||
2046 | ); |
||||||||||
2047 | |||||||||||
2048 | if (isset($map[$name])) { |
||||||||||
2049 | return $map[$name]; |
||||||||||
2050 | } else { |
||||||||||
2051 | throw new Exception('No such filter.'); |
||||||||||
2052 | } |
||||||||||
2053 | } |
||||||||||
2054 | |||||||||||
2055 | |||||||||||
2056 | |||||||||||
2057 | /** |
||||||||||
2058 | * Load image details from original image file. |
||||||||||
2059 | * |
||||||||||
2060 | * @param string $file the file to load or null to use $this->pathToImage. |
||||||||||
2061 | * |
||||||||||
2062 | * @return $this |
||||||||||
2063 | * @throws Exception |
||||||||||
2064 | */ |
||||||||||
2065 | public function loadImageDetails($file = null) |
||||||||||
2066 | { |
||||||||||
2067 | $file = $file ? $file : $this->pathToImage; |
||||||||||
2068 | |||||||||||
2069 | is_readable($file) |
||||||||||
0 ignored issues
–
show
It seems like
$file can also be of type null ; however, parameter $filename of is_readable() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
2070 | or $this->raiseError('Image file does not exist.'); |
||||||||||
2071 | |||||||||||
2072 | $info = list($this->width, $this->height, $this->fileType) = getimagesize($file); |
||||||||||
0 ignored issues
–
show
It seems like
$file can also be of type null ; however, parameter $filename of getimagesize() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
2073 | if (empty($info)) { |
||||||||||
2074 | // To support webp |
||||||||||
2075 | $this->fileType = false; |
||||||||||
2076 | if (function_exists("exif_imagetype")) { |
||||||||||
2077 | $this->fileType = exif_imagetype($file); |
||||||||||
0 ignored issues
–
show
It seems like
$file can also be of type null ; however, parameter $filename of exif_imagetype() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
2078 | if ($this->fileType === false) { |
||||||||||
2079 | if (function_exists("imagecreatefromwebp")) { |
||||||||||
2080 | $webp = imagecreatefromwebp($file); |
||||||||||
2081 | if ($webp !== false) { |
||||||||||
2082 | $this->width = imagesx($webp); |
||||||||||
2083 | $this->height = imagesy($webp); |
||||||||||
2084 | $this->fileType = IMG_WEBP; |
||||||||||
2085 | } |
||||||||||
2086 | } |
||||||||||
2087 | } |
||||||||||
2088 | } |
||||||||||
2089 | } |
||||||||||
2090 | |||||||||||
2091 | if (!$this->fileType) { |
||||||||||
2092 | throw new Exception("Loading image details, the file doesn't seem to be a valid image."); |
||||||||||
2093 | } |
||||||||||
2094 | |||||||||||
2095 | if ($this->verbose) { |
||||||||||
2096 | $this->log("Loading image details for: {$file}"); |
||||||||||
2097 | $this->log(" Image width x height (type): {$this->width} x {$this->height} ({$this->fileType})."); |
||||||||||
2098 | $this->log(" Image filesize: " . filesize($file) . " bytes."); |
||||||||||
0 ignored issues
–
show
It seems like
$file can also be of type null ; however, parameter $filename of filesize() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
2099 | $this->log(" Image mimetype: " . $this->getMimeType()); |
||||||||||
0 ignored issues
–
show
Are you sure
$this->getMimeType() of type CImage can be used in concatenation ? Consider adding a __toString() -method.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
2100 | } |
||||||||||
2101 | |||||||||||
2102 | return $this; |
||||||||||
2103 | } |
||||||||||
2104 | |||||||||||
2105 | |||||||||||
2106 | |||||||||||
2107 | /** |
||||||||||
2108 | * Get mime type for image type. |
||||||||||
2109 | * |
||||||||||
2110 | * @return $this |
||||||||||
2111 | * @throws Exception |
||||||||||
2112 | */ |
||||||||||
2113 | protected function getMimeType() |
||||||||||
2114 | { |
||||||||||
2115 | if ($this->fileType === IMG_WEBP) { |
||||||||||
2116 | return "image/webp"; |
||||||||||
0 ignored issues
–
show
|
|||||||||||
2117 | } |
||||||||||
2118 | |||||||||||
2119 | return image_type_to_mime_type($this->fileType); |
||||||||||
0 ignored issues
–
show
|
|||||||||||
2120 | } |
||||||||||
2121 | |||||||||||
2122 | |||||||||||
2123 | |||||||||||
2124 | /** |
||||||||||
2125 | * Init new width and height and do some sanity checks on constraints, before any |
||||||||||
2126 | * processing can be done. |
||||||||||
2127 | * |
||||||||||
2128 | * @return $this |
||||||||||
2129 | * @throws Exception |
||||||||||
2130 | */ |
||||||||||
2131 | public function initDimensions() |
||||||||||
2132 | { |
||||||||||
2133 | $this->log("Init dimension (before) newWidth x newHeight is {$this->newWidth} x {$this->newHeight}."); |
||||||||||
2134 | |||||||||||
2135 | // width as % |
||||||||||
2136 | if ($this->newWidth |
||||||||||
2137 | && $this->newWidth[strlen($this->newWidth)-1] == '%') { |
||||||||||
2138 | $this->newWidth = $this->width * substr($this->newWidth, 0, -1) / 100; |
||||||||||
2139 | $this->log("Setting new width based on % to {$this->newWidth}"); |
||||||||||
2140 | } |
||||||||||
2141 | |||||||||||
2142 | // height as % |
||||||||||
2143 | if ($this->newHeight |
||||||||||
2144 | && $this->newHeight[strlen($this->newHeight)-1] == '%') { |
||||||||||
2145 | $this->newHeight = $this->height * substr($this->newHeight, 0, -1) / 100; |
||||||||||
2146 | $this->log("Setting new height based on % to {$this->newHeight}"); |
||||||||||
2147 | } |
||||||||||
2148 | |||||||||||
2149 | is_null($this->aspectRatio) or is_numeric($this->aspectRatio) or $this->raiseError('Aspect ratio out of range'); |
||||||||||
0 ignored issues
–
show
|
|||||||||||
2150 | |||||||||||
2151 | // width & height from aspect ratio |
||||||||||
2152 | if ($this->aspectRatio && is_null($this->newWidth) && is_null($this->newHeight)) { |
||||||||||
2153 | if ($this->aspectRatio >= 1) { |
||||||||||
2154 | $this->newWidth = $this->width; |
||||||||||
2155 | $this->newHeight = $this->width / $this->aspectRatio; |
||||||||||
2156 | $this->log("Setting new width & height based on width & aspect ratio (>=1) to (w x h) {$this->newWidth} x {$this->newHeight}"); |
||||||||||
2157 | |||||||||||
2158 | } else { |
||||||||||
2159 | $this->newHeight = $this->height; |
||||||||||
2160 | $this->newWidth = $this->height * $this->aspectRatio; |
||||||||||
2161 | $this->log("Setting new width & height based on width & aspect ratio (<1) to (w x h) {$this->newWidth} x {$this->newHeight}"); |
||||||||||
2162 | } |
||||||||||
2163 | |||||||||||
2164 | } elseif ($this->aspectRatio && is_null($this->newWidth)) { |
||||||||||
2165 | $this->newWidth = $this->newHeight * $this->aspectRatio; |
||||||||||
2166 | $this->log("Setting new width based on aspect ratio to {$this->newWidth}"); |
||||||||||
2167 | |||||||||||
2168 | } elseif ($this->aspectRatio && is_null($this->newHeight)) { |
||||||||||
2169 | $this->newHeight = $this->newWidth / $this->aspectRatio; |
||||||||||
2170 | $this->log("Setting new height based on aspect ratio to {$this->newHeight}"); |
||||||||||
2171 | } |
||||||||||
2172 | |||||||||||
2173 | // Change width & height based on dpr |
||||||||||
2174 | if ($this->dpr != 1) { |
||||||||||
2175 | if (!is_null($this->newWidth)) { |
||||||||||
2176 | $this->newWidth = round($this->newWidth * $this->dpr); |
||||||||||
2177 | $this->log("Setting new width based on dpr={$this->dpr} - w={$this->newWidth}"); |
||||||||||
2178 | } |
||||||||||
2179 | if (!is_null($this->newHeight)) { |
||||||||||
2180 | $this->newHeight = round($this->newHeight * $this->dpr); |
||||||||||
2181 | $this->log("Setting new height based on dpr={$this->dpr} - h={$this->newHeight}"); |
||||||||||
2182 | } |
||||||||||
2183 | } |
||||||||||
2184 | |||||||||||
2185 | // Check values to be within domain |
||||||||||
2186 | is_null($this->newWidth) |
||||||||||
2187 | or is_numeric($this->newWidth) |
||||||||||
2188 | or $this->raiseError('Width not numeric'); |
||||||||||
2189 | |||||||||||
2190 | is_null($this->newHeight) |
||||||||||
2191 | or is_numeric($this->newHeight) |
||||||||||
2192 | or $this->raiseError('Height not numeric'); |
||||||||||
2193 | |||||||||||
2194 | $this->log("Init dimension (after) newWidth x newHeight is {$this->newWidth} x {$this->newHeight}."); |
||||||||||
2195 | |||||||||||
2196 | return $this; |
||||||||||
2197 | } |
||||||||||
2198 | |||||||||||
2199 | |||||||||||
2200 | |||||||||||
2201 | /** |
||||||||||
2202 | * Calculate new width and height of image, based on settings. |
||||||||||
2203 | * |
||||||||||
2204 | * @return $this |
||||||||||
2205 | */ |
||||||||||
2206 | public function calculateNewWidthAndHeight() |
||||||||||
2207 | { |
||||||||||
2208 | // Crop, use cropped width and height as base for calulations |
||||||||||
2209 | $this->log("Calculate new width and height."); |
||||||||||
2210 | $this->log("Original width x height is {$this->width} x {$this->height}."); |
||||||||||
2211 | $this->log("Target dimension (before calculating) newWidth x newHeight is {$this->newWidth} x {$this->newHeight}."); |
||||||||||
2212 | |||||||||||
2213 | // Check if there is an area to crop off |
||||||||||
2214 | if (isset($this->area)) { |
||||||||||
2215 | $this->offset['top'] = round($this->area['top'] / 100 * $this->height); |
||||||||||
2216 | $this->offset['right'] = round($this->area['right'] / 100 * $this->width); |
||||||||||
2217 | $this->offset['bottom'] = round($this->area['bottom'] / 100 * $this->height); |
||||||||||
2218 | $this->offset['left'] = round($this->area['left'] / 100 * $this->width); |
||||||||||
2219 | $this->offset['width'] = $this->width - $this->offset['left'] - $this->offset['right']; |
||||||||||
2220 | $this->offset['height'] = $this->height - $this->offset['top'] - $this->offset['bottom']; |
||||||||||
2221 | $this->width = $this->offset['width']; |
||||||||||
2222 | $this->height = $this->offset['height']; |
||||||||||
2223 | $this->log("The offset for the area to use is top {$this->area['top']}%, right {$this->area['right']}%, bottom {$this->area['bottom']}%, left {$this->area['left']}%."); |
||||||||||
2224 | $this->log("The offset for the area to use is top {$this->offset['top']}px, right {$this->offset['right']}px, bottom {$this->offset['bottom']}px, left {$this->offset['left']}px, width {$this->offset['width']}px, height {$this->offset['height']}px."); |
||||||||||
2225 | } |
||||||||||
2226 | |||||||||||
2227 | $width = $this->width; |
||||||||||
2228 | $height = $this->height; |
||||||||||
2229 | |||||||||||
2230 | // Check if crop is set |
||||||||||
2231 | if ($this->crop) { |
||||||||||
2232 | $width = $this->crop['width'] = $this->crop['width'] <= 0 ? $this->width + $this->crop['width'] : $this->crop['width']; |
||||||||||
2233 | $height = $this->crop['height'] = $this->crop['height'] <= 0 ? $this->height + $this->crop['height'] : $this->crop['height']; |
||||||||||
2234 | |||||||||||
2235 | if ($this->crop['start_x'] == 'left') { |
||||||||||
2236 | $this->crop['start_x'] = 0; |
||||||||||
2237 | } elseif ($this->crop['start_x'] == 'right') { |
||||||||||
2238 | $this->crop['start_x'] = $this->width - $width; |
||||||||||
2239 | } elseif ($this->crop['start_x'] == 'center') { |
||||||||||
2240 | $this->crop['start_x'] = round($this->width / 2) - round($width / 2); |
||||||||||
2241 | } |
||||||||||
2242 | |||||||||||
2243 | if ($this->crop['start_y'] == 'top') { |
||||||||||
2244 | $this->crop['start_y'] = 0; |
||||||||||
2245 | } elseif ($this->crop['start_y'] == 'bottom') { |
||||||||||
2246 | $this->crop['start_y'] = $this->height - $height; |
||||||||||
2247 | } elseif ($this->crop['start_y'] == 'center') { |
||||||||||
2248 | $this->crop['start_y'] = round($this->height / 2) - round($height / 2); |
||||||||||
2249 | } |
||||||||||
2250 | |||||||||||
2251 | $this->log("Crop area is width {$width}px, height {$height}px, start_x {$this->crop['start_x']}px, start_y {$this->crop['start_y']}px."); |
||||||||||
2252 | } |
||||||||||
2253 | |||||||||||
2254 | // Calculate new width and height if keeping aspect-ratio. |
||||||||||
2255 | if ($this->keepRatio) { |
||||||||||
2256 | |||||||||||
2257 | $this->log("Keep aspect ratio."); |
||||||||||
2258 | |||||||||||
2259 | // Crop-to-fit and both new width and height are set. |
||||||||||
2260 | if (($this->cropToFit || $this->fillToFit) && isset($this->newWidth) && isset($this->newHeight)) { |
||||||||||
2261 | |||||||||||
2262 | // Use newWidth and newHeigh as width/height, image should fit in box. |
||||||||||
2263 | $this->log("Use newWidth and newHeigh as width/height, image should fit in box."); |
||||||||||
2264 | |||||||||||
2265 | } elseif (isset($this->newWidth) && isset($this->newHeight)) { |
||||||||||
2266 | |||||||||||
2267 | // Both new width and height are set. |
||||||||||
2268 | // Use newWidth and newHeigh as max width/height, image should not be larger. |
||||||||||
2269 | $ratioWidth = $width / $this->newWidth; |
||||||||||
2270 | $ratioHeight = $height / $this->newHeight; |
||||||||||
2271 | $ratio = ($ratioWidth > $ratioHeight) ? $ratioWidth : $ratioHeight; |
||||||||||
2272 | $this->newWidth = round($width / $ratio); |
||||||||||
2273 | $this->newHeight = round($height / $ratio); |
||||||||||
2274 | $this->log("New width and height was set."); |
||||||||||
2275 | |||||||||||
2276 | } elseif (isset($this->newWidth)) { |
||||||||||
2277 | |||||||||||
2278 | // Use new width as max-width |
||||||||||
2279 | $factor = (float)$this->newWidth / (float)$width; |
||||||||||
2280 | $this->newHeight = round($factor * $height); |
||||||||||
2281 | $this->log("New width was set."); |
||||||||||
2282 | |||||||||||
2283 | } elseif (isset($this->newHeight)) { |
||||||||||
2284 | |||||||||||
2285 | // Use new height as max-hight |
||||||||||
2286 | $factor = (float)$this->newHeight / (float)$height; |
||||||||||
2287 | $this->newWidth = round($factor * $width); |
||||||||||
2288 | $this->log("New height was set."); |
||||||||||
2289 | |||||||||||
2290 | } else { |
||||||||||
2291 | |||||||||||
2292 | // Use existing width and height as new width and height. |
||||||||||
2293 | $this->newWidth = $width; |
||||||||||
2294 | $this->newHeight = $height; |
||||||||||
2295 | } |
||||||||||
2296 | |||||||||||
2297 | |||||||||||
2298 | // Get image dimensions for pre-resize image. |
||||||||||
2299 | if ($this->cropToFit || $this->fillToFit) { |
||||||||||
2300 | |||||||||||
2301 | // Get relations of original & target image |
||||||||||
2302 | $ratioWidth = $width / $this->newWidth; |
||||||||||
2303 | $ratioHeight = $height / $this->newHeight; |
||||||||||
2304 | |||||||||||
2305 | if ($this->cropToFit) { |
||||||||||
2306 | |||||||||||
2307 | // Use newWidth and newHeigh as defined width/height, |
||||||||||
2308 | // image should fit the area. |
||||||||||
2309 | $this->log("Crop to fit."); |
||||||||||
2310 | $ratio = ($ratioWidth < $ratioHeight) ? $ratioWidth : $ratioHeight; |
||||||||||
2311 | $this->cropWidth = round($width / $ratio); |
||||||||||
2312 | $this->cropHeight = round($height / $ratio); |
||||||||||
2313 | $this->log("Crop width, height, ratio: $this->cropWidth x $this->cropHeight ($ratio)."); |
||||||||||
2314 | |||||||||||
2315 | } elseif ($this->fillToFit) { |
||||||||||
2316 | |||||||||||
2317 | // Use newWidth and newHeigh as defined width/height, |
||||||||||
2318 | // image should fit the area. |
||||||||||
2319 | $this->log("Fill to fit."); |
||||||||||
2320 | $ratio = ($ratioWidth < $ratioHeight) ? $ratioHeight : $ratioWidth; |
||||||||||
2321 | $this->fillWidth = round($width / $ratio); |
||||||||||
2322 | $this->fillHeight = round($height / $ratio); |
||||||||||
2323 | $this->log("Fill width, height, ratio: $this->fillWidth x $this->fillHeight ($ratio)."); |
||||||||||
2324 | } |
||||||||||
2325 | } |
||||||||||
2326 | } |
||||||||||
2327 | |||||||||||
2328 | // Crop, ensure to set new width and height |
||||||||||
2329 | if ($this->crop) { |
||||||||||
2330 | $this->log("Crop."); |
||||||||||
2331 | $this->newWidth = round(isset($this->newWidth) ? $this->newWidth : $this->crop['width']); |
||||||||||
2332 | $this->newHeight = round(isset($this->newHeight) ? $this->newHeight : $this->crop['height']); |
||||||||||
2333 | } |
||||||||||
2334 | |||||||||||
2335 | // Fill to fit, ensure to set new width and height |
||||||||||
2336 | /*if ($this->fillToFit) { |
||||||||||
2337 | $this->log("FillToFit."); |
||||||||||
2338 | $this->newWidth = round(isset($this->newWidth) ? $this->newWidth : $this->crop['width']); |
||||||||||
2339 | $this->newHeight = round(isset($this->newHeight) ? $this->newHeight : $this->crop['height']); |
||||||||||
2340 | }*/ |
||||||||||
2341 | |||||||||||
2342 | // No new height or width is set, use existing measures. |
||||||||||
2343 | $this->newWidth = round(isset($this->newWidth) ? $this->newWidth : $this->width); |
||||||||||
2344 | $this->newHeight = round(isset($this->newHeight) ? $this->newHeight : $this->height); |
||||||||||
2345 | $this->log("Calculated new width x height as {$this->newWidth} x {$this->newHeight}."); |
||||||||||
2346 | |||||||||||
2347 | return $this; |
||||||||||
2348 | } |
||||||||||
2349 | |||||||||||
2350 | |||||||||||
2351 | |||||||||||
2352 | /** |
||||||||||
2353 | * Re-calculate image dimensions when original image dimension has changed. |
||||||||||
2354 | * |
||||||||||
2355 | * @return $this |
||||||||||
2356 | */ |
||||||||||
2357 | public function reCalculateDimensions() |
||||||||||
2358 | { |
||||||||||
2359 | $this->log("Re-calculate image dimensions, newWidth x newHeigh was: " . $this->newWidth . " x " . $this->newHeight); |
||||||||||
2360 | |||||||||||
2361 | $this->newWidth = $this->newWidthOrig; |
||||||||||
2362 | $this->newHeight = $this->newHeightOrig; |
||||||||||
2363 | $this->crop = $this->cropOrig; |
||||||||||
2364 | |||||||||||
2365 | $this->initDimensions() |
||||||||||
2366 | ->calculateNewWidthAndHeight(); |
||||||||||
2367 | |||||||||||
2368 | return $this; |
||||||||||
2369 | } |
||||||||||
2370 | |||||||||||
2371 | |||||||||||
2372 | |||||||||||
2373 | /** |
||||||||||
2374 | * Set extension for filename to save as. |
||||||||||
2375 | * |
||||||||||
2376 | * @param string $saveas extension to save image as |
||||||||||
2377 | * |
||||||||||
2378 | * @return $this |
||||||||||
2379 | */ |
||||||||||
2380 | public function setSaveAsExtension($saveAs = null) |
||||||||||
2381 | { |
||||||||||
2382 | if (isset($saveAs)) { |
||||||||||
2383 | $saveAs = strtolower($saveAs); |
||||||||||
2384 | $this->checkFileExtension($saveAs); |
||||||||||
2385 | $this->saveAs = $saveAs; |
||||||||||
2386 | $this->extension = $saveAs; |
||||||||||
2387 | } |
||||||||||
2388 | |||||||||||
2389 | $this->log("Prepare to save image as: " . $this->extension); |
||||||||||
2390 | |||||||||||
2391 | return $this; |
||||||||||
2392 | } |
||||||||||
2393 | |||||||||||
2394 | |||||||||||
2395 | |||||||||||
2396 | /** |
||||||||||
2397 | * Set JPEG quality to use when saving image |
||||||||||
2398 | * |
||||||||||
2399 | * @param int $quality as the quality to set. |
||||||||||
2400 | * |
||||||||||
2401 | * @return $this |
||||||||||
2402 | */ |
||||||||||
2403 | public function setJpegQuality($quality = null) |
||||||||||
2404 | { |
||||||||||
2405 | if ($quality) { |
||||||||||
0 ignored issues
–
show
The expression
$quality of type integer|null is loosely compared to true ; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For 0 == false // true
0 == null // true
123 == false // false
123 == null // false
// It is often better to use strict comparison
0 === false // false
0 === null // false
![]() |
|||||||||||
2406 | $this->useQuality = true; |
||||||||||
2407 | } |
||||||||||
2408 | |||||||||||
2409 | $this->quality = isset($quality) |
||||||||||
2410 | ? $quality |
||||||||||
2411 | : self::JPEG_QUALITY_DEFAULT; |
||||||||||
2412 | |||||||||||
2413 | (is_numeric($this->quality) and $this->quality > 0 and $this->quality <= 100) |
||||||||||
2414 | or $this->raiseError('Quality not in range.'); |
||||||||||
2415 | |||||||||||
2416 | $this->log("Setting JPEG quality to {$this->quality}."); |
||||||||||
2417 | |||||||||||
2418 | return $this; |
||||||||||
2419 | } |
||||||||||
2420 | |||||||||||
2421 | |||||||||||
2422 | |||||||||||
2423 | /** |
||||||||||
2424 | * Set PNG compressen algorithm to use when saving image |
||||||||||
2425 | * |
||||||||||
2426 | * @param int $compress as the algorithm to use. |
||||||||||
2427 | * |
||||||||||
2428 | * @return $this |
||||||||||
2429 | */ |
||||||||||
2430 | public function setPngCompression($compress = null) |
||||||||||
2431 | { |
||||||||||
2432 | if ($compress) { |
||||||||||
0 ignored issues
–
show
The expression
$compress of type integer|null is loosely compared to true ; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For 0 == false // true
0 == null // true
123 == false // false
123 == null // false
// It is often better to use strict comparison
0 === false // false
0 === null // false
![]() |
|||||||||||
2433 | $this->useCompress = true; |
||||||||||
2434 | } |
||||||||||
2435 | |||||||||||
2436 | $this->compress = isset($compress) |
||||||||||
2437 | ? $compress |
||||||||||
2438 | : self::PNG_COMPRESSION_DEFAULT; |
||||||||||
2439 | |||||||||||
2440 | (is_numeric($this->compress) and $this->compress >= -1 and $this->compress <= 9) |
||||||||||
2441 | or $this->raiseError('Quality not in range.'); |
||||||||||
2442 | |||||||||||
2443 | $this->log("Setting PNG compression level to {$this->compress}."); |
||||||||||
2444 | |||||||||||
2445 | return $this; |
||||||||||
2446 | } |
||||||||||
2447 | |||||||||||
2448 | |||||||||||
2449 | |||||||||||
2450 | /** |
||||||||||
2451 | * Use original image if possible, check options which affects image processing. |
||||||||||
2452 | * |
||||||||||
2453 | * @param boolean $useOrig default is to use original if possible, else set to false. |
||||||||||
2454 | * |
||||||||||
2455 | * @return $this |
||||||||||
2456 | */ |
||||||||||
2457 | public function useOriginalIfPossible($useOrig = true) |
||||||||||
2458 | { |
||||||||||
2459 | if ($useOrig |
||||||||||
2460 | && ($this->newWidth == $this->width) |
||||||||||
2461 | && ($this->newHeight == $this->height) |
||||||||||
2462 | && !$this->area |
||||||||||
0 ignored issues
–
show
|
|||||||||||
2463 | && !$this->crop |
||||||||||
2464 | && !$this->cropToFit |
||||||||||
2465 | && !$this->fillToFit |
||||||||||
2466 | && !$this->filters |
||||||||||
2467 | && !$this->sharpen |
||||||||||
2468 | && !$this->emboss |
||||||||||
2469 | && !$this->blur |
||||||||||
2470 | && !$this->convolve |
||||||||||
2471 | && !$this->palette |
||||||||||
2472 | && !$this->useQuality |
||||||||||
2473 | && !$this->useCompress |
||||||||||
2474 | && !$this->saveAs |
||||||||||
2475 | && !$this->rotateBefore |
||||||||||
2476 | && !$this->rotateAfter |
||||||||||
2477 | && !$this->autoRotate |
||||||||||
2478 | && !$this->bgColor |
||||||||||
2479 | && ($this->upscale === self::UPSCALE_DEFAULT) |
||||||||||
2480 | && !$this->lossy |
||||||||||
2481 | ) { |
||||||||||
2482 | $this->log("Using original image."); |
||||||||||
2483 | $this->output($this->pathToImage); |
||||||||||
2484 | } |
||||||||||
2485 | |||||||||||
2486 | return $this; |
||||||||||
2487 | } |
||||||||||
2488 | |||||||||||
2489 | |||||||||||
2490 | |||||||||||
2491 | /** |
||||||||||
2492 | * Generate filename to save file in cache. |
||||||||||
2493 | * |
||||||||||
2494 | * @param string $base as optional basepath for storing file. |
||||||||||
2495 | * @param boolean $useSubdir use or skip the subdir part when creating the |
||||||||||
2496 | * filename. |
||||||||||
2497 | * @param string $prefix to add as part of filename |
||||||||||
2498 | * |
||||||||||
2499 | * @return $this |
||||||||||
2500 | */ |
||||||||||
2501 | public function generateFilename($base = null, $useSubdir = true, $prefix = null) |
||||||||||
2502 | { |
||||||||||
2503 | $filename = basename($this->pathToImage); |
||||||||||
0 ignored issues
–
show
It seems like
$this->pathToImage can also be of type null ; however, parameter $path of basename() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
2504 | $cropToFit = $this->cropToFit ? '_cf' : null; |
||||||||||
2505 | $fillToFit = $this->fillToFit ? '_ff' : null; |
||||||||||
2506 | $crop_x = $this->crop_x ? "_x{$this->crop_x}" : null; |
||||||||||
2507 | $crop_y = $this->crop_y ? "_y{$this->crop_y}" : null; |
||||||||||
2508 | $scale = $this->scale ? "_s{$this->scale}" : null; |
||||||||||
2509 | $bgColor = $this->bgColor ? "_bgc{$this->bgColor}" : null; |
||||||||||
2510 | $quality = $this->quality ? "_q{$this->quality}" : null; |
||||||||||
2511 | $compress = $this->compress ? "_co{$this->compress}" : null; |
||||||||||
2512 | $rotateBefore = $this->rotateBefore ? "_rb{$this->rotateBefore}" : null; |
||||||||||
2513 | $rotateAfter = $this->rotateAfter ? "_ra{$this->rotateAfter}" : null; |
||||||||||
2514 | $lossy = $this->lossy ? "_l" : null; |
||||||||||
2515 | |||||||||||
2516 | $saveAs = $this->normalizeFileExtension(); |
||||||||||
2517 | $saveAs = $saveAs ? "_$saveAs" : null; |
||||||||||
2518 | |||||||||||
2519 | $copyStrat = null; |
||||||||||
2520 | if ($this->copyStrategy === self::RESIZE) { |
||||||||||
2521 | $copyStrat = "_rs"; |
||||||||||
2522 | } |
||||||||||
2523 | |||||||||||
2524 | $width = $this->newWidth ? '_' . $this->newWidth : null; |
||||||||||
2525 | $height = $this->newHeight ? '_' . $this->newHeight : null; |
||||||||||
2526 | |||||||||||
2527 | $offset = isset($this->offset) |
||||||||||
2528 | ? '_o' . $this->offset['top'] . '-' . $this->offset['right'] . '-' . $this->offset['bottom'] . '-' . $this->offset['left'] |
||||||||||
2529 | : null; |
||||||||||
2530 | |||||||||||
2531 | $crop = $this->crop |
||||||||||
2532 | ? '_c' . $this->crop['width'] . '-' . $this->crop['height'] . '-' . $this->crop['start_x'] . '-' . $this->crop['start_y'] |
||||||||||
2533 | : null; |
||||||||||
2534 | |||||||||||
2535 | $filters = null; |
||||||||||
2536 | if (isset($this->filters)) { |
||||||||||
2537 | foreach ($this->filters as $filter) { |
||||||||||
2538 | if (is_array($filter)) { |
||||||||||
2539 | $filters .= "_f{$filter['id']}"; |
||||||||||
2540 | for ($i=1; $i<=$filter['argc']; $i++) { |
||||||||||
2541 | $filters .= "-".$filter["arg{$i}"]; |
||||||||||
2542 | } |
||||||||||
2543 | } |
||||||||||
2544 | } |
||||||||||
2545 | } |
||||||||||
2546 | |||||||||||
2547 | $sharpen = $this->sharpen ? 's' : null; |
||||||||||
2548 | $emboss = $this->emboss ? 'e' : null; |
||||||||||
2549 | $blur = $this->blur ? 'b' : null; |
||||||||||
2550 | $palette = $this->palette ? 'p' : null; |
||||||||||
2551 | |||||||||||
2552 | $autoRotate = $this->autoRotate ? 'ar' : null; |
||||||||||
2553 | |||||||||||
2554 | $optimize = $this->jpegOptimize ? 'o' : null; |
||||||||||
2555 | $optimize .= $this->pngFilter ? 'f' : null; |
||||||||||
2556 | $optimize .= $this->pngDeflate ? 'd' : null; |
||||||||||
2557 | |||||||||||
2558 | $convolve = null; |
||||||||||
2559 | if ($this->convolve) { |
||||||||||
2560 | $convolve = '_conv' . preg_replace('/[^a-zA-Z0-9]/', '', $this->convolve); |
||||||||||
2561 | } |
||||||||||
2562 | |||||||||||
2563 | $upscale = null; |
||||||||||
2564 | if ($this->upscale !== self::UPSCALE_DEFAULT) { |
||||||||||
2565 | $upscale = '_nu'; |
||||||||||
2566 | } |
||||||||||
2567 | |||||||||||
2568 | $subdir = null; |
||||||||||
2569 | if ($useSubdir === true) { |
||||||||||
2570 | $subdir = str_replace('/', '-', dirname($this->imageSrc)); |
||||||||||
0 ignored issues
–
show
It seems like
$this->imageSrc can also be of type null ; however, parameter $path of dirname() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
2571 | $subdir = ($subdir == '.') ? '_.' : $subdir; |
||||||||||
2572 | $subdir .= '_'; |
||||||||||
2573 | } |
||||||||||
2574 | |||||||||||
2575 | $file = $prefix . $subdir . $filename . $width . $height |
||||||||||
2576 | . $offset . $crop . $cropToFit . $fillToFit |
||||||||||
2577 | . $crop_x . $crop_y . $upscale |
||||||||||
2578 | . $quality . $filters . $sharpen . $emboss . $blur . $palette |
||||||||||
2579 | . $optimize . $compress |
||||||||||
2580 | . $scale . $rotateBefore . $rotateAfter . $autoRotate . $bgColor |
||||||||||
2581 | . $convolve . $copyStrat . $lossy . $saveAs; |
||||||||||
2582 | |||||||||||
2583 | return $this->setTarget($file, $base); |
||||||||||
2584 | } |
||||||||||
2585 | |||||||||||
2586 | |||||||||||
2587 | |||||||||||
2588 | /** |
||||||||||
2589 | * Use cached version of image, if possible. |
||||||||||
2590 | * |
||||||||||
2591 | * @param boolean $useCache is default true, set to false to avoid using cached object. |
||||||||||
2592 | * |
||||||||||
2593 | * @return $this |
||||||||||
2594 | */ |
||||||||||
2595 | public function useCacheIfPossible($useCache = true) |
||||||||||
2596 | { |
||||||||||
2597 | if ($useCache && is_readable($this->cacheFileName)) { |
||||||||||
0 ignored issues
–
show
It seems like
$this->cacheFileName can also be of type null ; however, parameter $filename of is_readable() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
2598 | $fileTime = filemtime($this->pathToImage); |
||||||||||
0 ignored issues
–
show
It seems like
$this->pathToImage can also be of type null ; however, parameter $filename of filemtime() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
2599 | $cacheTime = filemtime($this->cacheFileName); |
||||||||||
2600 | |||||||||||
2601 | if ($fileTime <= $cacheTime) { |
||||||||||
2602 | if ($this->useCache) { |
||||||||||
2603 | if ($this->verbose) { |
||||||||||
2604 | $this->log("Use cached file."); |
||||||||||
2605 | $this->log("Cached image filesize: " . filesize($this->cacheFileName) . " bytes."); |
||||||||||
0 ignored issues
–
show
It seems like
$this->cacheFileName can also be of type null ; however, parameter $filename of filesize() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
2606 | } |
||||||||||
2607 | $this->output($this->cacheFileName, $this->outputFormat); |
||||||||||
2608 | } else { |
||||||||||
2609 | $this->log("Cache is valid but ignoring it by intention."); |
||||||||||
2610 | } |
||||||||||
2611 | } else { |
||||||||||
2612 | $this->log("Original file is modified, ignoring cache."); |
||||||||||
2613 | } |
||||||||||
2614 | } else { |
||||||||||
2615 | $this->log("Cachefile does not exists or ignoring it."); |
||||||||||
2616 | } |
||||||||||
2617 | |||||||||||
2618 | return $this; |
||||||||||
2619 | } |
||||||||||
2620 | |||||||||||
2621 | |||||||||||
2622 | |||||||||||
2623 | /** |
||||||||||
2624 | * Load image from disk. Try to load image without verbose error message, |
||||||||||
2625 | * if fail, load again and display error messages. |
||||||||||
2626 | * |
||||||||||
2627 | * @param string $src of image. |
||||||||||
2628 | * @param string $dir as base directory where images are. |
||||||||||
2629 | * |
||||||||||
2630 | * @return $this |
||||||||||
2631 | * |
||||||||||
2632 | */ |
||||||||||
2633 | public function load($src = null, $dir = null) |
||||||||||
2634 | { |
||||||||||
2635 | if (isset($src)) { |
||||||||||
2636 | $this->setSource($src, $dir); |
||||||||||
2637 | } |
||||||||||
2638 | |||||||||||
2639 | $this->loadImageDetails(); |
||||||||||
2640 | |||||||||||
2641 | if ($this->fileType === IMG_WEBP) { |
||||||||||
2642 | $this->image = imagecreatefromwebp($this->pathToImage); |
||||||||||
2643 | } else { |
||||||||||
2644 | $imageAsString = file_get_contents($this->pathToImage); |
||||||||||
0 ignored issues
–
show
It seems like
$this->pathToImage can also be of type null ; however, parameter $filename of file_get_contents() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
2645 | $this->image = imagecreatefromstring($imageAsString); |
||||||||||
2646 | } |
||||||||||
2647 | if ($this->image === false) { |
||||||||||
2648 | throw new Exception("Could not load image."); |
||||||||||
2649 | } |
||||||||||
2650 | |||||||||||
2651 | /* Removed v0.7.7 |
||||||||||
2652 | if (image_type_to_mime_type($this->fileType) == 'image/png') { |
||||||||||
2653 | $type = $this->getPngType(); |
||||||||||
2654 | $hasFewColors = imagecolorstotal($this->image); |
||||||||||
2655 | |||||||||||
2656 | if ($type == self::PNG_RGB_PALETTE || ($hasFewColors > 0 && $hasFewColors <= 256)) { |
||||||||||
2657 | if ($this->verbose) { |
||||||||||
2658 | $this->log("Handle this image as a palette image."); |
||||||||||
2659 | } |
||||||||||
2660 | $this->palette = true; |
||||||||||
2661 | } |
||||||||||
2662 | } |
||||||||||
2663 | */ |
||||||||||
2664 | |||||||||||
2665 | if ($this->verbose) { |
||||||||||
2666 | $this->log("### Image successfully loaded from file."); |
||||||||||
2667 | $this->log(" imageistruecolor() : " . (imageistruecolor($this->image) ? 'true' : 'false')); |
||||||||||
2668 | $this->log(" imagecolorstotal() : " . imagecolorstotal($this->image)); |
||||||||||
2669 | $this->log(" Number of colors in image = " . $this->colorsTotal($this->image)); |
||||||||||
0 ignored issues
–
show
It seems like
$this->image can also be of type GdImage ; however, parameter $im of CImage::colorsTotal() does only seem to accept resource , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
2670 | $index = imagecolortransparent($this->image); |
||||||||||
2671 | $this->log(" Detected transparent color = " . ($index >= 0 ? implode(", ", imagecolorsforindex($this->image, $index)) : "NONE") . " at index = $index"); |
||||||||||
2672 | } |
||||||||||
2673 | |||||||||||
2674 | return $this; |
||||||||||
2675 | } |
||||||||||
2676 | |||||||||||
2677 | |||||||||||
2678 | |||||||||||
2679 | /** |
||||||||||
2680 | * Get the type of PNG image. |
||||||||||
2681 | * |
||||||||||
2682 | * @param string $filename to use instead of default. |
||||||||||
2683 | * |
||||||||||
2684 | * @return int as the type of the png-image |
||||||||||
2685 | * |
||||||||||
2686 | */ |
||||||||||
2687 | public function getPngType($filename = null) |
||||||||||
2688 | { |
||||||||||
2689 | $filename = $filename ? $filename : $this->pathToImage; |
||||||||||
2690 | |||||||||||
2691 | $pngType = ord(file_get_contents($filename, false, null, 25, 1)); |
||||||||||
0 ignored issues
–
show
It seems like
$filename can also be of type null ; however, parameter $filename of file_get_contents() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
2692 | |||||||||||
2693 | if ($this->verbose) { |
||||||||||
2694 | $this->log("Checking png type of: " . $filename); |
||||||||||
2695 | $this->log($this->getPngTypeAsString($pngType)); |
||||||||||
2696 | } |
||||||||||
2697 | |||||||||||
2698 | return $pngType; |
||||||||||
2699 | } |
||||||||||
2700 | |||||||||||
2701 | |||||||||||
2702 | |||||||||||
2703 | /** |
||||||||||
2704 | * Get the type of PNG image as a verbose string. |
||||||||||
2705 | * |
||||||||||
2706 | * @param integer $type to use, default is to check the type. |
||||||||||
2707 | * @param string $filename to use instead of default. |
||||||||||
2708 | * |
||||||||||
2709 | * @return int as the type of the png-image |
||||||||||
2710 | * |
||||||||||
2711 | */ |
||||||||||
2712 | private function getPngTypeAsString($pngType = null, $filename = null) |
||||||||||
2713 | { |
||||||||||
2714 | if ($filename || !$pngType) { |
||||||||||
2715 | $pngType = $this->getPngType($filename); |
||||||||||
2716 | } |
||||||||||
2717 | |||||||||||
2718 | $index = imagecolortransparent($this->image); |
||||||||||
2719 | $transparent = null; |
||||||||||
2720 | if ($index != -1) { |
||||||||||
2721 | $transparent = " (transparent)"; |
||||||||||
2722 | } |
||||||||||
2723 | |||||||||||
2724 | switch ($pngType) { |
||||||||||
2725 | |||||||||||
2726 | case self::PNG_GREYSCALE: |
||||||||||
2727 | $text = "PNG is type 0, Greyscale$transparent"; |
||||||||||
2728 | break; |
||||||||||
2729 | |||||||||||
2730 | case self::PNG_RGB: |
||||||||||
2731 | $text = "PNG is type 2, RGB$transparent"; |
||||||||||
2732 | break; |
||||||||||
2733 | |||||||||||
2734 | case self::PNG_RGB_PALETTE: |
||||||||||
2735 | $text = "PNG is type 3, RGB with palette$transparent"; |
||||||||||
2736 | break; |
||||||||||
2737 | |||||||||||
2738 | case self::PNG_GREYSCALE_ALPHA: |
||||||||||
2739 | $text = "PNG is type 4, Greyscale with alpha channel"; |
||||||||||
2740 | break; |
||||||||||
2741 | |||||||||||
2742 | case self::PNG_RGB_ALPHA: |
||||||||||
2743 | $text = "PNG is type 6, RGB with alpha channel (PNG 32-bit)"; |
||||||||||
2744 | break; |
||||||||||
2745 | |||||||||||
2746 | default: |
||||||||||
2747 | $text = "PNG is UNKNOWN type, is it really a PNG image?"; |
||||||||||
2748 | } |
||||||||||
2749 | |||||||||||
2750 | return $text; |
||||||||||
0 ignored issues
–
show
|
|||||||||||
2751 | } |
||||||||||
2752 | |||||||||||
2753 | |||||||||||
2754 | |||||||||||
2755 | |||||||||||
2756 | /** |
||||||||||
2757 | * Calculate number of colors in an image. |
||||||||||
2758 | * |
||||||||||
2759 | * @param resource $im the image. |
||||||||||
2760 | * |
||||||||||
2761 | * @return int |
||||||||||
2762 | */ |
||||||||||
2763 | private function colorsTotal($im) |
||||||||||
2764 | { |
||||||||||
2765 | if (imageistruecolor($im)) { |
||||||||||
2766 | $this->log("Colors as true color."); |
||||||||||
2767 | $h = imagesy($im); |
||||||||||
2768 | $w = imagesx($im); |
||||||||||
2769 | $c = array(); |
||||||||||
2770 | for ($x=0; $x < $w; $x++) { |
||||||||||
2771 | for ($y=0; $y < $h; $y++) { |
||||||||||
2772 | @$c['c'.imagecolorat($im, $x, $y)]++; |
||||||||||
2773 | } |
||||||||||
2774 | } |
||||||||||
2775 | return count($c); |
||||||||||
2776 | } else { |
||||||||||
2777 | $this->log("Colors as palette."); |
||||||||||
2778 | return imagecolorstotal($im); |
||||||||||
2779 | } |
||||||||||
2780 | } |
||||||||||
2781 | |||||||||||
2782 | |||||||||||
2783 | |||||||||||
2784 | /** |
||||||||||
2785 | * Preprocess image before rezising it. |
||||||||||
2786 | * |
||||||||||
2787 | * @return $this |
||||||||||
2788 | */ |
||||||||||
2789 | public function preResize() |
||||||||||
2790 | { |
||||||||||
2791 | $this->log("### Pre-process before resizing"); |
||||||||||
2792 | |||||||||||
2793 | // Rotate image |
||||||||||
2794 | if ($this->rotateBefore) { |
||||||||||
2795 | $this->log("Rotating image."); |
||||||||||
2796 | $this->rotate($this->rotateBefore, $this->bgColor) |
||||||||||
2797 | ->reCalculateDimensions(); |
||||||||||
2798 | } |
||||||||||
2799 | |||||||||||
2800 | // Auto-rotate image |
||||||||||
2801 | if ($this->autoRotate) { |
||||||||||
2802 | $this->log("Auto rotating image."); |
||||||||||
2803 | $this->rotateExif() |
||||||||||
2804 | ->reCalculateDimensions(); |
||||||||||
2805 | } |
||||||||||
2806 | |||||||||||
2807 | // Scale the original image before starting |
||||||||||
2808 | if (isset($this->scale)) { |
||||||||||
2809 | $this->log("Scale by {$this->scale}%"); |
||||||||||
2810 | $newWidth = $this->width * $this->scale / 100; |
||||||||||
2811 | $newHeight = $this->height * $this->scale / 100; |
||||||||||
2812 | $img = $this->CreateImageKeepTransparency($newWidth, $newHeight); |
||||||||||
2813 | imagecopyresampled($img, $this->image, 0, 0, 0, 0, $newWidth, $newHeight, $this->width, $this->height); |
||||||||||
2814 | $this->image = $img; |
||||||||||
2815 | $this->width = $newWidth; |
||||||||||
2816 | $this->height = $newHeight; |
||||||||||
2817 | } |
||||||||||
2818 | |||||||||||
2819 | return $this; |
||||||||||
2820 | } |
||||||||||
2821 | |||||||||||
2822 | |||||||||||
2823 | |||||||||||
2824 | /** |
||||||||||
2825 | * Resize or resample the image while resizing. |
||||||||||
2826 | * |
||||||||||
2827 | * @param int $strategy as CImage::RESIZE or CImage::RESAMPLE |
||||||||||
2828 | * |
||||||||||
2829 | * @return $this |
||||||||||
2830 | */ |
||||||||||
2831 | public function setCopyResizeStrategy($strategy) |
||||||||||
2832 | { |
||||||||||
2833 | $this->copyStrategy = $strategy; |
||||||||||
2834 | return $this; |
||||||||||
2835 | } |
||||||||||
2836 | |||||||||||
2837 | |||||||||||
2838 | |||||||||||
2839 | /** |
||||||||||
2840 | * Resize and or crop the image. |
||||||||||
2841 | * |
||||||||||
2842 | * @return void |
||||||||||
2843 | */ |
||||||||||
2844 | public function imageCopyResampled($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) |
||||||||||
2845 | { |
||||||||||
2846 | if($this->copyStrategy == self::RESIZE) { |
||||||||||
2847 | $this->log("Copy by resize"); |
||||||||||
2848 | imagecopyresized($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h); |
||||||||||
2849 | } else { |
||||||||||
2850 | $this->log("Copy by resample"); |
||||||||||
2851 | imagecopyresampled($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h); |
||||||||||
2852 | } |
||||||||||
2853 | } |
||||||||||
2854 | |||||||||||
2855 | |||||||||||
2856 | |||||||||||
2857 | /** |
||||||||||
2858 | * Resize and or crop the image. |
||||||||||
2859 | * |
||||||||||
2860 | * @return $this |
||||||||||
2861 | */ |
||||||||||
2862 | public function resize() |
||||||||||
2863 | { |
||||||||||
2864 | |||||||||||
2865 | $this->log("### Starting to Resize()"); |
||||||||||
2866 | $this->log("Upscale = '$this->upscale'"); |
||||||||||
2867 | |||||||||||
2868 | // Only use a specified area of the image, $this->offset is defining the area to use |
||||||||||
2869 | if (isset($this->offset)) { |
||||||||||
2870 | |||||||||||
2871 | $this->log("Offset for area to use, cropping it width={$this->offset['width']}, height={$this->offset['height']}, start_x={$this->offset['left']}, start_y={$this->offset['top']}"); |
||||||||||
2872 | $img = $this->CreateImageKeepTransparency($this->offset['width'], $this->offset['height']); |
||||||||||
2873 | imagecopy($img, $this->image, 0, 0, $this->offset['left'], $this->offset['top'], $this->offset['width'], $this->offset['height']); |
||||||||||
2874 | $this->image = $img; |
||||||||||
2875 | $this->width = $this->offset['width']; |
||||||||||
2876 | $this->height = $this->offset['height']; |
||||||||||
2877 | } |
||||||||||
2878 | |||||||||||
2879 | if ($this->crop) { |
||||||||||
2880 | |||||||||||
2881 | // Do as crop, take only part of image |
||||||||||
2882 | $this->log("Cropping area width={$this->crop['width']}, height={$this->crop['height']}, start_x={$this->crop['start_x']}, start_y={$this->crop['start_y']}"); |
||||||||||
2883 | $img = $this->CreateImageKeepTransparency($this->crop['width'], $this->crop['height']); |
||||||||||
2884 | imagecopy($img, $this->image, 0, 0, $this->crop['start_x'], $this->crop['start_y'], $this->crop['width'], $this->crop['height']); |
||||||||||
2885 | $this->image = $img; |
||||||||||
2886 | $this->width = $this->crop['width']; |
||||||||||
2887 | $this->height = $this->crop['height']; |
||||||||||
2888 | } |
||||||||||
2889 | |||||||||||
2890 | if (!$this->upscale) { |
||||||||||
2891 | // Consider rewriting the no-upscale code to fit within this if-statement, |
||||||||||
2892 | // likely to be more readable code. |
||||||||||
2893 | // The code is more or leass equal in below crop-to-fit, fill-to-fit and stretch |
||||||||||
2894 | } |
||||||||||
2895 | |||||||||||
2896 | if ($this->cropToFit) { |
||||||||||
2897 | |||||||||||
2898 | // Resize by crop to fit |
||||||||||
2899 | $this->log("Resizing using strategy - Crop to fit"); |
||||||||||
2900 | |||||||||||
2901 | if (!$this->upscale |
||||||||||
2902 | && ($this->width < $this->newWidth || $this->height < $this->newHeight)) { |
||||||||||
2903 | $this->log("Resizing - smaller image, do not upscale."); |
||||||||||
2904 | |||||||||||
2905 | $posX = 0; |
||||||||||
2906 | $posY = 0; |
||||||||||
2907 | $cropX = 0; |
||||||||||
2908 | $cropY = 0; |
||||||||||
2909 | |||||||||||
2910 | if ($this->newWidth > $this->width) { |
||||||||||
2911 | $posX = round(($this->newWidth - $this->width) / 2); |
||||||||||
2912 | } |
||||||||||
2913 | if ($this->newWidth < $this->width) { |
||||||||||
2914 | $cropX = round(($this->width/2) - ($this->newWidth/2)); |
||||||||||
2915 | } |
||||||||||
2916 | |||||||||||
2917 | if ($this->newHeight > $this->height) { |
||||||||||
2918 | $posY = round(($this->newHeight - $this->height) / 2); |
||||||||||
2919 | } |
||||||||||
2920 | if ($this->newHeight < $this->height) { |
||||||||||
2921 | $cropY = round(($this->height/2) - ($this->newHeight/2)); |
||||||||||
2922 | } |
||||||||||
2923 | $this->log(" cwidth: $this->cropWidth"); |
||||||||||
2924 | $this->log(" cheight: $this->cropHeight"); |
||||||||||
2925 | $this->log(" nwidth: $this->newWidth"); |
||||||||||
2926 | $this->log(" nheight: $this->newHeight"); |
||||||||||
2927 | $this->log(" width: $this->width"); |
||||||||||
2928 | $this->log(" height: $this->height"); |
||||||||||
2929 | $this->log(" posX: $posX"); |
||||||||||
2930 | $this->log(" posY: $posY"); |
||||||||||
2931 | $this->log(" cropX: $cropX"); |
||||||||||
2932 | $this->log(" cropY: $cropY"); |
||||||||||
2933 | |||||||||||
2934 | $imageResized = $this->CreateImageKeepTransparency($this->newWidth, $this->newHeight); |
||||||||||
2935 | imagecopy($imageResized, $this->image, $posX, $posY, $cropX, $cropY, $this->width, $this->height); |
||||||||||
0 ignored issues
–
show
It seems like
$cropY can also be of type double ; however, parameter $src_y of imagecopy() does only seem to accept integer , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() It seems like
$posX can also be of type double ; however, parameter $dst_x of imagecopy() does only seem to accept integer , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() It seems like
$posY can also be of type double ; however, parameter $dst_y of imagecopy() does only seem to accept integer , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() It seems like
$cropX can also be of type double ; however, parameter $src_x of imagecopy() does only seem to accept integer , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
2936 | } else { |
||||||||||
2937 | $cropX = round(($this->cropWidth/2) - ($this->newWidth/2)); |
||||||||||
2938 | $cropY = round(($this->cropHeight/2) - ($this->newHeight/2)); |
||||||||||
2939 | $imgPreCrop = $this->CreateImageKeepTransparency($this->cropWidth, $this->cropHeight); |
||||||||||
2940 | $imageResized = $this->CreateImageKeepTransparency($this->newWidth, $this->newHeight); |
||||||||||
2941 | $this->imageCopyResampled($imgPreCrop, $this->image, 0, 0, 0, 0, $this->cropWidth, $this->cropHeight, $this->width, $this->height); |
||||||||||
2942 | imagecopy($imageResized, $imgPreCrop, 0, 0, $cropX, $cropY, $this->newWidth, $this->newHeight); |
||||||||||
2943 | } |
||||||||||
2944 | |||||||||||
2945 | $this->image = $imageResized; |
||||||||||
2946 | $this->width = $this->newWidth; |
||||||||||
2947 | $this->height = $this->newHeight; |
||||||||||
2948 | |||||||||||
2949 | } elseif ($this->fillToFit) { |
||||||||||
2950 | |||||||||||
2951 | // Resize by fill to fit |
||||||||||
2952 | $this->log("Resizing using strategy - Fill to fit"); |
||||||||||
2953 | |||||||||||
2954 | $posX = 0; |
||||||||||
2955 | $posY = 0; |
||||||||||
2956 | |||||||||||
2957 | $ratioOrig = $this->width / $this->height; |
||||||||||
2958 | $ratioNew = $this->newWidth / $this->newHeight; |
||||||||||
2959 | |||||||||||
2960 | // Check ratio for landscape or portrait |
||||||||||
2961 | if ($ratioOrig < $ratioNew) { |
||||||||||
2962 | $posX = round(($this->newWidth - $this->fillWidth) / 2); |
||||||||||
2963 | } else { |
||||||||||
2964 | $posY = round(($this->newHeight - $this->fillHeight) / 2); |
||||||||||
2965 | } |
||||||||||
2966 | |||||||||||
2967 | if (!$this->upscale |
||||||||||
2968 | && ($this->width < $this->newWidth && $this->height < $this->newHeight) |
||||||||||
2969 | ) { |
||||||||||
2970 | |||||||||||
2971 | $this->log("Resizing - smaller image, do not upscale."); |
||||||||||
2972 | $posX = round(($this->newWidth - $this->width) / 2); |
||||||||||
2973 | $posY = round(($this->newHeight - $this->height) / 2); |
||||||||||
2974 | $imageResized = $this->CreateImageKeepTransparency($this->newWidth, $this->newHeight); |
||||||||||
2975 | imagecopy($imageResized, $this->image, $posX, $posY, 0, 0, $this->width, $this->height); |
||||||||||
2976 | |||||||||||
2977 | } else { |
||||||||||
2978 | $imgPreFill = $this->CreateImageKeepTransparency($this->fillWidth, $this->fillHeight); |
||||||||||
2979 | $imageResized = $this->CreateImageKeepTransparency($this->newWidth, $this->newHeight); |
||||||||||
2980 | $this->imageCopyResampled($imgPreFill, $this->image, 0, 0, 0, 0, $this->fillWidth, $this->fillHeight, $this->width, $this->height); |
||||||||||
2981 | imagecopy($imageResized, $imgPreFill, $posX, $posY, 0, 0, $this->fillWidth, $this->fillHeight); |
||||||||||
2982 | } |
||||||||||
2983 | |||||||||||
2984 | $this->image = $imageResized; |
||||||||||
2985 | $this->width = $this->newWidth; |
||||||||||
2986 | $this->height = $this->newHeight; |
||||||||||
2987 | |||||||||||
2988 | } elseif (!($this->newWidth == $this->width && $this->newHeight == $this->height)) { |
||||||||||
2989 | |||||||||||
2990 | // Resize it |
||||||||||
2991 | $this->log("Resizing, new height and/or width"); |
||||||||||
2992 | |||||||||||
2993 | if (!$this->upscale |
||||||||||
2994 | && ($this->width < $this->newWidth || $this->height < $this->newHeight) |
||||||||||
2995 | ) { |
||||||||||
2996 | $this->log("Resizing - smaller image, do not upscale."); |
||||||||||
2997 | |||||||||||
2998 | if (!$this->keepRatio) { |
||||||||||
2999 | $this->log("Resizing - stretch to fit selected."); |
||||||||||
3000 | |||||||||||
3001 | $posX = 0; |
||||||||||
3002 | $posY = 0; |
||||||||||
3003 | $cropX = 0; |
||||||||||
3004 | $cropY = 0; |
||||||||||
3005 | |||||||||||
3006 | if ($this->newWidth > $this->width && $this->newHeight > $this->height) { |
||||||||||
3007 | $posX = round(($this->newWidth - $this->width) / 2); |
||||||||||
3008 | $posY = round(($this->newHeight - $this->height) / 2); |
||||||||||
3009 | } elseif ($this->newWidth > $this->width) { |
||||||||||
3010 | $posX = round(($this->newWidth - $this->width) / 2); |
||||||||||
3011 | $cropY = round(($this->height - $this->newHeight) / 2); |
||||||||||
3012 | } elseif ($this->newHeight > $this->height) { |
||||||||||
3013 | $posY = round(($this->newHeight - $this->height) / 2); |
||||||||||
3014 | $cropX = round(($this->width - $this->newWidth) / 2); |
||||||||||
3015 | } |
||||||||||
3016 | |||||||||||
3017 | $imageResized = $this->CreateImageKeepTransparency($this->newWidth, $this->newHeight); |
||||||||||
3018 | imagecopy($imageResized, $this->image, $posX, $posY, $cropX, $cropY, $this->width, $this->height); |
||||||||||
3019 | $this->image = $imageResized; |
||||||||||
3020 | $this->width = $this->newWidth; |
||||||||||
3021 | $this->height = $this->newHeight; |
||||||||||
3022 | } |
||||||||||
3023 | } else { |
||||||||||
3024 | $imageResized = $this->CreateImageKeepTransparency($this->newWidth, $this->newHeight); |
||||||||||
3025 | $this->imageCopyResampled($imageResized, $this->image, 0, 0, 0, 0, $this->newWidth, $this->newHeight, $this->width, $this->height); |
||||||||||
3026 | $this->image = $imageResized; |
||||||||||
3027 | $this->width = $this->newWidth; |
||||||||||
3028 | $this->height = $this->newHeight; |
||||||||||
3029 | } |
||||||||||
3030 | } |
||||||||||
3031 | |||||||||||
3032 | return $this; |
||||||||||
3033 | } |
||||||||||
3034 | |||||||||||
3035 | |||||||||||
3036 | |||||||||||
3037 | /** |
||||||||||
3038 | * Postprocess image after rezising image. |
||||||||||
3039 | * |
||||||||||
3040 | * @return $this |
||||||||||
3041 | */ |
||||||||||
3042 | public function postResize() |
||||||||||
3043 | { |
||||||||||
3044 | $this->log("### Post-process after resizing"); |
||||||||||
3045 | |||||||||||
3046 | // Rotate image |
||||||||||
3047 | if ($this->rotateAfter) { |
||||||||||
3048 | $this->log("Rotating image."); |
||||||||||
3049 | $this->rotate($this->rotateAfter, $this->bgColor); |
||||||||||
3050 | } |
||||||||||
3051 | |||||||||||
3052 | // Apply filters |
||||||||||
3053 | if (isset($this->filters) && is_array($this->filters)) { |
||||||||||
3054 | |||||||||||
3055 | foreach ($this->filters as $filter) { |
||||||||||
3056 | $this->log("Applying filter {$filter['type']}."); |
||||||||||
3057 | |||||||||||
3058 | switch ($filter['argc']) { |
||||||||||
3059 | |||||||||||
3060 | case 0: |
||||||||||
3061 | imagefilter($this->image, $filter['type']); |
||||||||||
3062 | break; |
||||||||||
3063 | |||||||||||
3064 | case 1: |
||||||||||
3065 | imagefilter($this->image, $filter['type'], $filter['arg1']); |
||||||||||
3066 | break; |
||||||||||
3067 | |||||||||||
3068 | case 2: |
||||||||||
3069 | imagefilter($this->image, $filter['type'], $filter['arg1'], $filter['arg2']); |
||||||||||
3070 | break; |
||||||||||
3071 | |||||||||||
3072 | case 3: |
||||||||||
3073 | imagefilter($this->image, $filter['type'], $filter['arg1'], $filter['arg2'], $filter['arg3']); |
||||||||||
3074 | break; |
||||||||||
3075 | |||||||||||
3076 | case 4: |
||||||||||
3077 | imagefilter($this->image, $filter['type'], $filter['arg1'], $filter['arg2'], $filter['arg3'], $filter['arg4']); |
||||||||||
3078 | break; |
||||||||||
3079 | } |
||||||||||
3080 | } |
||||||||||
3081 | } |
||||||||||
3082 | |||||||||||
3083 | // Convert to palette image |
||||||||||
3084 | if ($this->palette) { |
||||||||||
3085 | $this->log("Converting to palette image."); |
||||||||||
3086 | $this->trueColorToPalette(); |
||||||||||
3087 | } |
||||||||||
3088 | |||||||||||
3089 | // Blur the image |
||||||||||
3090 | if ($this->blur) { |
||||||||||
3091 | $this->log("Blur."); |
||||||||||
3092 | $this->blurImage(); |
||||||||||
3093 | } |
||||||||||
3094 | |||||||||||
3095 | // Emboss the image |
||||||||||
3096 | if ($this->emboss) { |
||||||||||
3097 | $this->log("Emboss."); |
||||||||||
3098 | $this->embossImage(); |
||||||||||
3099 | } |
||||||||||
3100 | |||||||||||
3101 | // Sharpen the image |
||||||||||
3102 | if ($this->sharpen) { |
||||||||||
3103 | $this->log("Sharpen."); |
||||||||||
3104 | $this->sharpenImage(); |
||||||||||
3105 | } |
||||||||||
3106 | |||||||||||
3107 | // Custom convolution |
||||||||||
3108 | if ($this->convolve) { |
||||||||||
3109 | //$this->log("Convolve: " . $this->convolve); |
||||||||||
3110 | $this->imageConvolution(); |
||||||||||
3111 | } |
||||||||||
3112 | |||||||||||
3113 | return $this; |
||||||||||
3114 | } |
||||||||||
3115 | |||||||||||
3116 | |||||||||||
3117 | |||||||||||
3118 | /** |
||||||||||
3119 | * Rotate image using angle. |
||||||||||
3120 | * |
||||||||||
3121 | * @param float $angle to rotate image. |
||||||||||
3122 | * @param int $anglebgColor to fill image with if needed. |
||||||||||
3123 | * |
||||||||||
3124 | * @return $this |
||||||||||
3125 | */ |
||||||||||
3126 | public function rotate($angle, $bgColor) |
||||||||||
0 ignored issues
–
show
The parameter
$bgColor is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() |
|||||||||||
3127 | { |
||||||||||
3128 | $this->log("Rotate image " . $angle . " degrees with filler color."); |
||||||||||
3129 | |||||||||||
3130 | $color = $this->getBackgroundColor(); |
||||||||||
3131 | $this->image = imagerotate($this->image, $angle, $color); |
||||||||||
0 ignored issues
–
show
$color of type color is incompatible with the type integer expected by parameter $bgd_color of imagerotate() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
3132 | |||||||||||
3133 | $this->width = imagesx($this->image); |
||||||||||
3134 | $this->height = imagesy($this->image); |
||||||||||
3135 | |||||||||||
3136 | $this->log("New image dimension width x height: " . $this->width . " x " . $this->height); |
||||||||||
3137 | |||||||||||
3138 | return $this; |
||||||||||
3139 | } |
||||||||||
3140 | |||||||||||
3141 | |||||||||||
3142 | |||||||||||
3143 | /** |
||||||||||
3144 | * Rotate image using information in EXIF. |
||||||||||
3145 | * |
||||||||||
3146 | * @return $this |
||||||||||
3147 | */ |
||||||||||
3148 | public function rotateExif() |
||||||||||
3149 | { |
||||||||||
3150 | if (!in_array($this->fileType, array(IMAGETYPE_JPEG, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM))) { |
||||||||||
3151 | $this->log("Autorotate ignored, EXIF not supported by this filetype."); |
||||||||||
3152 | return $this; |
||||||||||
3153 | } |
||||||||||
3154 | |||||||||||
3155 | $exif = exif_read_data($this->pathToImage); |
||||||||||
3156 | |||||||||||
3157 | if (!empty($exif['Orientation'])) { |
||||||||||
3158 | switch ($exif['Orientation']) { |
||||||||||
3159 | case 3: |
||||||||||
3160 | $this->log("Autorotate 180."); |
||||||||||
3161 | $this->rotate(180, $this->bgColor); |
||||||||||
3162 | break; |
||||||||||
3163 | |||||||||||
3164 | case 6: |
||||||||||
3165 | $this->log("Autorotate -90."); |
||||||||||
3166 | $this->rotate(-90, $this->bgColor); |
||||||||||
3167 | break; |
||||||||||
3168 | |||||||||||
3169 | case 8: |
||||||||||
3170 | $this->log("Autorotate 90."); |
||||||||||
3171 | $this->rotate(90, $this->bgColor); |
||||||||||
3172 | break; |
||||||||||
3173 | |||||||||||
3174 | default: |
||||||||||
3175 | $this->log("Autorotate ignored, unknown value as orientation."); |
||||||||||
3176 | } |
||||||||||
3177 | } else { |
||||||||||
3178 | $this->log("Autorotate ignored, no orientation in EXIF."); |
||||||||||
3179 | } |
||||||||||
3180 | |||||||||||
3181 | return $this; |
||||||||||
3182 | } |
||||||||||
3183 | |||||||||||
3184 | |||||||||||
3185 | |||||||||||
3186 | /** |
||||||||||
3187 | * Convert true color image to palette image, keeping alpha. |
||||||||||
3188 | * http://stackoverflow.com/questions/5752514/how-to-convert-png-to-8-bit-png-using-php-gd-library |
||||||||||
3189 | * |
||||||||||
3190 | * @return void |
||||||||||
3191 | */ |
||||||||||
3192 | public function trueColorToPalette() |
||||||||||
3193 | { |
||||||||||
3194 | $img = imagecreatetruecolor($this->width, $this->height); |
||||||||||
3195 | $bga = imagecolorallocatealpha($img, 0, 0, 0, 127); |
||||||||||
3196 | imagecolortransparent($img, $bga); |
||||||||||
3197 | imagefill($img, 0, 0, $bga); |
||||||||||
3198 | imagecopy($img, $this->image, 0, 0, 0, 0, $this->width, $this->height); |
||||||||||
3199 | imagetruecolortopalette($img, false, 255); |
||||||||||
3200 | imagesavealpha($img, true); |
||||||||||
3201 | |||||||||||
3202 | if (imageistruecolor($this->image)) { |
||||||||||
3203 | $this->log("Matching colors with true color image."); |
||||||||||
3204 | imagecolormatch($this->image, $img); |
||||||||||
3205 | } |
||||||||||
3206 | |||||||||||
3207 | $this->image = $img; |
||||||||||
3208 | } |
||||||||||
3209 | |||||||||||
3210 | |||||||||||
3211 | |||||||||||
3212 | /** |
||||||||||
3213 | * Sharpen image using image convolution. |
||||||||||
3214 | * |
||||||||||
3215 | * @return $this |
||||||||||
3216 | */ |
||||||||||
3217 | public function sharpenImage() |
||||||||||
3218 | { |
||||||||||
3219 | $this->imageConvolution('sharpen'); |
||||||||||
3220 | return $this; |
||||||||||
3221 | } |
||||||||||
3222 | |||||||||||
3223 | |||||||||||
3224 | |||||||||||
3225 | /** |
||||||||||
3226 | * Emboss image using image convolution. |
||||||||||
3227 | * |
||||||||||
3228 | * @return $this |
||||||||||
3229 | */ |
||||||||||
3230 | public function embossImage() |
||||||||||
3231 | { |
||||||||||
3232 | $this->imageConvolution('emboss'); |
||||||||||
3233 | return $this; |
||||||||||
3234 | } |
||||||||||
3235 | |||||||||||
3236 | |||||||||||
3237 | |||||||||||
3238 | /** |
||||||||||
3239 | * Blur image using image convolution. |
||||||||||
3240 | * |
||||||||||
3241 | * @return $this |
||||||||||
3242 | */ |
||||||||||
3243 | public function blurImage() |
||||||||||
3244 | { |
||||||||||
3245 | $this->imageConvolution('blur'); |
||||||||||
3246 | return $this; |
||||||||||
3247 | } |
||||||||||
3248 | |||||||||||
3249 | |||||||||||
3250 | |||||||||||
3251 | /** |
||||||||||
3252 | * Create convolve expression and return arguments for image convolution. |
||||||||||
3253 | * |
||||||||||
3254 | * @param string $expression constant string which evaluates to a list of |
||||||||||
3255 | * 11 numbers separated by komma or such a list. |
||||||||||
3256 | * |
||||||||||
3257 | * @return array as $matrix (3x3), $divisor and $offset |
||||||||||
3258 | */ |
||||||||||
3259 | public function createConvolveArguments($expression) |
||||||||||
3260 | { |
||||||||||
3261 | // Check of matching constant |
||||||||||
3262 | if (isset($this->convolves[$expression])) { |
||||||||||
3263 | $expression = $this->convolves[$expression]; |
||||||||||
3264 | } |
||||||||||
3265 | |||||||||||
3266 | $part = explode(',', $expression); |
||||||||||
3267 | $this->log("Creating convolution expressen: $expression"); |
||||||||||
3268 | |||||||||||
3269 | // Expect list of 11 numbers, split by , and build up arguments |
||||||||||
3270 | if (count($part) != 11) { |
||||||||||
3271 | throw new Exception( |
||||||||||
3272 | "Missmatch in argument convolve. Expected comma-separated string with |
||||||||||
3273 | 11 float values. Got $expression." |
||||||||||
3274 | ); |
||||||||||
3275 | } |
||||||||||
3276 | |||||||||||
3277 | array_walk($part, function ($item, $key) { |
||||||||||
0 ignored issues
–
show
The parameter
$key is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() |
|||||||||||
3278 | if (!is_numeric($item)) { |
||||||||||
3279 | throw new Exception("Argument to convolve expression should be float but is not."); |
||||||||||
3280 | } |
||||||||||
3281 | }); |
||||||||||
3282 | |||||||||||
3283 | return array( |
||||||||||
3284 | array( |
||||||||||
3285 | array($part[0], $part[1], $part[2]), |
||||||||||
3286 | array($part[3], $part[4], $part[5]), |
||||||||||
3287 | array($part[6], $part[7], $part[8]), |
||||||||||
3288 | ), |
||||||||||
3289 | $part[9], |
||||||||||
3290 | $part[10], |
||||||||||
3291 | ); |
||||||||||
3292 | } |
||||||||||
3293 | |||||||||||
3294 | |||||||||||
3295 | |||||||||||
3296 | /** |
||||||||||
3297 | * Add custom expressions (or overwrite existing) for image convolution. |
||||||||||
3298 | * |
||||||||||
3299 | * @param array $options Key value array with strings to be converted |
||||||||||
3300 | * to convolution expressions. |
||||||||||
3301 | * |
||||||||||
3302 | * @return $this |
||||||||||
3303 | */ |
||||||||||
3304 | public function addConvolveExpressions($options) |
||||||||||
3305 | { |
||||||||||
3306 | $this->convolves = array_merge($this->convolves, $options); |
||||||||||
3307 | return $this; |
||||||||||
3308 | } |
||||||||||
3309 | |||||||||||
3310 | |||||||||||
3311 | |||||||||||
3312 | /** |
||||||||||
3313 | * Image convolution. |
||||||||||
3314 | * |
||||||||||
3315 | * @param string $options A string with 11 float separated by comma. |
||||||||||
3316 | * |
||||||||||
3317 | * @return $this |
||||||||||
3318 | */ |
||||||||||
3319 | public function imageConvolution($options = null) |
||||||||||
3320 | { |
||||||||||
3321 | // Use incoming options or use $this. |
||||||||||
3322 | $options = $options ? $options : $this->convolve; |
||||||||||
3323 | |||||||||||
3324 | // Treat incoming as string, split by + |
||||||||||
3325 | $this->log("Convolution with '$options'"); |
||||||||||
3326 | $options = explode(":", $options); |
||||||||||
3327 | |||||||||||
3328 | // Check each option if it matches constant value |
||||||||||
3329 | foreach ($options as $option) { |
||||||||||
3330 | list($matrix, $divisor, $offset) = $this->createConvolveArguments($option); |
||||||||||
3331 | imageconvolution($this->image, $matrix, $divisor, $offset); |
||||||||||
3332 | } |
||||||||||
3333 | |||||||||||
3334 | return $this; |
||||||||||
3335 | } |
||||||||||
3336 | |||||||||||
3337 | |||||||||||
3338 | |||||||||||
3339 | /** |
||||||||||
3340 | * Set default background color between 000000-FFFFFF or if using |
||||||||||
3341 | * alpha 00000000-FFFFFF7F. |
||||||||||
3342 | * |
||||||||||
3343 | * @param string $color as hex value. |
||||||||||
3344 | * |
||||||||||
3345 | * @return $this |
||||||||||
3346 | */ |
||||||||||
3347 | public function setDefaultBackgroundColor($color) |
||||||||||
3348 | { |
||||||||||
3349 | $this->log("Setting default background color to '$color'."); |
||||||||||
3350 | |||||||||||
3351 | if (!(strlen($color) == 6 || strlen($color) == 8)) { |
||||||||||
3352 | throw new Exception( |
||||||||||
3353 | "Background color needs a hex value of 6 or 8 |
||||||||||
3354 | digits. 000000-FFFFFF or 00000000-FFFFFF7F. |
||||||||||
3355 | Current value was: '$color'." |
||||||||||
3356 | ); |
||||||||||
3357 | } |
||||||||||
3358 | |||||||||||
3359 | $red = hexdec(substr($color, 0, 2)); |
||||||||||
3360 | $green = hexdec(substr($color, 2, 2)); |
||||||||||
3361 | $blue = hexdec(substr($color, 4, 2)); |
||||||||||
3362 | |||||||||||
3363 | $alpha = (strlen($color) == 8) |
||||||||||
3364 | ? hexdec(substr($color, 6, 2)) |
||||||||||
3365 | : null; |
||||||||||
3366 | |||||||||||
3367 | if (($red < 0 || $red > 255) |
||||||||||
3368 | || ($green < 0 || $green > 255) |
||||||||||
3369 | || ($blue < 0 || $blue > 255) |
||||||||||
3370 | || ($alpha < 0 || $alpha > 127) |
||||||||||
3371 | ) { |
||||||||||
3372 | throw new Exception( |
||||||||||
3373 | "Background color out of range. Red, green blue |
||||||||||
3374 | should be 00-FF and alpha should be 00-7F. |
||||||||||
3375 | Current value was: '$color'." |
||||||||||
3376 | ); |
||||||||||
3377 | } |
||||||||||
3378 | |||||||||||
3379 | $this->bgColor = strtolower($color); |
||||||||||
3380 | $this->bgColorDefault = array( |
||||||||||
3381 | 'red' => $red, |
||||||||||
3382 | 'green' => $green, |
||||||||||
3383 | 'blue' => $blue, |
||||||||||
3384 | 'alpha' => $alpha |
||||||||||
3385 | ); |
||||||||||
3386 | |||||||||||
3387 | return $this; |
||||||||||
3388 | } |
||||||||||
3389 | |||||||||||
3390 | |||||||||||
3391 | |||||||||||
3392 | /** |
||||||||||
3393 | * Get the background color. |
||||||||||
3394 | * |
||||||||||
3395 | * @param resource $img the image to work with or null if using $this->image. |
||||||||||
3396 | * |
||||||||||
3397 | * @return color value or null if no background color is set. |
||||||||||
3398 | */ |
||||||||||
3399 | private function getBackgroundColor($img = null) |
||||||||||
3400 | { |
||||||||||
3401 | $img = isset($img) ? $img : $this->image; |
||||||||||
3402 | |||||||||||
3403 | if ($this->bgColorDefault) { |
||||||||||
0 ignored issues
–
show
The expression
$this->bgColorDefault of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||||||||
3404 | |||||||||||
3405 | $red = $this->bgColorDefault['red']; |
||||||||||
3406 | $green = $this->bgColorDefault['green']; |
||||||||||
3407 | $blue = $this->bgColorDefault['blue']; |
||||||||||
3408 | $alpha = $this->bgColorDefault['alpha']; |
||||||||||
3409 | |||||||||||
3410 | if ($alpha) { |
||||||||||
3411 | $color = imagecolorallocatealpha($img, $red, $green, $blue, $alpha); |
||||||||||
3412 | } else { |
||||||||||
3413 | $color = imagecolorallocate($img, $red, $green, $blue); |
||||||||||
3414 | } |
||||||||||
3415 | |||||||||||
3416 | return $color; |
||||||||||
0 ignored issues
–
show
|
|||||||||||
3417 | |||||||||||
3418 | } else { |
||||||||||
3419 | return 0; |
||||||||||
0 ignored issues
–
show
|
|||||||||||
3420 | } |
||||||||||
3421 | } |
||||||||||
3422 | |||||||||||
3423 | |||||||||||
3424 | |||||||||||
3425 | /** |
||||||||||
3426 | * Create a image and keep transparency for png and gifs. |
||||||||||
3427 | * |
||||||||||
3428 | * @param int $width of the new image. |
||||||||||
3429 | * @param int $height of the new image. |
||||||||||
3430 | * |
||||||||||
3431 | * @return image resource. |
||||||||||
3432 | */ |
||||||||||
3433 | private function createImageKeepTransparency($width, $height) |
||||||||||
3434 | { |
||||||||||
3435 | $this->log("Creating a new working image width={$width}px, height={$height}px."); |
||||||||||
3436 | $img = imagecreatetruecolor($width, $height); |
||||||||||
3437 | imagealphablending($img, false); |
||||||||||
3438 | imagesavealpha($img, true); |
||||||||||
3439 | |||||||||||
3440 | $index = $this->image |
||||||||||
3441 | ? imagecolortransparent($this->image) |
||||||||||
3442 | : -1; |
||||||||||
3443 | |||||||||||
3444 | if ($index != -1) { |
||||||||||
3445 | |||||||||||
3446 | imagealphablending($img, true); |
||||||||||
3447 | $transparent = imagecolorsforindex($this->image, $index); |
||||||||||
3448 | $color = imagecolorallocatealpha($img, $transparent['red'], $transparent['green'], $transparent['blue'], $transparent['alpha']); |
||||||||||
3449 | imagefill($img, 0, 0, $color); |
||||||||||
3450 | $index = imagecolortransparent($img, $color); |
||||||||||
3451 | $this->Log("Detected transparent color = " . implode(", ", $transparent) . " at index = $index"); |
||||||||||
3452 | |||||||||||
3453 | } elseif ($this->bgColorDefault) { |
||||||||||
0 ignored issues
–
show
The expression
$this->bgColorDefault of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||||||||
3454 | |||||||||||
3455 | $color = $this->getBackgroundColor($img); |
||||||||||
0 ignored issues
–
show
It seems like
$img can also be of type GdImage ; however, parameter $img of CImage::getBackgroundColor() does only seem to accept resource , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
3456 | imagefill($img, 0, 0, $color); |
||||||||||
0 ignored issues
–
show
$color of type color is incompatible with the type integer expected by parameter $color of imagefill() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
3457 | $this->Log("Filling image with background color."); |
||||||||||
3458 | } |
||||||||||
3459 | |||||||||||
3460 | return $img; |
||||||||||
0 ignored issues
–
show
|
|||||||||||
3461 | } |
||||||||||
3462 | |||||||||||
3463 | |||||||||||
3464 | |||||||||||
3465 | /** |
||||||||||
3466 | * Set optimizing and post-processing options. |
||||||||||
3467 | * |
||||||||||
3468 | * @param array $options with config for postprocessing with external tools. |
||||||||||
3469 | * |
||||||||||
3470 | * @return $this |
||||||||||
3471 | */ |
||||||||||
3472 | public function setPostProcessingOptions($options) |
||||||||||
3473 | { |
||||||||||
3474 | if (isset($options['jpeg_optimize']) && $options['jpeg_optimize']) { |
||||||||||
3475 | $this->jpegOptimizeCmd = $options['jpeg_optimize_cmd']; |
||||||||||
3476 | } else { |
||||||||||
3477 | $this->jpegOptimizeCmd = null; |
||||||||||
3478 | } |
||||||||||
3479 | |||||||||||
3480 | if (array_key_exists("png_lossy", $options) |
||||||||||
3481 | && $options['png_lossy'] !== false) { |
||||||||||
3482 | $this->pngLossy = $options['png_lossy']; |
||||||||||
3483 | $this->pngLossyCmd = $options['png_lossy_cmd']; |
||||||||||
3484 | } else { |
||||||||||
3485 | $this->pngLossyCmd = null; |
||||||||||
3486 | } |
||||||||||
3487 | |||||||||||
3488 | if (isset($options['png_filter']) && $options['png_filter']) { |
||||||||||
3489 | $this->pngFilterCmd = $options['png_filter_cmd']; |
||||||||||
3490 | } else { |
||||||||||
3491 | $this->pngFilterCmd = null; |
||||||||||
3492 | } |
||||||||||
3493 | |||||||||||
3494 | if (isset($options['png_deflate']) && $options['png_deflate']) { |
||||||||||
3495 | $this->pngDeflateCmd = $options['png_deflate_cmd']; |
||||||||||
3496 | } else { |
||||||||||
3497 | $this->pngDeflateCmd = null; |
||||||||||
3498 | } |
||||||||||
3499 | |||||||||||
3500 | return $this; |
||||||||||
3501 | } |
||||||||||
3502 | |||||||||||
3503 | |||||||||||
3504 | |||||||||||
3505 | /** |
||||||||||
3506 | * Find out the type (file extension) for the image to be saved. |
||||||||||
3507 | * |
||||||||||
3508 | * @return string as image extension. |
||||||||||
3509 | */ |
||||||||||
3510 | protected function getTargetImageExtension() |
||||||||||
3511 | { |
||||||||||
3512 | // switch on mimetype |
||||||||||
3513 | if (isset($this->extension)) { |
||||||||||
3514 | return strtolower($this->extension); |
||||||||||
3515 | } elseif ($this->fileType === IMG_WEBP) { |
||||||||||
3516 | return "webp"; |
||||||||||
3517 | } |
||||||||||
3518 | |||||||||||
3519 | return substr(image_type_to_extension($this->fileType), 1); |
||||||||||
3520 | } |
||||||||||
3521 | |||||||||||
3522 | |||||||||||
3523 | |||||||||||
3524 | /** |
||||||||||
3525 | * Save image. |
||||||||||
3526 | * |
||||||||||
3527 | * @param string $src as target filename. |
||||||||||
3528 | * @param string $base as base directory where to store images. |
||||||||||
3529 | * @param boolean $overwrite or not, default to always overwrite file. |
||||||||||
3530 | * |
||||||||||
3531 | * @return $this or false if no folder is set. |
||||||||||
3532 | */ |
||||||||||
3533 | public function save($src = null, $base = null, $overwrite = true) |
||||||||||
3534 | { |
||||||||||
3535 | if (isset($src)) { |
||||||||||
3536 | $this->setTarget($src, $base); |
||||||||||
3537 | } |
||||||||||
3538 | |||||||||||
3539 | if ($overwrite === false && is_file($this->cacheFileName)) { |
||||||||||
0 ignored issues
–
show
It seems like
$this->cacheFileName can also be of type null ; however, parameter $filename of is_file() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
3540 | $this->Log("Not overwriting file since its already exists and \$overwrite if false."); |
||||||||||
3541 | return; |
||||||||||
3542 | } |
||||||||||
3543 | |||||||||||
3544 | is_writable($this->saveFolder) |
||||||||||
3545 | or $this->raiseError('Target directory is not writable.'); |
||||||||||
3546 | |||||||||||
3547 | $type = $this->getTargetImageExtension(); |
||||||||||
3548 | $this->Log("Saving image as " . $type); |
||||||||||
3549 | switch($type) { |
||||||||||
3550 | |||||||||||
3551 | case 'jpeg': |
||||||||||
3552 | case 'jpg': |
||||||||||
3553 | $this->Log("Saving image as JPEG to cache using quality = {$this->quality}."); |
||||||||||
3554 | imagejpeg($this->image, $this->cacheFileName, $this->quality); |
||||||||||
3555 | |||||||||||
3556 | // Use JPEG optimize if defined |
||||||||||
3557 | if ($this->jpegOptimizeCmd) { |
||||||||||
3558 | if ($this->verbose) { |
||||||||||
3559 | clearstatcache(); |
||||||||||
3560 | $this->log("Filesize before optimize: " . filesize($this->cacheFileName) . " bytes."); |
||||||||||
0 ignored issues
–
show
It seems like
$this->cacheFileName can also be of type null ; however, parameter $filename of filesize() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
3561 | } |
||||||||||
3562 | $res = array(); |
||||||||||
3563 | $cmd = $this->jpegOptimizeCmd . " -outfile $this->cacheFileName $this->cacheFileName"; |
||||||||||
3564 | exec($cmd, $res); |
||||||||||
3565 | $this->log($cmd); |
||||||||||
3566 | $this->log($res); |
||||||||||
3567 | } |
||||||||||
3568 | break; |
||||||||||
3569 | |||||||||||
3570 | case 'gif': |
||||||||||
3571 | $this->Log("Saving image as GIF to cache."); |
||||||||||
3572 | imagegif($this->image, $this->cacheFileName); |
||||||||||
3573 | break; |
||||||||||
3574 | |||||||||||
3575 | case 'webp': |
||||||||||
3576 | $this->Log("Saving image as WEBP to cache using quality = {$this->quality}."); |
||||||||||
3577 | imagewebp($this->image, $this->cacheFileName, $this->quality); |
||||||||||
3578 | break; |
||||||||||
3579 | |||||||||||
3580 | case 'png': |
||||||||||
3581 | default: |
||||||||||
3582 | $this->Log("Saving image as PNG to cache using compression = {$this->compress}."); |
||||||||||
3583 | |||||||||||
3584 | // Turn off alpha blending and set alpha flag |
||||||||||
3585 | imagealphablending($this->image, false); |
||||||||||
3586 | imagesavealpha($this->image, true); |
||||||||||
3587 | imagepng($this->image, $this->cacheFileName, $this->compress); |
||||||||||
3588 | |||||||||||
3589 | // Use external program to process lossy PNG, if defined |
||||||||||
3590 | $lossyEnabled = $this->pngLossy === true; |
||||||||||
3591 | $lossySoftEnabled = $this->pngLossy === null; |
||||||||||
3592 | $lossyActiveEnabled = $this->lossy === true; |
||||||||||
3593 | if ($lossyEnabled || ($lossySoftEnabled && $lossyActiveEnabled)) { |
||||||||||
3594 | if ($this->verbose) { |
||||||||||
3595 | clearstatcache(); |
||||||||||
3596 | $this->log("Lossy enabled: $lossyEnabled"); |
||||||||||
3597 | $this->log("Lossy soft enabled: $lossySoftEnabled"); |
||||||||||
3598 | $this->Log("Filesize before lossy optimize: " . filesize($this->cacheFileName) . " bytes."); |
||||||||||
3599 | } |
||||||||||
3600 | $res = array(); |
||||||||||
3601 | $cmd = $this->pngLossyCmd . " $this->cacheFileName $this->cacheFileName"; |
||||||||||
3602 | exec($cmd, $res); |
||||||||||
3603 | $this->Log($cmd); |
||||||||||
3604 | $this->Log($res); |
||||||||||
3605 | } |
||||||||||
3606 | |||||||||||
3607 | // Use external program to filter PNG, if defined |
||||||||||
3608 | if ($this->pngFilterCmd) { |
||||||||||
3609 | if ($this->verbose) { |
||||||||||
3610 | clearstatcache(); |
||||||||||
3611 | $this->Log("Filesize before filter optimize: " . filesize($this->cacheFileName) . " bytes."); |
||||||||||
3612 | } |
||||||||||
3613 | $res = array(); |
||||||||||
3614 | $cmd = $this->pngFilterCmd . " $this->cacheFileName"; |
||||||||||
3615 | exec($cmd, $res); |
||||||||||
3616 | $this->Log($cmd); |
||||||||||
3617 | $this->Log($res); |
||||||||||
3618 | } |
||||||||||
3619 | |||||||||||
3620 | // Use external program to deflate PNG, if defined |
||||||||||
3621 | if ($this->pngDeflateCmd) { |
||||||||||
3622 | if ($this->verbose) { |
||||||||||
3623 | clearstatcache(); |
||||||||||
3624 | $this->Log("Filesize before deflate optimize: " . filesize($this->cacheFileName) . " bytes."); |
||||||||||
3625 | } |
||||||||||
3626 | $res = array(); |
||||||||||
3627 | $cmd = $this->pngDeflateCmd . " $this->cacheFileName"; |
||||||||||
3628 | exec($cmd, $res); |
||||||||||
3629 | $this->Log($cmd); |
||||||||||
3630 | $this->Log($res); |
||||||||||
3631 | } |
||||||||||
3632 | break; |
||||||||||
3633 | } |
||||||||||
3634 | |||||||||||
3635 | if ($this->verbose) { |
||||||||||
3636 | clearstatcache(); |
||||||||||
3637 | $this->log("Saved image to cache."); |
||||||||||
3638 | $this->log(" Cached image filesize: " . filesize($this->cacheFileName) . " bytes."); |
||||||||||
3639 | $this->log(" imageistruecolor() : " . (imageistruecolor($this->image) ? 'true' : 'false')); |
||||||||||
3640 | $this->log(" imagecolorstotal() : " . imagecolorstotal($this->image)); |
||||||||||
3641 | $this->log(" Number of colors in image = " . $this->ColorsTotal($this->image)); |
||||||||||
3642 | $index = imagecolortransparent($this->image); |
||||||||||
3643 | $this->log(" Detected transparent color = " . ($index > 0 ? implode(", ", imagecolorsforindex($this->image, $index)) : "NONE") . " at index = $index"); |
||||||||||
3644 | } |
||||||||||
3645 | |||||||||||
3646 | return $this; |
||||||||||
3647 | } |
||||||||||
3648 | |||||||||||
3649 | |||||||||||
3650 | |||||||||||
3651 | /** |
||||||||||
3652 | * Convert image from one colorpsace/color profile to sRGB without |
||||||||||
3653 | * color profile. |
||||||||||
3654 | * |
||||||||||
3655 | * @param string $src of image. |
||||||||||
3656 | * @param string $dir as base directory where images are. |
||||||||||
3657 | * @param string $cache as base directory where to store images. |
||||||||||
3658 | * @param string $iccFile filename of colorprofile. |
||||||||||
3659 | * @param boolean $useCache or not, default to always use cache. |
||||||||||
3660 | * |
||||||||||
3661 | * @return string | boolean false if no conversion else the converted |
||||||||||
3662 | * filename. |
||||||||||
3663 | */ |
||||||||||
3664 | public function convert2sRGBColorSpace($src, $dir, $cache, $iccFile, $useCache = true) |
||||||||||
3665 | { |
||||||||||
3666 | if ($this->verbose) { |
||||||||||
3667 | $this->log("# Converting image to sRGB colorspace."); |
||||||||||
3668 | } |
||||||||||
3669 | |||||||||||
3670 | if (!class_exists("Imagick")) { |
||||||||||
3671 | $this->log(" Ignoring since Imagemagick is not installed."); |
||||||||||
3672 | return false; |
||||||||||
3673 | } |
||||||||||
3674 | |||||||||||
3675 | // Prepare |
||||||||||
3676 | $this->setSaveFolder($cache) |
||||||||||
3677 | ->setSource($src, $dir) |
||||||||||
3678 | ->generateFilename(null, false, 'srgb_'); |
||||||||||
3679 | |||||||||||
3680 | // Check if the cached version is accurate. |
||||||||||
3681 | if ($useCache && is_readable($this->cacheFileName)) { |
||||||||||
0 ignored issues
–
show
It seems like
$this->cacheFileName can also be of type null ; however, parameter $filename of is_readable() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
3682 | $fileTime = filemtime($this->pathToImage); |
||||||||||
0 ignored issues
–
show
It seems like
$this->pathToImage can also be of type null ; however, parameter $filename of filemtime() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
3683 | $cacheTime = filemtime($this->cacheFileName); |
||||||||||
3684 | |||||||||||
3685 | if ($fileTime <= $cacheTime) { |
||||||||||
3686 | $this->log(" Using cached version: " . $this->cacheFileName); |
||||||||||
3687 | return $this->cacheFileName; |
||||||||||
3688 | } |
||||||||||
3689 | } |
||||||||||
3690 | |||||||||||
3691 | // Only covert if cachedir is writable |
||||||||||
3692 | if (is_writable($this->saveFolder)) { |
||||||||||
3693 | // Load file and check if conversion is needed |
||||||||||
3694 | $image = new Imagick($this->pathToImage); |
||||||||||
3695 | $colorspace = $image->getImageColorspace(); |
||||||||||
3696 | $this->log(" Current colorspace: " . $colorspace); |
||||||||||
3697 | |||||||||||
3698 | $profiles = $image->getImageProfiles('*', false); |
||||||||||
3699 | $hasICCProfile = (array_search('icc', $profiles) !== false); |
||||||||||
3700 | $this->log(" Has ICC color profile: " . ($hasICCProfile ? "YES" : "NO")); |
||||||||||
3701 | |||||||||||
3702 | if ($colorspace != Imagick::COLORSPACE_SRGB || $hasICCProfile) { |
||||||||||
3703 | $this->log(" Converting to sRGB."); |
||||||||||
3704 | |||||||||||
3705 | $sRGBicc = file_get_contents($iccFile); |
||||||||||
3706 | $image->profileImage('icc', $sRGBicc); |
||||||||||
3707 | |||||||||||
3708 | $image->transformImageColorspace(Imagick::COLORSPACE_SRGB); |
||||||||||
3709 | $image->writeImage($this->cacheFileName); |
||||||||||
3710 | return $this->cacheFileName; |
||||||||||
3711 | } |
||||||||||
3712 | } |
||||||||||
3713 | |||||||||||
3714 | return false; |
||||||||||
3715 | } |
||||||||||
3716 | |||||||||||
3717 | |||||||||||
3718 | |||||||||||
3719 | /** |
||||||||||
3720 | * Create a hard link, as an alias, to the cached file. |
||||||||||
3721 | * |
||||||||||
3722 | * @param string $alias where to store the link, |
||||||||||
3723 | * filename without extension. |
||||||||||
3724 | * |
||||||||||
3725 | * @return $this |
||||||||||
3726 | */ |
||||||||||
3727 | public function linkToCacheFile($alias) |
||||||||||
3728 | { |
||||||||||
3729 | if ($alias === null) { |
||||||||||
0 ignored issues
–
show
|
|||||||||||
3730 | $this->log("Ignore creating alias."); |
||||||||||
3731 | return $this; |
||||||||||
3732 | } |
||||||||||
3733 | |||||||||||
3734 | if (is_readable($alias)) { |
||||||||||
3735 | unlink($alias); |
||||||||||
3736 | } |
||||||||||
3737 | |||||||||||
3738 | $res = link($this->cacheFileName, $alias); |
||||||||||
0 ignored issues
–
show
It seems like
$this->cacheFileName can also be of type null ; however, parameter $target of link() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
3739 | |||||||||||
3740 | if ($res) { |
||||||||||
3741 | $this->log("Created an alias as: $alias"); |
||||||||||
3742 | } else { |
||||||||||
3743 | $this->log("Failed to create the alias: $alias"); |
||||||||||
3744 | } |
||||||||||
3745 | |||||||||||
3746 | return $this; |
||||||||||
3747 | } |
||||||||||
3748 | |||||||||||
3749 | |||||||||||
3750 | |||||||||||
3751 | /** |
||||||||||
3752 | * Add HTTP header for output together with image. |
||||||||||
3753 | * |
||||||||||
3754 | * @param string $type the header type such as "Cache-Control" |
||||||||||
3755 | * @param string $value the value to use |
||||||||||
3756 | * |
||||||||||
3757 | * @return void |
||||||||||
3758 | */ |
||||||||||
3759 | public function addHTTPHeader($type, $value) |
||||||||||
3760 | { |
||||||||||
3761 | $this->HTTPHeader[$type] = $value; |
||||||||||
3762 | } |
||||||||||
3763 | |||||||||||
3764 | |||||||||||
3765 | |||||||||||
3766 | /** |
||||||||||
3767 | * Output image to browser using caching. |
||||||||||
3768 | * |
||||||||||
3769 | * @param string $file to read and output, default is to |
||||||||||
3770 | * use $this->cacheFileName |
||||||||||
3771 | * @param string $format set to json to output file as json |
||||||||||
3772 | * object with details |
||||||||||
3773 | * |
||||||||||
3774 | * @return void |
||||||||||
3775 | */ |
||||||||||
3776 | public function output($file = null, $format = null) |
||||||||||
3777 | { |
||||||||||
3778 | if (is_null($file)) { |
||||||||||
3779 | $file = $this->cacheFileName; |
||||||||||
3780 | } |
||||||||||
3781 | |||||||||||
3782 | if (is_null($format)) { |
||||||||||
3783 | $format = $this->outputFormat; |
||||||||||
3784 | } |
||||||||||
3785 | |||||||||||
3786 | $this->log("### Output"); |
||||||||||
3787 | $this->log("Output format is: $format"); |
||||||||||
3788 | |||||||||||
3789 | if (!$this->verbose && $format == 'json') { |
||||||||||
3790 | header('Content-type: application/json'); |
||||||||||
3791 | echo $this->json($file); |
||||||||||
3792 | exit; |
||||||||||
0 ignored issues
–
show
|
|||||||||||
3793 | } elseif ($format == 'ascii') { |
||||||||||
3794 | header('Content-type: text/plain'); |
||||||||||
3795 | echo $this->ascii($file); |
||||||||||
3796 | exit; |
||||||||||
0 ignored issues
–
show
|
|||||||||||
3797 | } |
||||||||||
3798 | |||||||||||
3799 | $this->log("Outputting image: $file"); |
||||||||||
3800 | |||||||||||
3801 | // Get image modification time |
||||||||||
3802 | clearstatcache(); |
||||||||||
3803 | $lastModified = filemtime($file); |
||||||||||
0 ignored issues
–
show
It seems like
$file can also be of type null ; however, parameter $filename of filemtime() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
3804 | $lastModifiedFormat = "D, d M Y H:i:s"; |
||||||||||
3805 | $gmdate = gmdate($lastModifiedFormat, $lastModified); |
||||||||||
3806 | |||||||||||
3807 | if (!$this->verbose) { |
||||||||||
3808 | $header = "Last-Modified: $gmdate GMT"; |
||||||||||
3809 | header($header); |
||||||||||
3810 | $this->fastTrackCache->addHeader($header); |
||||||||||
3811 | $this->fastTrackCache->setLastModified($lastModified); |
||||||||||
3812 | } |
||||||||||
3813 | |||||||||||
3814 | foreach ($this->HTTPHeader as $key => $val) { |
||||||||||
3815 | $header = "$key: $val"; |
||||||||||
3816 | header($header); |
||||||||||
3817 | $this->fastTrackCache->addHeader($header); |
||||||||||
3818 | } |
||||||||||
3819 | |||||||||||
3820 | if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) |
||||||||||
3821 | && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $lastModified) { |
||||||||||
3822 | |||||||||||
3823 | if ($this->verbose) { |
||||||||||
3824 | $this->log("304 not modified"); |
||||||||||
3825 | $this->verboseOutput(); |
||||||||||
3826 | exit; |
||||||||||
0 ignored issues
–
show
|
|||||||||||
3827 | } |
||||||||||
3828 | |||||||||||
3829 | header("HTTP/1.0 304 Not Modified"); |
||||||||||
3830 | if (CIMAGE_DEBUG) { |
||||||||||
3831 | trace(__CLASS__ . " 304"); |
||||||||||
3832 | } |
||||||||||
3833 | |||||||||||
3834 | } else { |
||||||||||
3835 | |||||||||||
3836 | $this->loadImageDetails($file); |
||||||||||
3837 | $mime = $this->getMimeType(); |
||||||||||
3838 | $size = filesize($file); |
||||||||||
0 ignored issues
–
show
It seems like
$file can also be of type null ; however, parameter $filename of filesize() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
3839 | |||||||||||
3840 | if ($this->verbose) { |
||||||||||
3841 | $this->log("Last-Modified: " . $gmdate . " GMT"); |
||||||||||
3842 | $this->log("Content-type: " . $mime); |
||||||||||
0 ignored issues
–
show
Are you sure
$mime of type CImage can be used in concatenation ? Consider adding a __toString() -method.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
3843 | $this->log("Content-length: " . $size); |
||||||||||
3844 | $this->verboseOutput(); |
||||||||||
3845 | |||||||||||
3846 | if (is_null($this->verboseFileName)) { |
||||||||||
3847 | exit; |
||||||||||
0 ignored issues
–
show
|
|||||||||||
3848 | } |
||||||||||
3849 | } |
||||||||||
3850 | |||||||||||
3851 | $header = "Content-type: $mime"; |
||||||||||
3852 | header($header); |
||||||||||
3853 | $this->fastTrackCache->addHeaderOnOutput($header); |
||||||||||
3854 | |||||||||||
3855 | $header = "Content-length: $size"; |
||||||||||
3856 | header($header); |
||||||||||
3857 | $this->fastTrackCache->addHeaderOnOutput($header); |
||||||||||
3858 | |||||||||||
3859 | $this->fastTrackCache->setSource($file); |
||||||||||
3860 | $this->fastTrackCache->writeToCache(); |
||||||||||
3861 | if (CIMAGE_DEBUG) { |
||||||||||
3862 | trace(__CLASS__ . " 200"); |
||||||||||
3863 | } |
||||||||||
3864 | readfile($file); |
||||||||||
0 ignored issues
–
show
It seems like
$file can also be of type null ; however, parameter $filename of readfile() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
3865 | } |
||||||||||
3866 | |||||||||||
3867 | exit; |
||||||||||
0 ignored issues
–
show
|
|||||||||||
3868 | } |
||||||||||
3869 | |||||||||||
3870 | |||||||||||
3871 | |||||||||||
3872 | /** |
||||||||||
3873 | * Create a JSON object from the image details. |
||||||||||
3874 | * |
||||||||||
3875 | * @param string $file the file to output. |
||||||||||
3876 | * |
||||||||||
3877 | * @return string json-encoded representation of the image. |
||||||||||
3878 | */ |
||||||||||
3879 | public function json($file = null) |
||||||||||
3880 | { |
||||||||||
3881 | $file = $file ? $file : $this->cacheFileName; |
||||||||||
3882 | |||||||||||
3883 | $details = array(); |
||||||||||
3884 | |||||||||||
3885 | clearstatcache(); |
||||||||||
3886 | |||||||||||
3887 | $details['src'] = $this->imageSrc; |
||||||||||
3888 | $lastModified = filemtime($this->pathToImage); |
||||||||||
0 ignored issues
–
show
It seems like
$this->pathToImage can also be of type null ; however, parameter $filename of filemtime() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
3889 | $details['srcGmdate'] = gmdate("D, d M Y H:i:s", $lastModified); |
||||||||||
3890 | |||||||||||
3891 | $details['cache'] = basename($this->cacheFileName); |
||||||||||
0 ignored issues
–
show
It seems like
$this->cacheFileName can also be of type null ; however, parameter $path of basename() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
3892 | $lastModified = filemtime($this->cacheFileName); |
||||||||||
3893 | $details['cacheGmdate'] = gmdate("D, d M Y H:i:s", $lastModified); |
||||||||||
3894 | |||||||||||
3895 | $this->load($file); |
||||||||||
3896 | |||||||||||
3897 | $details['filename'] = basename($file); |
||||||||||
3898 | $details['mimeType'] = $this->getMimeType($this->fileType); |
||||||||||
0 ignored issues
–
show
The call to
CImage::getMimeType() has too many arguments starting with $this->fileType .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||||||||
3899 | $details['width'] = $this->width; |
||||||||||
3900 | $details['height'] = $this->height; |
||||||||||
3901 | $details['aspectRatio'] = round($this->width / $this->height, 3); |
||||||||||
3902 | $details['size'] = filesize($file); |
||||||||||
0 ignored issues
–
show
It seems like
$file can also be of type null ; however, parameter $filename of filesize() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
3903 | $details['colors'] = $this->colorsTotal($this->image); |
||||||||||
0 ignored issues
–
show
It seems like
$this->image can also be of type GdImage ; however, parameter $im of CImage::colorsTotal() does only seem to accept resource , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
3904 | $details['includedFiles'] = count(get_included_files()); |
||||||||||
3905 | $details['memoryPeek'] = round(memory_get_peak_usage()/1024/1024, 3) . " MB" ; |
||||||||||
3906 | $details['memoryCurrent'] = round(memory_get_usage()/1024/1024, 3) . " MB"; |
||||||||||
3907 | $details['memoryLimit'] = ini_get('memory_limit'); |
||||||||||
3908 | |||||||||||
3909 | if (isset($_SERVER['REQUEST_TIME_FLOAT'])) { |
||||||||||
3910 | $details['loadTime'] = (string) round((microtime(true) - $_SERVER['REQUEST_TIME_FLOAT']), 3) . "s"; |
||||||||||
3911 | } |
||||||||||
3912 | |||||||||||
3913 | if ($details['mimeType'] == 'image/png') { |
||||||||||
3914 | $details['pngType'] = $this->getPngTypeAsString(null, $file); |
||||||||||
3915 | } |
||||||||||
3916 | |||||||||||
3917 | $options = null; |
||||||||||
3918 | if (defined("JSON_PRETTY_PRINT") && defined("JSON_UNESCAPED_SLASHES")) { |
||||||||||
3919 | $options = JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES; |
||||||||||
3920 | } |
||||||||||
3921 | |||||||||||
3922 | return json_encode($details, $options); |
||||||||||
0 ignored issues
–
show
It seems like
$options can also be of type null ; however, parameter $flags of json_encode() does only seem to accept integer , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
3923 | } |
||||||||||
3924 | |||||||||||
3925 | |||||||||||
3926 | |||||||||||
3927 | /** |
||||||||||
3928 | * Set options for creating ascii version of image. |
||||||||||
3929 | * |
||||||||||
3930 | * @param array $options empty to use default or set options to change. |
||||||||||
3931 | * |
||||||||||
3932 | * @return void. |
||||||||||
0 ignored issues
–
show
|
|||||||||||
3933 | */ |
||||||||||
3934 | public function setAsciiOptions($options = array()) |
||||||||||
3935 | { |
||||||||||
3936 | $this->asciiOptions = $options; |
||||||||||
3937 | } |
||||||||||
3938 | |||||||||||
3939 | |||||||||||
3940 | |||||||||||
3941 | /** |
||||||||||
3942 | * Create an ASCII version from the image details. |
||||||||||
3943 | * |
||||||||||
3944 | * @param string $file the file to output. |
||||||||||
3945 | * |
||||||||||
3946 | * @return string ASCII representation of the image. |
||||||||||
3947 | */ |
||||||||||
3948 | public function ascii($file = null) |
||||||||||
3949 | { |
||||||||||
3950 | $file = $file ? $file : $this->cacheFileName; |
||||||||||
3951 | |||||||||||
3952 | $asciiArt = new CAsciiArt(); |
||||||||||
3953 | $asciiArt->setOptions($this->asciiOptions); |
||||||||||
3954 | return $asciiArt->createFromFile($file); |
||||||||||
3955 | } |
||||||||||
3956 | |||||||||||
3957 | |||||||||||
3958 | |||||||||||
3959 | /** |
||||||||||
3960 | * Log an event if verbose mode. |
||||||||||
3961 | * |
||||||||||
3962 | * @param string $message to log. |
||||||||||
3963 | * |
||||||||||
3964 | * @return this |
||||||||||
3965 | */ |
||||||||||
3966 | public function log($message) |
||||||||||
3967 | { |
||||||||||
3968 | if ($this->verbose) { |
||||||||||
3969 | $this->log[] = $message; |
||||||||||
3970 | } |
||||||||||
3971 | |||||||||||
3972 | return $this; |
||||||||||
3973 | } |
||||||||||
3974 | |||||||||||
3975 | |||||||||||
3976 | |||||||||||
3977 | /** |
||||||||||
3978 | * Do verbose output to a file. |
||||||||||
3979 | * |
||||||||||
3980 | * @param string $fileName where to write the verbose output. |
||||||||||
3981 | * |
||||||||||
3982 | * @return void |
||||||||||
3983 | */ |
||||||||||
3984 | public function setVerboseToFile($fileName) |
||||||||||
3985 | { |
||||||||||
3986 | $this->log("Setting verbose output to file."); |
||||||||||
3987 | $this->verboseFileName = $fileName; |
||||||||||
3988 | } |
||||||||||
3989 | |||||||||||
3990 | |||||||||||
3991 | |||||||||||
3992 | /** |
||||||||||
3993 | * Do verbose output and print out the log and the actual images. |
||||||||||
3994 | * |
||||||||||
3995 | * @return void |
||||||||||
3996 | */ |
||||||||||
3997 | private function verboseOutput() |
||||||||||
3998 | { |
||||||||||
3999 | $log = null; |
||||||||||
4000 | $this->log("### Summary of verbose log"); |
||||||||||
4001 | $this->log("As JSON: \n" . $this->json()); |
||||||||||
4002 | $this->log("Memory peak: " . round(memory_get_peak_usage() /1024/1024) . "M"); |
||||||||||
4003 | $this->log("Memory limit: " . ini_get('memory_limit')); |
||||||||||
4004 | |||||||||||
4005 | $included = get_included_files(); |
||||||||||
4006 | $this->log("Included files: " . count($included)); |
||||||||||
4007 | |||||||||||
4008 | foreach ($this->log as $val) { |
||||||||||
4009 | if (is_array($val)) { |
||||||||||
4010 | foreach ($val as $val1) { |
||||||||||
4011 | $log .= htmlentities($val1) . '<br/>'; |
||||||||||
4012 | } |
||||||||||
4013 | } else { |
||||||||||
4014 | $log .= htmlentities($val) . '<br/>'; |
||||||||||
4015 | } |
||||||||||
4016 | } |
||||||||||
4017 | |||||||||||
4018 | if (!is_null($this->verboseFileName)) { |
||||||||||
4019 | file_put_contents( |
||||||||||
4020 | $this->verboseFileName, |
||||||||||
4021 | str_replace("<br/>", "\n", $log) |
||||||||||
4022 | ); |
||||||||||
4023 | } else { |
||||||||||
4024 | echo <<<EOD |
||||||||||
4025 | <h1>CImage Verbose Output</h1> |
||||||||||
4026 | <pre>{$log}</pre> |
||||||||||
4027 | EOD; |
||||||||||
4028 | } |
||||||||||
4029 | } |
||||||||||
4030 | |||||||||||
4031 | |||||||||||
4032 | |||||||||||
4033 | /** |
||||||||||
4034 | * Raise error, enables to implement a selection of error methods. |
||||||||||
4035 | * |
||||||||||
4036 | * @param string $message the error message to display. |
||||||||||
4037 | * |
||||||||||
4038 | * @return void |
||||||||||
4039 | * @throws Exception |
||||||||||
4040 | */ |
||||||||||
4041 | private function raiseError($message) |
||||||||||
4042 | { |
||||||||||
4043 | throw new Exception($message); |
||||||||||
4044 | } |
||||||||||
4045 | } |
||||||||||
4046 | |||||||||||
4047 | |||||||||||
4048 | |||||||||||
4049 | /** |
||||||||||
4050 | * Deal with the cache directory and cached items. |
||||||||||
4051 | * |
||||||||||
4052 | */ |
||||||||||
4053 | class CCache |
||||||||||
4054 | { |
||||||||||
4055 | /** |
||||||||||
4056 | * Path to the cache directory. |
||||||||||
4057 | */ |
||||||||||
4058 | private $path; |
||||||||||
4059 | |||||||||||
4060 | |||||||||||
4061 | |||||||||||
4062 | /** |
||||||||||
4063 | * Set the path to the cache dir which must exist. |
||||||||||
4064 | * |
||||||||||
4065 | * @param string path to the cache dir. |
||||||||||
0 ignored issues
–
show
The type
path was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||||||||||
4066 | * |
||||||||||
4067 | * @throws Exception when $path is not a directory. |
||||||||||
4068 | * |
||||||||||
4069 | * @return $this |
||||||||||
4070 | */ |
||||||||||
4071 | public function setDir($path) |
||||||||||
4072 | { |
||||||||||
4073 | if (!is_dir($path)) { |
||||||||||
4074 | throw new Exception("Cachedir is not a directory."); |
||||||||||
4075 | } |
||||||||||
4076 | |||||||||||
4077 | $this->path = $path; |
||||||||||
4078 | |||||||||||
4079 | return $this; |
||||||||||
4080 | } |
||||||||||
4081 | |||||||||||
4082 | |||||||||||
4083 | |||||||||||
4084 | /** |
||||||||||
4085 | * Get the path to the cache subdir and try to create it if its not there. |
||||||||||
4086 | * |
||||||||||
4087 | * @param string $subdir name of subdir |
||||||||||
4088 | * @param array $create default is to try to create the subdir |
||||||||||
4089 | * |
||||||||||
4090 | * @return string | boolean as real path to the subdir or |
||||||||||
4091 | * false if it does not exists |
||||||||||
4092 | */ |
||||||||||
4093 | public function getPathToSubdir($subdir, $create = true) |
||||||||||
4094 | { |
||||||||||
4095 | $path = realpath($this->path . "/" . $subdir); |
||||||||||
4096 | |||||||||||
4097 | if (is_dir($path)) { |
||||||||||
4098 | return $path; |
||||||||||
4099 | } |
||||||||||
4100 | |||||||||||
4101 | if ($create && is_writable($this->path)) { |
||||||||||
4102 | $path = $this->path . "/" . $subdir; |
||||||||||
4103 | |||||||||||
4104 | if (mkdir($path)) { |
||||||||||
4105 | return realpath($path); |
||||||||||
4106 | } |
||||||||||
4107 | } |
||||||||||
4108 | |||||||||||
4109 | return false; |
||||||||||
4110 | } |
||||||||||
4111 | |||||||||||
4112 | |||||||||||
4113 | |||||||||||
4114 | /** |
||||||||||
4115 | * Get status of the cache subdir. |
||||||||||
4116 | * |
||||||||||
4117 | * @param string $subdir name of subdir |
||||||||||
4118 | * |
||||||||||
4119 | * @return string with status |
||||||||||
4120 | */ |
||||||||||
4121 | public function getStatusOfSubdir($subdir) |
||||||||||
4122 | { |
||||||||||
4123 | $path = realpath($this->path . "/" . $subdir); |
||||||||||
4124 | |||||||||||
4125 | $exists = is_dir($path); |
||||||||||
4126 | $res = $exists ? "exists" : "does not exist"; |
||||||||||
4127 | |||||||||||
4128 | if ($exists) { |
||||||||||
4129 | $res .= is_writable($path) ? ", writable" : ", not writable"; |
||||||||||
4130 | } |
||||||||||
4131 | |||||||||||
4132 | return $res; |
||||||||||
4133 | } |
||||||||||
4134 | |||||||||||
4135 | |||||||||||
4136 | |||||||||||
4137 | /** |
||||||||||
4138 | * Remove the cache subdir. |
||||||||||
4139 | * |
||||||||||
4140 | * @param string $subdir name of subdir |
||||||||||
4141 | * |
||||||||||
4142 | * @return null | boolean true if success else false, null if no operation |
||||||||||
4143 | */ |
||||||||||
4144 | public function removeSubdir($subdir) |
||||||||||
4145 | { |
||||||||||
4146 | $path = realpath($this->path . "/" . $subdir); |
||||||||||
4147 | |||||||||||
4148 | if (is_dir($path)) { |
||||||||||
4149 | return rmdir($path); |
||||||||||
4150 | } |
||||||||||
4151 | |||||||||||
4152 | return null; |
||||||||||
4153 | } |
||||||||||
4154 | } |
||||||||||
4155 | |||||||||||
4156 | |||||||||||
4157 | |||||||||||
4158 | /** |
||||||||||
4159 | * Enable a fast track cache with a json representation of the image delivery. |
||||||||||
4160 | * |
||||||||||
4161 | */ |
||||||||||
4162 | class CFastTrackCache |
||||||||||
4163 | { |
||||||||||
4164 | /** |
||||||||||
4165 | * Cache is disabled to start with. |
||||||||||
4166 | */ |
||||||||||
4167 | private $enabled = false; |
||||||||||
4168 | |||||||||||
4169 | |||||||||||
4170 | |||||||||||
4171 | /** |
||||||||||
4172 | * Path to the cache directory. |
||||||||||
4173 | */ |
||||||||||
4174 | private $path; |
||||||||||
4175 | |||||||||||
4176 | |||||||||||
4177 | |||||||||||
4178 | /** |
||||||||||
4179 | * Filename of current cache item. |
||||||||||
4180 | */ |
||||||||||
4181 | private $filename; |
||||||||||
4182 | |||||||||||
4183 | |||||||||||
4184 | |||||||||||
4185 | /** |
||||||||||
4186 | * Container with items to store as cached item. |
||||||||||
4187 | */ |
||||||||||
4188 | private $container; |
||||||||||
4189 | |||||||||||
4190 | |||||||||||
4191 | |||||||||||
4192 | /** |
||||||||||
4193 | * Enable or disable cache. |
||||||||||
4194 | * |
||||||||||
4195 | * @param boolean $enable set to true to enable, false to disable |
||||||||||
4196 | * |
||||||||||
4197 | * @return $this |
||||||||||
4198 | */ |
||||||||||
4199 | public function enable($enabled) |
||||||||||
4200 | { |
||||||||||
4201 | $this->enabled = $enabled; |
||||||||||
4202 | return $this; |
||||||||||
4203 | } |
||||||||||
4204 | |||||||||||
4205 | |||||||||||
4206 | |||||||||||
4207 | /** |
||||||||||
4208 | * Set the path to the cache dir which must exist. |
||||||||||
4209 | * |
||||||||||
4210 | * @param string $path to the cache dir. |
||||||||||
4211 | * |
||||||||||
4212 | * @throws Exception when $path is not a directory. |
||||||||||
4213 | * |
||||||||||
4214 | * @return $this |
||||||||||
4215 | */ |
||||||||||
4216 | public function setCacheDir($path) |
||||||||||
4217 | { |
||||||||||
4218 | if (!is_dir($path)) { |
||||||||||
4219 | throw new Exception("Cachedir is not a directory."); |
||||||||||
4220 | } |
||||||||||
4221 | |||||||||||
4222 | $this->path = rtrim($path, "/"); |
||||||||||
4223 | |||||||||||
4224 | return $this; |
||||||||||
4225 | } |
||||||||||
4226 | |||||||||||
4227 | |||||||||||
4228 | |||||||||||
4229 | /** |
||||||||||
4230 | * Set the filename to store in cache, use the querystring to create that |
||||||||||
4231 | * filename. |
||||||||||
4232 | * |
||||||||||
4233 | * @param array $clear items to clear in $_GET when creating the filename. |
||||||||||
4234 | * |
||||||||||
4235 | * @return string as filename created. |
||||||||||
4236 | */ |
||||||||||
4237 | public function setFilename($clear) |
||||||||||
4238 | { |
||||||||||
4239 | $query = $_GET; |
||||||||||
4240 | |||||||||||
4241 | // Remove parts from querystring that should not be part of filename |
||||||||||
4242 | foreach ($clear as $value) { |
||||||||||
4243 | unset($query[$value]); |
||||||||||
4244 | } |
||||||||||
4245 | |||||||||||
4246 | arsort($query); |
||||||||||
4247 | $queryAsString = http_build_query($query); |
||||||||||
4248 | |||||||||||
4249 | $this->filename = md5($queryAsString); |
||||||||||
4250 | |||||||||||
4251 | if (CIMAGE_DEBUG) { |
||||||||||
4252 | $this->container["query-string"] = $queryAsString; |
||||||||||
4253 | } |
||||||||||
4254 | |||||||||||
4255 | return $this->filename; |
||||||||||
4256 | } |
||||||||||
4257 | |||||||||||
4258 | |||||||||||
4259 | |||||||||||
4260 | /** |
||||||||||
4261 | * Add header items. |
||||||||||
4262 | * |
||||||||||
4263 | * @param string $header add this as header. |
||||||||||
4264 | * |
||||||||||
4265 | * @return $this |
||||||||||
4266 | */ |
||||||||||
4267 | public function addHeader($header) |
||||||||||
4268 | { |
||||||||||
4269 | $this->container["header"][] = $header; |
||||||||||
4270 | return $this; |
||||||||||
4271 | } |
||||||||||
4272 | |||||||||||
4273 | |||||||||||
4274 | |||||||||||
4275 | /** |
||||||||||
4276 | * Add header items on output, these are not output when 304. |
||||||||||
4277 | * |
||||||||||
4278 | * @param string $header add this as header. |
||||||||||
4279 | * |
||||||||||
4280 | * @return $this |
||||||||||
4281 | */ |
||||||||||
4282 | public function addHeaderOnOutput($header) |
||||||||||
4283 | { |
||||||||||
4284 | $this->container["header-output"][] = $header; |
||||||||||
4285 | return $this; |
||||||||||
4286 | } |
||||||||||
4287 | |||||||||||
4288 | |||||||||||
4289 | |||||||||||
4290 | /** |
||||||||||
4291 | * Set path to source image to. |
||||||||||
4292 | * |
||||||||||
4293 | * @param string $source path to source image file. |
||||||||||
4294 | * |
||||||||||
4295 | * @return $this |
||||||||||
4296 | */ |
||||||||||
4297 | public function setSource($source) |
||||||||||
4298 | { |
||||||||||
4299 | $this->container["source"] = $source; |
||||||||||
4300 | return $this; |
||||||||||
4301 | } |
||||||||||
4302 | |||||||||||
4303 | |||||||||||
4304 | |||||||||||
4305 | /** |
||||||||||
4306 | * Set last modified of source image, use to check for 304. |
||||||||||
4307 | * |
||||||||||
4308 | * @param string $lastModified |
||||||||||
4309 | * |
||||||||||
4310 | * @return $this |
||||||||||
4311 | */ |
||||||||||
4312 | public function setLastModified($lastModified) |
||||||||||
4313 | { |
||||||||||
4314 | $this->container["last-modified"] = $lastModified; |
||||||||||
4315 | return $this; |
||||||||||
4316 | } |
||||||||||
4317 | |||||||||||
4318 | |||||||||||
4319 | |||||||||||
4320 | /** |
||||||||||
4321 | * Get filename of cached item. |
||||||||||
4322 | * |
||||||||||
4323 | * @return string as filename. |
||||||||||
4324 | */ |
||||||||||
4325 | public function getFilename() |
||||||||||
4326 | { |
||||||||||
4327 | return $this->path . "/" . $this->filename; |
||||||||||
4328 | } |
||||||||||
4329 | |||||||||||
4330 | |||||||||||
4331 | |||||||||||
4332 | /** |
||||||||||
4333 | * Write current item to cache. |
||||||||||
4334 | * |
||||||||||
4335 | * @return boolean if cache file was written. |
||||||||||
4336 | */ |
||||||||||
4337 | public function writeToCache() |
||||||||||
4338 | { |
||||||||||
4339 | if (!$this->enabled) { |
||||||||||
4340 | return false; |
||||||||||
4341 | } |
||||||||||
4342 | |||||||||||
4343 | if (is_dir($this->path) && is_writable($this->path)) { |
||||||||||
4344 | $filename = $this->getFilename(); |
||||||||||
4345 | return file_put_contents($filename, json_encode($this->container)) !== false; |
||||||||||
4346 | } |
||||||||||
4347 | |||||||||||
4348 | return false; |
||||||||||
4349 | } |
||||||||||
4350 | |||||||||||
4351 | |||||||||||
4352 | |||||||||||
4353 | /** |
||||||||||
4354 | * Output current item from cache, if available. |
||||||||||
4355 | * |
||||||||||
4356 | * @return void |
||||||||||
4357 | */ |
||||||||||
4358 | public function output() |
||||||||||
4359 | { |
||||||||||
4360 | $filename = $this->getFilename(); |
||||||||||
4361 | if (!is_readable($filename)) { |
||||||||||
4362 | return; |
||||||||||
4363 | } |
||||||||||
4364 | |||||||||||
4365 | $item = json_decode(file_get_contents($filename), true); |
||||||||||
4366 | |||||||||||
4367 | if (!is_readable($item["source"])) { |
||||||||||
4368 | return; |
||||||||||
4369 | } |
||||||||||
4370 | |||||||||||
4371 | foreach ($item["header"] as $value) { |
||||||||||
4372 | header($value); |
||||||||||
4373 | } |
||||||||||
4374 | |||||||||||
4375 | if (isset($_SERVER["HTTP_IF_MODIFIED_SINCE"]) |
||||||||||
4376 | && strtotime($_SERVER["HTTP_IF_MODIFIED_SINCE"]) == $item["last-modified"]) { |
||||||||||
4377 | header("HTTP/1.0 304 Not Modified"); |
||||||||||
4378 | if (CIMAGE_DEBUG) { |
||||||||||
4379 | trace(__CLASS__ . " 304"); |
||||||||||
4380 | } |
||||||||||
4381 | exit; |
||||||||||
0 ignored issues
–
show
|
|||||||||||
4382 | } |
||||||||||
4383 | |||||||||||
4384 | foreach ($item["header-output"] as $value) { |
||||||||||
4385 | header($value); |
||||||||||
4386 | } |
||||||||||
4387 | |||||||||||
4388 | if (CIMAGE_DEBUG) { |
||||||||||
4389 | trace(__CLASS__ . " 200"); |
||||||||||
4390 | } |
||||||||||
4391 | readfile($item["source"]); |
||||||||||
4392 | exit; |
||||||||||
0 ignored issues
–
show
|
|||||||||||
4393 | } |
||||||||||
4394 | } |
||||||||||
4395 | |||||||||||
4396 | |||||||||||
4397 | |||||||||||
4398 | /** |
||||||||||
4399 | * Resize and crop images on the fly, store generated images in a cache. |
||||||||||
4400 | * |
||||||||||
4401 | * @author Mikael Roos [email protected] |
||||||||||
4402 | * @example http://dbwebb.se/opensource/cimage |
||||||||||
4403 | * @link https://github.com/mosbth/cimage |
||||||||||
4404 | * |
||||||||||
4405 | */ |
||||||||||
4406 | |||||||||||
4407 | /** |
||||||||||
4408 | * Custom exception handler. |
||||||||||
4409 | */ |
||||||||||
4410 | set_exception_handler(function ($exception) { |
||||||||||
4411 | errorPage( |
||||||||||
4412 | "<p><b>img.php: Uncaught exception:</b> <p>" |
||||||||||
4413 | . $exception->getMessage() |
||||||||||
4414 | . "</p><pre>" |
||||||||||
4415 | . $exception->getTraceAsString() |
||||||||||
4416 | . "</pre>", |
||||||||||
4417 | 500 |
||||||||||
4418 | ); |
||||||||||
4419 | }); |
||||||||||
4420 | |||||||||||
4421 | |||||||||||
4422 | |||||||||||
4423 | /** |
||||||||||
4424 | * Get configuration options from file, if the file exists, else use $config |
||||||||||
4425 | * if its defined or create an empty $config. |
||||||||||
4426 | */ |
||||||||||
4427 | $configFile = __DIR__.'/'.basename(__FILE__, '.php').'_config.php'; |
||||||||||
4428 | |||||||||||
4429 | if (is_file($configFile)) { |
||||||||||
4430 | $config = require $configFile; |
||||||||||
4431 | } elseif (!isset($config)) { |
||||||||||
4432 | $config = array(); |
||||||||||
4433 | } |
||||||||||
4434 | |||||||||||
4435 | // Make CIMAGE_DEBUG false by default, if not already defined |
||||||||||
4436 | if (!defined("CIMAGE_DEBUG")) { |
||||||||||
4437 | define("CIMAGE_DEBUG", false); |
||||||||||
4438 | } |
||||||||||
4439 | |||||||||||
4440 | |||||||||||
4441 | |||||||||||
4442 | /** |
||||||||||
4443 | * Setup the autoloader, but not when using a bundle. |
||||||||||
4444 | */ |
||||||||||
4445 | if (!defined("CIMAGE_BUNDLE")) { |
||||||||||
4446 | if (!isset($config["autoloader"])) { |
||||||||||
4447 | die("CImage: Missing autoloader."); |
||||||||||
4448 | } |
||||||||||
4449 | |||||||||||
4450 | require $config["autoloader"]; |
||||||||||
4451 | } |
||||||||||
4452 | |||||||||||
4453 | |||||||||||
4454 | |||||||||||
4455 | /** |
||||||||||
4456 | * verbose, v - do a verbose dump of what happens |
||||||||||
4457 | * vf - do verbose dump to file |
||||||||||
4458 | */ |
||||||||||
4459 | $verbose = getDefined(array('verbose', 'v'), true, false); |
||||||||||
4460 | $verboseFile = getDefined('vf', true, false); |
||||||||||
4461 | verbose("img.php version = " . CIMAGE_VERSION); |
||||||||||
4462 | |||||||||||
4463 | |||||||||||
4464 | |||||||||||
4465 | /** |
||||||||||
4466 | * status - do a verbose dump of the configuration |
||||||||||
4467 | */ |
||||||||||
4468 | $status = getDefined('status', true, false); |
||||||||||
4469 | |||||||||||
4470 | |||||||||||
4471 | |||||||||||
4472 | /** |
||||||||||
4473 | * Set mode as strict, production or development. |
||||||||||
4474 | * Default is production environment. |
||||||||||
4475 | */ |
||||||||||
4476 | $mode = getConfig('mode', 'production'); |
||||||||||
4477 | |||||||||||
4478 | // Settings for any mode |
||||||||||
4479 | set_time_limit(20); |
||||||||||
4480 | ini_set('gd.jpeg_ignore_warning', 1); |
||||||||||
4481 | |||||||||||
4482 | if (!extension_loaded('gd')) { |
||||||||||
4483 | errorPage("Extension gd is not loaded.", 500); |
||||||||||
4484 | } |
||||||||||
4485 | |||||||||||
4486 | // Specific settings for each mode |
||||||||||
4487 | if ($mode == 'strict') { |
||||||||||
4488 | |||||||||||
4489 | error_reporting(0); |
||||||||||
4490 | ini_set('display_errors', 0); |
||||||||||
4491 | ini_set('log_errors', 1); |
||||||||||
4492 | $verbose = false; |
||||||||||
4493 | $status = false; |
||||||||||
4494 | $verboseFile = false; |
||||||||||
4495 | |||||||||||
4496 | } elseif ($mode == 'production') { |
||||||||||
4497 | |||||||||||
4498 | error_reporting(-1); |
||||||||||
4499 | ini_set('display_errors', 0); |
||||||||||
4500 | ini_set('log_errors', 1); |
||||||||||
4501 | $verbose = false; |
||||||||||
4502 | $status = false; |
||||||||||
4503 | $verboseFile = false; |
||||||||||
4504 | |||||||||||
4505 | } elseif ($mode == 'development') { |
||||||||||
4506 | |||||||||||
4507 | error_reporting(-1); |
||||||||||
4508 | ini_set('display_errors', 1); |
||||||||||
4509 | ini_set('log_errors', 0); |
||||||||||
4510 | $verboseFile = false; |
||||||||||
4511 | |||||||||||
4512 | } elseif ($mode == 'test') { |
||||||||||
4513 | |||||||||||
4514 | error_reporting(-1); |
||||||||||
4515 | ini_set('display_errors', 1); |
||||||||||
4516 | ini_set('log_errors', 0); |
||||||||||
4517 | |||||||||||
4518 | } else { |
||||||||||
4519 | errorPage("Unknown mode: $mode", 500); |
||||||||||
4520 | } |
||||||||||
4521 | |||||||||||
4522 | verbose("mode = $mode"); |
||||||||||
4523 | verbose("error log = " . ini_get('error_log')); |
||||||||||
4524 | |||||||||||
4525 | |||||||||||
4526 | |||||||||||
4527 | /** |
||||||||||
4528 | * Set default timezone if not set or if its set in the config-file. |
||||||||||
4529 | */ |
||||||||||
4530 | $defaultTimezone = getConfig('default_timezone', null); |
||||||||||
4531 | |||||||||||
4532 | if ($defaultTimezone) { |
||||||||||
4533 | date_default_timezone_set($defaultTimezone); |
||||||||||
4534 | } elseif (!ini_get('default_timezone')) { |
||||||||||
4535 | date_default_timezone_set('UTC'); |
||||||||||
4536 | } |
||||||||||
4537 | |||||||||||
4538 | |||||||||||
4539 | |||||||||||
4540 | /** |
||||||||||
4541 | * Check if passwords are configured, used and match. |
||||||||||
4542 | * Options decide themself if they require passwords to be used. |
||||||||||
4543 | */ |
||||||||||
4544 | $pwdConfig = getConfig('password', false); |
||||||||||
4545 | $pwdAlways = getConfig('password_always', false); |
||||||||||
4546 | $pwdType = getConfig('password_type', 'text'); |
||||||||||
4547 | $pwd = get(array('password', 'pwd'), null); |
||||||||||
4548 | |||||||||||
4549 | // Check if passwords match, if configured to use passwords |
||||||||||
4550 | $passwordMatch = null; |
||||||||||
4551 | if ($pwd) { |
||||||||||
4552 | switch ($pwdType) { |
||||||||||
4553 | case 'md5': |
||||||||||
4554 | $passwordMatch = ($pwdConfig === md5($pwd)); |
||||||||||
4555 | break; |
||||||||||
4556 | case 'hash': |
||||||||||
4557 | $passwordMatch = password_verify($pwd, $pwdConfig); |
||||||||||
0 ignored issues
–
show
It seems like
$pwdConfig can also be of type false ; however, parameter $hash of password_verify() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
4558 | break; |
||||||||||
4559 | case 'text': |
||||||||||
4560 | $passwordMatch = ($pwdConfig === $pwd); |
||||||||||
4561 | break; |
||||||||||
4562 | default: |
||||||||||
4563 | $passwordMatch = false; |
||||||||||
4564 | } |
||||||||||
4565 | } |
||||||||||
4566 | |||||||||||
4567 | if ($pwdAlways && $passwordMatch !== true) { |
||||||||||
4568 | errorPage("Password required and does not match or exists.", 403); |
||||||||||
4569 | } |
||||||||||
4570 | |||||||||||
4571 | verbose("password match = $passwordMatch"); |
||||||||||
4572 | |||||||||||
4573 | |||||||||||
4574 | |||||||||||
4575 | /** |
||||||||||
4576 | * Prevent hotlinking, leeching, of images by controlling who access them |
||||||||||
4577 | * from where. |
||||||||||
4578 | * |
||||||||||
4579 | */ |
||||||||||
4580 | $allowHotlinking = getConfig('allow_hotlinking', true); |
||||||||||
4581 | $hotlinkingWhitelist = getConfig('hotlinking_whitelist', array()); |
||||||||||
4582 | |||||||||||
4583 | $serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null; |
||||||||||
4584 | $referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null; |
||||||||||
4585 | $refererHost = parse_url($referer, PHP_URL_HOST); |
||||||||||
4586 | |||||||||||
4587 | if (!$allowHotlinking) { |
||||||||||
4588 | if ($passwordMatch) { |
||||||||||
4589 | ; // Always allow when password match |
||||||||||
4590 | verbose("Hotlinking since passwordmatch"); |
||||||||||
4591 | } elseif ($passwordMatch === false) { |
||||||||||
4592 | errorPage("Hotlinking/leeching not allowed when password missmatch.", 403); |
||||||||||
4593 | } elseif (!$referer) { |
||||||||||
4594 | errorPage("Hotlinking/leeching not allowed and referer is missing.", 403); |
||||||||||
4595 | } elseif (strcmp($serverName, $refererHost) == 0) { |
||||||||||
0 ignored issues
–
show
It seems like
$serverName can also be of type null ; however, parameter $string1 of strcmp() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
4596 | ; // Allow when serverName matches refererHost |
||||||||||
4597 | verbose("Hotlinking disallowed but serverName matches refererHost."); |
||||||||||
4598 | } elseif (!empty($hotlinkingWhitelist)) { |
||||||||||
4599 | $whitelist = new CWhitelist(); |
||||||||||
4600 | $allowedByWhitelist = $whitelist->check($refererHost, $hotlinkingWhitelist); |
||||||||||
4601 | |||||||||||
4602 | if ($allowedByWhitelist) { |
||||||||||
4603 | verbose("Hotlinking/leeching allowed by whitelist."); |
||||||||||
4604 | } else { |
||||||||||
4605 | errorPage("Hotlinking/leeching not allowed by whitelist. Referer: $referer.", 403); |
||||||||||
4606 | } |
||||||||||
4607 | |||||||||||
4608 | } else { |
||||||||||
4609 | errorPage("Hotlinking/leeching not allowed.", 403); |
||||||||||
4610 | } |
||||||||||
4611 | } |
||||||||||
4612 | |||||||||||
4613 | verbose("allow_hotlinking = $allowHotlinking"); |
||||||||||
4614 | verbose("referer = $referer"); |
||||||||||
4615 | verbose("referer host = $refererHost"); |
||||||||||
4616 | |||||||||||
4617 | |||||||||||
4618 | |||||||||||
4619 | /** |
||||||||||
4620 | * Create the class for the image. |
||||||||||
4621 | */ |
||||||||||
4622 | $CImage = getConfig('CImage', 'CImage'); |
||||||||||
4623 | $img = new $CImage(); |
||||||||||
4624 | $img->setVerbose($verbose || $verboseFile); |
||||||||||
4625 | |||||||||||
4626 | |||||||||||
4627 | |||||||||||
4628 | /** |
||||||||||
4629 | * Get the cachepath from config. |
||||||||||
4630 | */ |
||||||||||
4631 | $CCache = getConfig('CCache', 'CCache'); |
||||||||||
4632 | $cachePath = getConfig('cache_path', __DIR__ . '/../cache/'); |
||||||||||
4633 | $cache = new $CCache(); |
||||||||||
4634 | $cache->setDir($cachePath); |
||||||||||
4635 | |||||||||||
4636 | |||||||||||
4637 | |||||||||||
4638 | /** |
||||||||||
4639 | * no-cache, nc - skip the cached version and process and create a new version in cache. |
||||||||||
4640 | */ |
||||||||||
4641 | $useCache = getDefined(array('no-cache', 'nc'), false, true); |
||||||||||
4642 | |||||||||||
4643 | verbose("use cache = $useCache"); |
||||||||||
4644 | |||||||||||
4645 | |||||||||||
4646 | |||||||||||
4647 | /** |
||||||||||
4648 | * Prepare fast track cache for swriting cache items. |
||||||||||
4649 | */ |
||||||||||
4650 | $fastTrackCache = "fasttrack"; |
||||||||||
4651 | $allowFastTrackCache = getConfig('fast_track_allow', false); |
||||||||||
4652 | |||||||||||
4653 | $CFastTrackCache = getConfig('CFastTrackCache', 'CFastTrackCache'); |
||||||||||
4654 | $ftc = new $CFastTrackCache(); |
||||||||||
4655 | $ftc->setCacheDir($cache->getPathToSubdir($fastTrackCache)) |
||||||||||
4656 | ->enable($allowFastTrackCache) |
||||||||||
4657 | ->setFilename(array('no-cache', 'nc')); |
||||||||||
4658 | $img->injectDependency("fastTrackCache", $ftc); |
||||||||||
4659 | |||||||||||
4660 | |||||||||||
4661 | |||||||||||
4662 | /** |
||||||||||
4663 | * Load and output images from fast track cache, if items are available |
||||||||||
4664 | * in cache. |
||||||||||
4665 | */ |
||||||||||
4666 | if ($useCache && $allowFastTrackCache) { |
||||||||||
4667 | if (CIMAGE_DEBUG) { |
||||||||||
4668 | trace("img.php fast track cache enabled and used"); |
||||||||||
4669 | } |
||||||||||
4670 | $ftc->output(); |
||||||||||
4671 | } |
||||||||||
4672 | |||||||||||
4673 | |||||||||||
4674 | |||||||||||
4675 | /** |
||||||||||
4676 | * Allow or disallow remote download of images from other servers. |
||||||||||
4677 | * Passwords apply if used. |
||||||||||
4678 | * |
||||||||||
4679 | */ |
||||||||||
4680 | $allowRemote = getConfig('remote_allow', false); |
||||||||||
4681 | |||||||||||
4682 | if ($allowRemote && $passwordMatch !== false) { |
||||||||||
4683 | $cacheRemote = $cache->getPathToSubdir("remote"); |
||||||||||
4684 | |||||||||||
4685 | $pattern = getConfig('remote_pattern', null); |
||||||||||
4686 | $img->setRemoteDownload($allowRemote, $cacheRemote, $pattern); |
||||||||||
4687 | |||||||||||
4688 | $whitelist = getConfig('remote_whitelist', null); |
||||||||||
4689 | $img->setRemoteHostWhitelist($whitelist); |
||||||||||
4690 | } |
||||||||||
4691 | |||||||||||
4692 | |||||||||||
4693 | |||||||||||
4694 | /** |
||||||||||
4695 | * shortcut, sc - extend arguments with a constant value, defined |
||||||||||
4696 | * in config-file. |
||||||||||
4697 | */ |
||||||||||
4698 | $shortcut = get(array('shortcut', 'sc'), null); |
||||||||||
4699 | $shortcutConfig = getConfig('shortcut', array( |
||||||||||
4700 | 'sepia' => "&f=grayscale&f0=brightness,-10&f1=contrast,-20&f2=colorize,120,60,0,0&sharpen", |
||||||||||
4701 | )); |
||||||||||
4702 | |||||||||||
4703 | verbose("shortcut = $shortcut"); |
||||||||||
4704 | |||||||||||
4705 | if (isset($shortcut) |
||||||||||
4706 | && isset($shortcutConfig[$shortcut])) { |
||||||||||
4707 | |||||||||||
4708 | parse_str($shortcutConfig[$shortcut], $get); |
||||||||||
4709 | verbose("shortcut-constant = {$shortcutConfig[$shortcut]}"); |
||||||||||
4710 | $_GET = array_merge($_GET, $get); |
||||||||||
4711 | } |
||||||||||
4712 | |||||||||||
4713 | |||||||||||
4714 | |||||||||||
4715 | /** |
||||||||||
4716 | * src - the source image file. |
||||||||||
4717 | */ |
||||||||||
4718 | $srcImage = urldecode(get('src')) |
||||||||||
0 ignored issues
–
show
It seems like
get('src') can also be of type null ; however, parameter $string of urldecode() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
4719 | or errorPage('Must set src-attribute.', 404); |
||||||||||
4720 | |||||||||||
4721 | // Get settings for src-alt as backup image |
||||||||||
4722 | $srcAltImage = urldecode(get('src-alt', null)); |
||||||||||
4723 | $srcAltConfig = getConfig('src_alt', null); |
||||||||||
4724 | if (empty($srcAltImage)) { |
||||||||||
4725 | $srcAltImage = $srcAltConfig; |
||||||||||
4726 | } |
||||||||||
4727 | |||||||||||
4728 | // Check for valid/invalid characters |
||||||||||
4729 | $imagePath = getConfig('image_path', __DIR__ . '/img/'); |
||||||||||
4730 | $imagePathConstraint = getConfig('image_path_constraint', true); |
||||||||||
4731 | $validFilename = getConfig('valid_filename', '#^[a-z0-9A-Z-/_ \.:]+$#'); |
||||||||||
4732 | |||||||||||
4733 | // Source is remote |
||||||||||
4734 | $remoteSource = false; |
||||||||||
4735 | |||||||||||
4736 | // Dummy image feature |
||||||||||
4737 | $dummyEnabled = getConfig('dummy_enabled', true); |
||||||||||
4738 | $dummyFilename = getConfig('dummy_filename', 'dummy'); |
||||||||||
4739 | $dummyImage = false; |
||||||||||
4740 | |||||||||||
4741 | preg_match($validFilename, $srcImage) |
||||||||||
4742 | or errorPage('Source filename contains invalid characters.', 404); |
||||||||||
4743 | |||||||||||
4744 | if ($dummyEnabled && $srcImage === $dummyFilename) { |
||||||||||
4745 | |||||||||||
4746 | // Prepare to create a dummy image and use it as the source image. |
||||||||||
4747 | $dummyImage = true; |
||||||||||
4748 | |||||||||||
4749 | } elseif ($allowRemote && $img->isRemoteSource($srcImage)) { |
||||||||||
4750 | |||||||||||
4751 | // If source is a remote file, ignore local file checks. |
||||||||||
4752 | $remoteSource = true; |
||||||||||
4753 | |||||||||||
4754 | } else { |
||||||||||
4755 | |||||||||||
4756 | // Check if file exists on disk or try using src-alt |
||||||||||
4757 | $pathToImage = realpath($imagePath . $srcImage); |
||||||||||
4758 | |||||||||||
4759 | if (!is_file($pathToImage) && !empty($srcAltImage)) { |
||||||||||
4760 | // Try using the src-alt instead |
||||||||||
4761 | $srcImage = $srcAltImage; |
||||||||||
4762 | $pathToImage = realpath($imagePath . $srcImage); |
||||||||||
4763 | |||||||||||
4764 | preg_match($validFilename, $srcImage) |
||||||||||
4765 | or errorPage('Source (alt) filename contains invalid characters.', 404); |
||||||||||
4766 | |||||||||||
4767 | if ($dummyEnabled && $srcImage === $dummyFilename) { |
||||||||||
4768 | // Check if src-alt is the dummy image |
||||||||||
4769 | $dummyImage = true; |
||||||||||
4770 | } |
||||||||||
4771 | } |
||||||||||
4772 | |||||||||||
4773 | if (!$dummyImage) { |
||||||||||
4774 | is_file($pathToImage) |
||||||||||
4775 | or errorPage( |
||||||||||
4776 | 'Source image is not a valid file, check the filename and that a |
||||||||||
4777 | matching file exists on the filesystem.', |
||||||||||
4778 | 404 |
||||||||||
4779 | ); |
||||||||||
4780 | } |
||||||||||
4781 | } |
||||||||||
4782 | |||||||||||
4783 | if ($imagePathConstraint && !$dummyImage && !$remoteSource) { |
||||||||||
4784 | // Check that the image is a file below the directory 'image_path'. |
||||||||||
4785 | $imageDir = realpath($imagePath); |
||||||||||
4786 | |||||||||||
4787 | substr_compare($imageDir, $pathToImage, 0, strlen($imageDir)) == 0 |
||||||||||
4788 | or errorPage( |
||||||||||
4789 | 'Security constraint: Source image is not below the directory "image_path" |
||||||||||
4790 | as specified in the config file img_config.php.', |
||||||||||
4791 | 404 |
||||||||||
4792 | ); |
||||||||||
4793 | } |
||||||||||
4794 | |||||||||||
4795 | verbose("src = $srcImage"); |
||||||||||
4796 | |||||||||||
4797 | |||||||||||
4798 | |||||||||||
4799 | /** |
||||||||||
4800 | * Manage size constants from config file, use constants to replace values |
||||||||||
4801 | * for width and height. |
||||||||||
4802 | */ |
||||||||||
4803 | $sizeConstant = getConfig('size_constant', function () { |
||||||||||
4804 | |||||||||||
4805 | // Set sizes to map constant to value, easier to use with width or height |
||||||||||
4806 | $sizes = array( |
||||||||||
4807 | 'w1' => 613, |
||||||||||
4808 | 'w2' => 630, |
||||||||||
4809 | ); |
||||||||||
4810 | |||||||||||
4811 | // Add grid column width, useful for use as predefined size for width (or height). |
||||||||||
4812 | $gridColumnWidth = 30; |
||||||||||
4813 | $gridGutterWidth = 10; |
||||||||||
4814 | $gridColumns = 24; |
||||||||||
4815 | |||||||||||
4816 | for ($i = 1; $i <= $gridColumns; $i++) { |
||||||||||
4817 | $sizes['c' . $i] = ($gridColumnWidth + $gridGutterWidth) * $i - $gridGutterWidth; |
||||||||||
4818 | } |
||||||||||
4819 | |||||||||||
4820 | return $sizes; |
||||||||||
4821 | }); |
||||||||||
4822 | |||||||||||
4823 | $sizes = call_user_func($sizeConstant); |
||||||||||
4824 | |||||||||||
4825 | |||||||||||
4826 | |||||||||||
4827 | /** |
||||||||||
4828 | * width, w - set target width, affecting the resulting image width, height and resize options |
||||||||||
4829 | */ |
||||||||||
4830 | $newWidth = get(array('width', 'w')); |
||||||||||
4831 | $maxWidth = getConfig('max_width', 2000); |
||||||||||
4832 | |||||||||||
4833 | // Check to replace predefined size |
||||||||||
4834 | if (isset($sizes[$newWidth])) { |
||||||||||
4835 | $newWidth = $sizes[$newWidth]; |
||||||||||
4836 | } |
||||||||||
4837 | |||||||||||
4838 | // Support width as % of original width |
||||||||||
4839 | if ($newWidth && $newWidth[strlen($newWidth)-1] == '%') { |
||||||||||
4840 | is_numeric(substr($newWidth, 0, -1)) |
||||||||||
4841 | or errorPage('Width % not numeric.', 404); |
||||||||||
4842 | } else { |
||||||||||
4843 | is_null($newWidth) |
||||||||||
4844 | or ($newWidth > 10 && $newWidth <= $maxWidth) |
||||||||||
4845 | or errorPage('Width out of range.', 404); |
||||||||||
4846 | } |
||||||||||
4847 | |||||||||||
4848 | verbose("new width = $newWidth"); |
||||||||||
4849 | |||||||||||
4850 | |||||||||||
4851 | |||||||||||
4852 | /** |
||||||||||
4853 | * height, h - set target height, affecting the resulting image width, height and resize options |
||||||||||
4854 | */ |
||||||||||
4855 | $newHeight = get(array('height', 'h')); |
||||||||||
4856 | $maxHeight = getConfig('max_height', 2000); |
||||||||||
4857 | |||||||||||
4858 | // Check to replace predefined size |
||||||||||
4859 | if (isset($sizes[$newHeight])) { |
||||||||||
4860 | $newHeight = $sizes[$newHeight]; |
||||||||||
4861 | } |
||||||||||
4862 | |||||||||||
4863 | // height |
||||||||||
4864 | if ($newHeight && $newHeight[strlen($newHeight)-1] == '%') { |
||||||||||
4865 | is_numeric(substr($newHeight, 0, -1)) |
||||||||||
4866 | or errorPage('Height % out of range.', 404); |
||||||||||
4867 | } else { |
||||||||||
4868 | is_null($newHeight) |
||||||||||
4869 | or ($newHeight > 10 && $newHeight <= $maxHeight) |
||||||||||
4870 | or errorPage('Height out of range.', 404); |
||||||||||
4871 | } |
||||||||||
4872 | |||||||||||
4873 | verbose("new height = $newHeight"); |
||||||||||
4874 | |||||||||||
4875 | |||||||||||
4876 | |||||||||||
4877 | /** |
||||||||||
4878 | * aspect-ratio, ar - affecting the resulting image width, height and resize options |
||||||||||
4879 | */ |
||||||||||
4880 | $aspectRatio = get(array('aspect-ratio', 'ar')); |
||||||||||
4881 | $aspectRatioConstant = getConfig('aspect_ratio_constant', function () { |
||||||||||
4882 | return array( |
||||||||||
4883 | '3:1' => 3/1, |
||||||||||
4884 | '3:2' => 3/2, |
||||||||||
4885 | '4:3' => 4/3, |
||||||||||
4886 | '8:5' => 8/5, |
||||||||||
4887 | '16:10' => 16/10, |
||||||||||
4888 | '16:9' => 16/9, |
||||||||||
4889 | 'golden' => 1.618, |
||||||||||
4890 | ); |
||||||||||
4891 | }); |
||||||||||
4892 | |||||||||||
4893 | // Check to replace predefined aspect ratio |
||||||||||
4894 | $aspectRatios = call_user_func($aspectRatioConstant); |
||||||||||
4895 | $negateAspectRatio = ($aspectRatio && $aspectRatio[0] == '!') ? true : false; |
||||||||||
4896 | $aspectRatio = $negateAspectRatio ? substr($aspectRatio, 1) : $aspectRatio; |
||||||||||
4897 | |||||||||||
4898 | if (isset($aspectRatios[$aspectRatio])) { |
||||||||||
4899 | $aspectRatio = $aspectRatios[$aspectRatio]; |
||||||||||
4900 | } |
||||||||||
4901 | |||||||||||
4902 | if ($negateAspectRatio) { |
||||||||||
4903 | $aspectRatio = 1 / $aspectRatio; |
||||||||||
4904 | } |
||||||||||
4905 | |||||||||||
4906 | is_null($aspectRatio) |
||||||||||
4907 | or is_numeric($aspectRatio) |
||||||||||
4908 | or errorPage('Aspect ratio out of range', 404); |
||||||||||
4909 | |||||||||||
4910 | verbose("aspect ratio = $aspectRatio"); |
||||||||||
4911 | |||||||||||
4912 | |||||||||||
4913 | |||||||||||
4914 | /** |
||||||||||
4915 | * crop-to-fit, cf - affecting the resulting image width, height and resize options |
||||||||||
4916 | */ |
||||||||||
4917 | $cropToFit = getDefined(array('crop-to-fit', 'cf'), true, false); |
||||||||||
4918 | |||||||||||
4919 | verbose("crop to fit = $cropToFit"); |
||||||||||
4920 | |||||||||||
4921 | |||||||||||
4922 | |||||||||||
4923 | /** |
||||||||||
4924 | * Set default background color from config file. |
||||||||||
4925 | */ |
||||||||||
4926 | $backgroundColor = getConfig('background_color', null); |
||||||||||
4927 | |||||||||||
4928 | if ($backgroundColor) { |
||||||||||
4929 | $img->setDefaultBackgroundColor($backgroundColor); |
||||||||||
4930 | verbose("Using default background_color = $backgroundColor"); |
||||||||||
4931 | } |
||||||||||
4932 | |||||||||||
4933 | |||||||||||
4934 | |||||||||||
4935 | /** |
||||||||||
4936 | * bgColor - Default background color to use |
||||||||||
4937 | */ |
||||||||||
4938 | $bgColor = get(array('bgColor', 'bg-color', 'bgc'), null); |
||||||||||
4939 | |||||||||||
4940 | verbose("bgColor = $bgColor"); |
||||||||||
4941 | |||||||||||
4942 | |||||||||||
4943 | |||||||||||
4944 | /** |
||||||||||
4945 | * Do or do not resample image when resizing. |
||||||||||
4946 | */ |
||||||||||
4947 | $resizeStrategy = getDefined(array('no-resample'), true, false); |
||||||||||
4948 | |||||||||||
4949 | if ($resizeStrategy) { |
||||||||||
4950 | $img->setCopyResizeStrategy($img::RESIZE); |
||||||||||
4951 | verbose("Setting = Resize instead of resample"); |
||||||||||
4952 | } |
||||||||||
4953 | |||||||||||
4954 | |||||||||||
4955 | |||||||||||
4956 | |||||||||||
4957 | /** |
||||||||||
4958 | * fill-to-fit, ff - affecting the resulting image width, height and resize options |
||||||||||
4959 | */ |
||||||||||
4960 | $fillToFit = get(array('fill-to-fit', 'ff'), null); |
||||||||||
4961 | |||||||||||
4962 | verbose("fill-to-fit = $fillToFit"); |
||||||||||
4963 | |||||||||||
4964 | if ($fillToFit !== null) { |
||||||||||
4965 | |||||||||||
4966 | if (!empty($fillToFit)) { |
||||||||||
4967 | $bgColor = $fillToFit; |
||||||||||
4968 | verbose("fillToFit changed bgColor to = $bgColor"); |
||||||||||
4969 | } |
||||||||||
4970 | |||||||||||
4971 | $fillToFit = true; |
||||||||||
4972 | verbose("fill-to-fit (fixed) = $fillToFit"); |
||||||||||
4973 | } |
||||||||||
4974 | |||||||||||
4975 | |||||||||||
4976 | |||||||||||
4977 | /** |
||||||||||
4978 | * no-ratio, nr, stretch - affecting the resulting image width, height and resize options |
||||||||||
4979 | */ |
||||||||||
4980 | $keepRatio = getDefined(array('no-ratio', 'nr', 'stretch'), false, true); |
||||||||||
4981 | |||||||||||
4982 | verbose("keep ratio = $keepRatio"); |
||||||||||
4983 | |||||||||||
4984 | |||||||||||
4985 | |||||||||||
4986 | /** |
||||||||||
4987 | * crop, c - affecting the resulting image width, height and resize options |
||||||||||
4988 | */ |
||||||||||
4989 | $crop = get(array('crop', 'c')); |
||||||||||
4990 | |||||||||||
4991 | verbose("crop = $crop"); |
||||||||||
4992 | |||||||||||
4993 | |||||||||||
4994 | |||||||||||
4995 | /** |
||||||||||
4996 | * area, a - affecting the resulting image width, height and resize options |
||||||||||
4997 | */ |
||||||||||
4998 | $area = get(array('area', 'a')); |
||||||||||
4999 | |||||||||||
5000 | verbose("area = $area"); |
||||||||||
5001 | |||||||||||
5002 | |||||||||||
5003 | |||||||||||
5004 | /** |
||||||||||
5005 | * skip-original, so - skip the original image and always process a new image |
||||||||||
5006 | */ |
||||||||||
5007 | $useOriginal = getDefined(array('skip-original', 'so'), false, true); |
||||||||||
5008 | $useOriginalDefault = getConfig('skip_original', false); |
||||||||||
5009 | |||||||||||
5010 | if ($useOriginalDefault === true) { |
||||||||||
5011 | verbose("skip original is default ON"); |
||||||||||
5012 | $useOriginal = false; |
||||||||||
5013 | } |
||||||||||
5014 | |||||||||||
5015 | verbose("use original = $useOriginal"); |
||||||||||
5016 | |||||||||||
5017 | |||||||||||
5018 | |||||||||||
5019 | /** |
||||||||||
5020 | * quality, q - set level of quality for jpeg images |
||||||||||
5021 | */ |
||||||||||
5022 | $quality = get(array('quality', 'q')); |
||||||||||
5023 | $qualityDefault = getConfig('jpg_quality', null); |
||||||||||
5024 | |||||||||||
5025 | is_null($quality) |
||||||||||
5026 | or ($quality > 0 and $quality <= 100) |
||||||||||
5027 | or errorPage('Quality out of range', 404); |
||||||||||
5028 | |||||||||||
5029 | if (is_null($quality) && !is_null($qualityDefault)) { |
||||||||||
5030 | $quality = $qualityDefault; |
||||||||||
5031 | } |
||||||||||
5032 | |||||||||||
5033 | verbose("quality = $quality"); |
||||||||||
5034 | |||||||||||
5035 | |||||||||||
5036 | |||||||||||
5037 | /** |
||||||||||
5038 | * compress, co - what strategy to use when compressing png images |
||||||||||
5039 | */ |
||||||||||
5040 | $compress = get(array('compress', 'co')); |
||||||||||
5041 | $compressDefault = getConfig('png_compression', null); |
||||||||||
5042 | |||||||||||
5043 | is_null($compress) |
||||||||||
5044 | or ($compress > 0 and $compress <= 9) |
||||||||||
5045 | or errorPage('Compress out of range', 404); |
||||||||||
5046 | |||||||||||
5047 | if (is_null($compress) && !is_null($compressDefault)) { |
||||||||||
5048 | $compress = $compressDefault; |
||||||||||
5049 | } |
||||||||||
5050 | |||||||||||
5051 | verbose("compress = $compress"); |
||||||||||
5052 | |||||||||||
5053 | |||||||||||
5054 | |||||||||||
5055 | /** |
||||||||||
5056 | * save-as, sa - what type of image to save |
||||||||||
5057 | */ |
||||||||||
5058 | $saveAs = get(array('save-as', 'sa')); |
||||||||||
5059 | |||||||||||
5060 | verbose("save as = $saveAs"); |
||||||||||
5061 | |||||||||||
5062 | |||||||||||
5063 | |||||||||||
5064 | /** |
||||||||||
5065 | * scale, s - Processing option, scale up or down the image prior actual resize |
||||||||||
5066 | */ |
||||||||||
5067 | $scale = get(array('scale', 's')); |
||||||||||
5068 | |||||||||||
5069 | is_null($scale) |
||||||||||
5070 | or ($scale >= 0 and $scale <= 400) |
||||||||||
5071 | or errorPage('Scale out of range', 404); |
||||||||||
5072 | |||||||||||
5073 | verbose("scale = $scale"); |
||||||||||
5074 | |||||||||||
5075 | |||||||||||
5076 | |||||||||||
5077 | /** |
||||||||||
5078 | * palette, p - Processing option, create a palette version of the image |
||||||||||
5079 | */ |
||||||||||
5080 | $palette = getDefined(array('palette', 'p'), true, false); |
||||||||||
5081 | |||||||||||
5082 | verbose("palette = $palette"); |
||||||||||
5083 | |||||||||||
5084 | |||||||||||
5085 | |||||||||||
5086 | /** |
||||||||||
5087 | * sharpen - Processing option, post filter for sharpen effect |
||||||||||
5088 | */ |
||||||||||
5089 | $sharpen = getDefined('sharpen', true, null); |
||||||||||
5090 | |||||||||||
5091 | verbose("sharpen = $sharpen"); |
||||||||||
5092 | |||||||||||
5093 | |||||||||||
5094 | |||||||||||
5095 | /** |
||||||||||
5096 | * emboss - Processing option, post filter for emboss effect |
||||||||||
5097 | */ |
||||||||||
5098 | $emboss = getDefined('emboss', true, null); |
||||||||||
5099 | |||||||||||
5100 | verbose("emboss = $emboss"); |
||||||||||
5101 | |||||||||||
5102 | |||||||||||
5103 | |||||||||||
5104 | /** |
||||||||||
5105 | * blur - Processing option, post filter for blur effect |
||||||||||
5106 | */ |
||||||||||
5107 | $blur = getDefined('blur', true, null); |
||||||||||
5108 | |||||||||||
5109 | verbose("blur = $blur"); |
||||||||||
5110 | |||||||||||
5111 | |||||||||||
5112 | |||||||||||
5113 | /** |
||||||||||
5114 | * rotateBefore - Rotate the image with an angle, before processing |
||||||||||
5115 | */ |
||||||||||
5116 | $rotateBefore = get(array('rotateBefore', 'rotate-before', 'rb')); |
||||||||||
5117 | |||||||||||
5118 | is_null($rotateBefore) |
||||||||||
5119 | or ($rotateBefore >= -360 and $rotateBefore <= 360) |
||||||||||
5120 | or errorPage('RotateBefore out of range', 404); |
||||||||||
5121 | |||||||||||
5122 | verbose("rotateBefore = $rotateBefore"); |
||||||||||
5123 | |||||||||||
5124 | |||||||||||
5125 | |||||||||||
5126 | /** |
||||||||||
5127 | * rotateAfter - Rotate the image with an angle, before processing |
||||||||||
5128 | */ |
||||||||||
5129 | $rotateAfter = get(array('rotateAfter', 'rotate-after', 'ra', 'rotate', 'r')); |
||||||||||
5130 | |||||||||||
5131 | is_null($rotateAfter) |
||||||||||
5132 | or ($rotateAfter >= -360 and $rotateAfter <= 360) |
||||||||||
5133 | or errorPage('RotateBefore out of range', 404); |
||||||||||
5134 | |||||||||||
5135 | verbose("rotateAfter = $rotateAfter"); |
||||||||||
5136 | |||||||||||
5137 | |||||||||||
5138 | |||||||||||
5139 | /** |
||||||||||
5140 | * autoRotate - Auto rotate based on EXIF information |
||||||||||
5141 | */ |
||||||||||
5142 | $autoRotate = getDefined(array('autoRotate', 'auto-rotate', 'aro'), true, false); |
||||||||||
5143 | |||||||||||
5144 | verbose("autoRotate = $autoRotate"); |
||||||||||
5145 | |||||||||||
5146 | |||||||||||
5147 | |||||||||||
5148 | /** |
||||||||||
5149 | * filter, f, f0-f9 - Processing option, post filter for various effects using imagefilter() |
||||||||||
5150 | */ |
||||||||||
5151 | $filters = array(); |
||||||||||
5152 | $filter = get(array('filter', 'f')); |
||||||||||
5153 | if ($filter) { |
||||||||||
5154 | $filters[] = $filter; |
||||||||||
5155 | } |
||||||||||
5156 | |||||||||||
5157 | for ($i = 0; $i < 10; $i++) { |
||||||||||
5158 | $filter = get(array("filter{$i}", "f{$i}")); |
||||||||||
5159 | if ($filter) { |
||||||||||
5160 | $filters[] = $filter; |
||||||||||
5161 | } |
||||||||||
5162 | } |
||||||||||
5163 | |||||||||||
5164 | verbose("filters = " . print_r($filters, 1)); |
||||||||||
0 ignored issues
–
show
Are you sure
print_r($filters, 1) of type string|true can be used in concatenation ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
5165 | |||||||||||
5166 | |||||||||||
5167 | |||||||||||
5168 | /** |
||||||||||
5169 | * json - output the image as a JSON object with details on the image. |
||||||||||
5170 | * ascii - output the image as ASCII art. |
||||||||||
5171 | */ |
||||||||||
5172 | $outputFormat = getDefined('json', 'json', null); |
||||||||||
5173 | $outputFormat = getDefined('ascii', 'ascii', $outputFormat); |
||||||||||
5174 | |||||||||||
5175 | verbose("outputformat = $outputFormat"); |
||||||||||
5176 | |||||||||||
5177 | if ($outputFormat == 'ascii') { |
||||||||||
5178 | $defaultOptions = getConfig( |
||||||||||
5179 | 'ascii-options', |
||||||||||
5180 | array( |
||||||||||
5181 | "characterSet" => 'two', |
||||||||||
5182 | "scale" => 14, |
||||||||||
5183 | "luminanceStrategy" => 3, |
||||||||||
5184 | "customCharacterSet" => null, |
||||||||||
5185 | ) |
||||||||||
5186 | ); |
||||||||||
5187 | $options = get('ascii'); |
||||||||||
5188 | $options = explode(',', $options); |
||||||||||
0 ignored issues
–
show
It seems like
$options can also be of type null ; however, parameter $string of explode() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
5189 | |||||||||||
5190 | if (isset($options[0]) && !empty($options[0])) { |
||||||||||
5191 | $defaultOptions['characterSet'] = $options[0]; |
||||||||||
5192 | } |
||||||||||
5193 | |||||||||||
5194 | if (isset($options[1]) && !empty($options[1])) { |
||||||||||
5195 | $defaultOptions['scale'] = $options[1]; |
||||||||||
5196 | } |
||||||||||
5197 | |||||||||||
5198 | if (isset($options[2]) && !empty($options[2])) { |
||||||||||
5199 | $defaultOptions['luminanceStrategy'] = $options[2]; |
||||||||||
5200 | } |
||||||||||
5201 | |||||||||||
5202 | if (count($options) > 3) { |
||||||||||
5203 | // Last option is custom character string |
||||||||||
5204 | unset($options[0]); |
||||||||||
5205 | unset($options[1]); |
||||||||||
5206 | unset($options[2]); |
||||||||||
5207 | $characterString = implode($options); |
||||||||||
5208 | $defaultOptions['customCharacterSet'] = $characterString; |
||||||||||
5209 | } |
||||||||||
5210 | |||||||||||
5211 | $img->setAsciiOptions($defaultOptions); |
||||||||||
5212 | } |
||||||||||
5213 | |||||||||||
5214 | |||||||||||
5215 | |||||||||||
5216 | |||||||||||
5217 | /** |
||||||||||
5218 | * dpr - change to get larger image to easier support larger dpr, such as retina. |
||||||||||
5219 | */ |
||||||||||
5220 | $dpr = get(array('ppi', 'dpr', 'device-pixel-ratio'), 1); |
||||||||||
5221 | |||||||||||
5222 | verbose("dpr = $dpr"); |
||||||||||
5223 | |||||||||||
5224 | |||||||||||
5225 | |||||||||||
5226 | /** |
||||||||||
5227 | * convolve - image convolution as in http://php.net/manual/en/function.imageconvolution.php |
||||||||||
5228 | */ |
||||||||||
5229 | $convolve = get('convolve', null); |
||||||||||
5230 | $convolutionConstant = getConfig('convolution_constant', array()); |
||||||||||
5231 | |||||||||||
5232 | // Check if the convolve is matching an existing constant |
||||||||||
5233 | if ($convolve && isset($convolutionConstant)) { |
||||||||||
5234 | $img->addConvolveExpressions($convolutionConstant); |
||||||||||
5235 | verbose("convolve constant = " . print_r($convolutionConstant, 1)); |
||||||||||
0 ignored issues
–
show
Are you sure
print_r($convolutionConstant, 1) of type string|true can be used in concatenation ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
5236 | } |
||||||||||
5237 | |||||||||||
5238 | verbose("convolve = " . print_r($convolve, 1)); |
||||||||||
0 ignored issues
–
show
Are you sure
print_r($convolve, 1) of type string|true can be used in concatenation ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
5239 | |||||||||||
5240 | |||||||||||
5241 | |||||||||||
5242 | /** |
||||||||||
5243 | * no-upscale, nu - Do not upscale smaller image to larger dimension. |
||||||||||
5244 | */ |
||||||||||
5245 | $upscale = getDefined(array('no-upscale', 'nu'), false, true); |
||||||||||
5246 | |||||||||||
5247 | verbose("upscale = $upscale"); |
||||||||||
5248 | |||||||||||
5249 | |||||||||||
5250 | |||||||||||
5251 | /** |
||||||||||
5252 | * Get details for post processing |
||||||||||
5253 | */ |
||||||||||
5254 | $postProcessing = getConfig('postprocessing', array( |
||||||||||
5255 | 'png_lossy' => false, |
||||||||||
5256 | 'png_lossy_cmd' => '/usr/local/bin/pngquant --force --output', |
||||||||||
5257 | |||||||||||
5258 | 'png_filter' => false, |
||||||||||
5259 | 'png_filter_cmd' => '/usr/local/bin/optipng -q', |
||||||||||
5260 | |||||||||||
5261 | 'png_deflate' => false, |
||||||||||
5262 | 'png_deflate_cmd' => '/usr/local/bin/pngout -q', |
||||||||||
5263 | |||||||||||
5264 | 'jpeg_optimize' => false, |
||||||||||
5265 | 'jpeg_optimize_cmd' => '/usr/local/bin/jpegtran -copy none -optimize', |
||||||||||
5266 | )); |
||||||||||
5267 | |||||||||||
5268 | |||||||||||
5269 | |||||||||||
5270 | /** |
||||||||||
5271 | * lossy - Do lossy postprocessing, if available. |
||||||||||
5272 | */ |
||||||||||
5273 | $lossy = getDefined(array('lossy'), true, null); |
||||||||||
5274 | |||||||||||
5275 | verbose("lossy = $lossy"); |
||||||||||
5276 | |||||||||||
5277 | |||||||||||
5278 | |||||||||||
5279 | /** |
||||||||||
5280 | * alias - Save resulting image to another alias name. |
||||||||||
5281 | * Password always apply, must be defined. |
||||||||||
5282 | */ |
||||||||||
5283 | $alias = get('alias', null); |
||||||||||
5284 | $aliasPath = getConfig('alias_path', null); |
||||||||||
5285 | $validAliasname = getConfig('valid_aliasname', '#^[a-z0-9A-Z-_]+$#'); |
||||||||||
5286 | $aliasTarget = null; |
||||||||||
5287 | |||||||||||
5288 | if ($alias && $aliasPath && $passwordMatch) { |
||||||||||
5289 | |||||||||||
5290 | $aliasTarget = $aliasPath . $alias; |
||||||||||
5291 | $useCache = false; |
||||||||||
5292 | |||||||||||
5293 | is_writable($aliasPath) |
||||||||||
5294 | or errorPage("Directory for alias is not writable.", 403); |
||||||||||
5295 | |||||||||||
5296 | preg_match($validAliasname, $alias) |
||||||||||
5297 | or errorPage('Filename for alias contains invalid characters. Do not add extension.', 404); |
||||||||||
5298 | |||||||||||
5299 | } elseif ($alias) { |
||||||||||
5300 | errorPage('Alias is not enabled in the config file or password not matching.', 403); |
||||||||||
5301 | } |
||||||||||
5302 | |||||||||||
5303 | verbose("alias = $alias"); |
||||||||||
5304 | |||||||||||
5305 | |||||||||||
5306 | |||||||||||
5307 | /** |
||||||||||
5308 | * Add cache control HTTP header. |
||||||||||
5309 | */ |
||||||||||
5310 | $cacheControl = getConfig('cache_control', null); |
||||||||||
5311 | |||||||||||
5312 | if ($cacheControl) { |
||||||||||
5313 | verbose("cacheControl = $cacheControl"); |
||||||||||
5314 | $img->addHTTPHeader("Cache-Control", $cacheControl); |
||||||||||
5315 | } |
||||||||||
5316 | |||||||||||
5317 | |||||||||||
5318 | |||||||||||
5319 | /** |
||||||||||
5320 | * Prepare a dummy image and use it as source image. |
||||||||||
5321 | */ |
||||||||||
5322 | if ($dummyImage === true) { |
||||||||||
5323 | $dummyDir = $cache->getPathToSubdir("dummy"); |
||||||||||
5324 | |||||||||||
5325 | $img->setSaveFolder($dummyDir) |
||||||||||
5326 | ->setSource($dummyFilename, $dummyDir) |
||||||||||
5327 | ->setOptions( |
||||||||||
5328 | array( |
||||||||||
5329 | 'newWidth' => $newWidth, |
||||||||||
5330 | 'newHeight' => $newHeight, |
||||||||||
5331 | 'bgColor' => $bgColor, |
||||||||||
5332 | ) |
||||||||||
5333 | ) |
||||||||||
5334 | ->setJpegQuality($quality) |
||||||||||
5335 | ->setPngCompression($compress) |
||||||||||
5336 | ->createDummyImage() |
||||||||||
5337 | ->generateFilename(null, false) |
||||||||||
5338 | ->save(null, null, false); |
||||||||||
5339 | |||||||||||
5340 | $srcImage = $img->getTarget(); |
||||||||||
5341 | $imagePath = null; |
||||||||||
5342 | |||||||||||
5343 | verbose("src (updated) = $srcImage"); |
||||||||||
5344 | } |
||||||||||
5345 | |||||||||||
5346 | |||||||||||
5347 | |||||||||||
5348 | /** |
||||||||||
5349 | * Prepare a sRGB version of the image and use it as source image. |
||||||||||
5350 | */ |
||||||||||
5351 | $srgbDefault = getConfig('srgb_default', false); |
||||||||||
5352 | $srgbColorProfile = getConfig('srgb_colorprofile', __DIR__ . '/../icc/sRGB_IEC61966-2-1_black_scaled.icc'); |
||||||||||
5353 | $srgb = getDefined('srgb', true, null); |
||||||||||
5354 | |||||||||||
5355 | if ($srgb || $srgbDefault) { |
||||||||||
5356 | |||||||||||
5357 | $filename = $img->convert2sRGBColorSpace( |
||||||||||
5358 | $srcImage, |
||||||||||
5359 | $imagePath, |
||||||||||
5360 | $cache->getPathToSubdir("srgb"), |
||||||||||
5361 | $srgbColorProfile, |
||||||||||
5362 | $useCache |
||||||||||
5363 | ); |
||||||||||
5364 | |||||||||||
5365 | if ($filename) { |
||||||||||
5366 | $srcImage = $img->getTarget(); |
||||||||||
5367 | $imagePath = null; |
||||||||||
5368 | verbose("srgb conversion and saved to cache = $srcImage"); |
||||||||||
5369 | } else { |
||||||||||
5370 | verbose("srgb not op"); |
||||||||||
5371 | } |
||||||||||
5372 | } |
||||||||||
5373 | |||||||||||
5374 | |||||||||||
5375 | |||||||||||
5376 | /** |
||||||||||
5377 | * Display status |
||||||||||
5378 | */ |
||||||||||
5379 | if ($status) { |
||||||||||
5380 | $text = "img.php version = " . CIMAGE_VERSION . "\n"; |
||||||||||
5381 | $text .= "PHP version = " . PHP_VERSION . "\n"; |
||||||||||
5382 | $text .= "Running on: " . $_SERVER['SERVER_SOFTWARE'] . "\n"; |
||||||||||
5383 | $text .= "Allow remote images = $allowRemote\n"; |
||||||||||
5384 | |||||||||||
5385 | $res = $cache->getStatusOfSubdir(""); |
||||||||||
5386 | $text .= "Cache $res\n"; |
||||||||||
5387 | |||||||||||
5388 | $res = $cache->getStatusOfSubdir("remote"); |
||||||||||
5389 | $text .= "Cache remote $res\n"; |
||||||||||
5390 | |||||||||||
5391 | $res = $cache->getStatusOfSubdir("dummy"); |
||||||||||
5392 | $text .= "Cache dummy $res\n"; |
||||||||||
5393 | |||||||||||
5394 | $res = $cache->getStatusOfSubdir("srgb"); |
||||||||||
5395 | $text .= "Cache srgb $res\n"; |
||||||||||
5396 | |||||||||||
5397 | $res = $cache->getStatusOfSubdir($fastTrackCache); |
||||||||||
5398 | $text .= "Cache fasttrack $res\n"; |
||||||||||
5399 | |||||||||||
5400 | $text .= "Alias path writable = " . is_writable($aliasPath) . "\n"; |
||||||||||
5401 | |||||||||||
5402 | $no = extension_loaded('exif') ? null : 'NOT'; |
||||||||||
5403 | $text .= "Extension exif is $no loaded.<br>"; |
||||||||||
5404 | |||||||||||
5405 | $no = extension_loaded('curl') ? null : 'NOT'; |
||||||||||
5406 | $text .= "Extension curl is $no loaded.<br>"; |
||||||||||
5407 | |||||||||||
5408 | $no = extension_loaded('imagick') ? null : 'NOT'; |
||||||||||
5409 | $text .= "Extension imagick is $no loaded.<br>"; |
||||||||||
5410 | |||||||||||
5411 | $no = extension_loaded('gd') ? null : 'NOT'; |
||||||||||
5412 | $text .= "Extension gd is $no loaded.<br>"; |
||||||||||
5413 | |||||||||||
5414 | $text .= checkExternalCommand("PNG LOSSY", $postProcessing["png_lossy"], $postProcessing["png_lossy_cmd"]); |
||||||||||
0 ignored issues
–
show
Are you sure the usage of
checkExternalCommand('PN...ssing['png_lossy_cmd']) is correct as it seems to always return null .
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. ![]() |
|||||||||||
5415 | $text .= checkExternalCommand("PNG FILTER", $postProcessing["png_filter"], $postProcessing["png_filter_cmd"]); |
||||||||||
0 ignored issues
–
show
Are you sure the usage of
checkExternalCommand('PN...sing['png_filter_cmd']) is correct as it seems to always return null .
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. ![]() |
|||||||||||
5416 | $text .= checkExternalCommand("PNG DEFLATE", $postProcessing["png_deflate"], $postProcessing["png_deflate_cmd"]); |
||||||||||
0 ignored issues
–
show
Are you sure the usage of
checkExternalCommand('PN...ing['png_deflate_cmd']) is correct as it seems to always return null .
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. ![]() |
|||||||||||
5417 | $text .= checkExternalCommand("JPEG OPTIMIZE", $postProcessing["jpeg_optimize"], $postProcessing["jpeg_optimize_cmd"]); |
||||||||||
0 ignored issues
–
show
Are you sure the usage of
checkExternalCommand('JP...g['jpeg_optimize_cmd']) is correct as it seems to always return null .
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. ![]() |
|||||||||||
5418 | |||||||||||
5419 | if (!$no) { |
||||||||||
5420 | $text .= print_r(gd_info(), 1); |
||||||||||
5421 | } |
||||||||||
5422 | |||||||||||
5423 | echo <<<EOD |
||||||||||
5424 | <!doctype html> |
||||||||||
5425 | <html lang=en> |
||||||||||
5426 | <meta charset=utf-8> |
||||||||||
5427 | <title>CImage status</title> |
||||||||||
5428 | <pre>$text</pre> |
||||||||||
5429 | EOD; |
||||||||||
5430 | exit; |
||||||||||
5431 | } |
||||||||||
5432 | |||||||||||
5433 | |||||||||||
5434 | |||||||||||
5435 | /** |
||||||||||
5436 | * Log verbose details to file |
||||||||||
5437 | */ |
||||||||||
5438 | if ($verboseFile) { |
||||||||||
5439 | $img->setVerboseToFile("$cachePath/log.txt"); |
||||||||||
5440 | } |
||||||||||
5441 | |||||||||||
5442 | |||||||||||
5443 | |||||||||||
5444 | /** |
||||||||||
5445 | * Hook after img.php configuration and before processing with CImage |
||||||||||
5446 | */ |
||||||||||
5447 | $hookBeforeCImage = getConfig('hook_before_CImage', null); |
||||||||||
5448 | |||||||||||
5449 | if (is_callable($hookBeforeCImage)) { |
||||||||||
5450 | verbose("hookBeforeCImage activated"); |
||||||||||
5451 | |||||||||||
5452 | $allConfig = $hookBeforeCImage($img, array( |
||||||||||
5453 | // Options for calculate dimensions |
||||||||||
5454 | 'newWidth' => $newWidth, |
||||||||||
5455 | 'newHeight' => $newHeight, |
||||||||||
5456 | 'aspectRatio' => $aspectRatio, |
||||||||||
5457 | 'keepRatio' => $keepRatio, |
||||||||||
5458 | 'cropToFit' => $cropToFit, |
||||||||||
5459 | 'fillToFit' => $fillToFit, |
||||||||||
5460 | 'crop' => $crop, |
||||||||||
5461 | 'area' => $area, |
||||||||||
5462 | 'upscale' => $upscale, |
||||||||||
5463 | |||||||||||
5464 | // Pre-processing, before resizing is done |
||||||||||
5465 | 'scale' => $scale, |
||||||||||
5466 | 'rotateBefore' => $rotateBefore, |
||||||||||
5467 | 'autoRotate' => $autoRotate, |
||||||||||
5468 | |||||||||||
5469 | // General processing options |
||||||||||
5470 | 'bgColor' => $bgColor, |
||||||||||
5471 | |||||||||||
5472 | // Post-processing, after resizing is done |
||||||||||
5473 | 'palette' => $palette, |
||||||||||
5474 | 'filters' => $filters, |
||||||||||
5475 | 'sharpen' => $sharpen, |
||||||||||
5476 | 'emboss' => $emboss, |
||||||||||
5477 | 'blur' => $blur, |
||||||||||
5478 | 'convolve' => $convolve, |
||||||||||
5479 | 'rotateAfter' => $rotateAfter, |
||||||||||
5480 | |||||||||||
5481 | // Output format |
||||||||||
5482 | 'outputFormat' => $outputFormat, |
||||||||||
5483 | 'dpr' => $dpr, |
||||||||||
5484 | |||||||||||
5485 | // Other |
||||||||||
5486 | 'postProcessing' => $postProcessing, |
||||||||||
5487 | 'lossy' => $lossy, |
||||||||||
5488 | )); |
||||||||||
5489 | verbose(print_r($allConfig, 1)); |
||||||||||
0 ignored issues
–
show
It seems like
print_r($allConfig, 1) can also be of type true ; however, parameter $msg of verbose() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||||
5490 | extract($allConfig); |
||||||||||
5491 | } |
||||||||||
5492 | |||||||||||
5493 | |||||||||||
5494 | |||||||||||
5495 | /** |
||||||||||
5496 | * Display image if verbose mode |
||||||||||
5497 | */ |
||||||||||
5498 | if ($verbose) { |
||||||||||
5499 | $query = array(); |
||||||||||
5500 | parse_str($_SERVER['QUERY_STRING'], $query); |
||||||||||
5501 | unset($query['verbose']); |
||||||||||
5502 | unset($query['v']); |
||||||||||
5503 | unset($query['nocache']); |
||||||||||
5504 | unset($query['nc']); |
||||||||||
5505 | unset($query['json']); |
||||||||||
5506 | $url1 = '?' . htmlentities(urldecode(http_build_query($query))); |
||||||||||
5507 | $url2 = '?' . urldecode(http_build_query($query)); |
||||||||||
5508 | echo <<<EOD |
||||||||||
5509 | <!doctype html> |
||||||||||
5510 | <html lang=en> |
||||||||||
5511 | <meta charset=utf-8> |
||||||||||
5512 | <title>CImage verbose output</title> |
||||||||||
5513 | <style>body{background-color: #ddd}</style> |
||||||||||
5514 | <a href=$url1><code>$url1</code></a><br> |
||||||||||
5515 | <img src='{$url1}' /> |
||||||||||
5516 | <pre id="json"></pre> |
||||||||||
5517 | <script src="https://code.jquery.com/jquery-2.1.1.min.js"></script> |
||||||||||
5518 | <script type="text/javascript"> |
||||||||||
5519 | window.getDetails = function (url, id) { |
||||||||||
5520 | $.getJSON(url, function(data) { |
||||||||||
5521 | element = document.getElementById(id); |
||||||||||
5522 | 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 : ''); |
||||||||||
5523 | }); |
||||||||||
5524 | } |
||||||||||
5525 | </script> |
||||||||||
5526 | <script type="text/javascript">window.getDetails("{$url2}&json", "json")</script> |
||||||||||
5527 | EOD; |
||||||||||
5528 | } |
||||||||||
5529 | |||||||||||
5530 | |||||||||||
5531 | |||||||||||
5532 | /** |
||||||||||
5533 | * Load, process and output the image |
||||||||||
5534 | */ |
||||||||||
5535 | $img->log("Incoming arguments: " . print_r(verbose(), 1)) |
||||||||||
0 ignored issues
–
show
Are you sure
print_r(verbose(), 1) of type string|true can be used in concatenation ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() Are you sure the usage of
verbose() is correct as it seems to always return null .
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. ![]() |
|||||||||||
5536 | ->setSaveFolder($cachePath) |
||||||||||
5537 | ->useCache($useCache) |
||||||||||
5538 | ->setSource($srcImage, $imagePath) |
||||||||||
5539 | ->setOptions( |
||||||||||
5540 | array( |
||||||||||
5541 | // Options for calculate dimensions |
||||||||||
5542 | 'newWidth' => $newWidth, |
||||||||||
5543 | 'newHeight' => $newHeight, |
||||||||||
5544 | 'aspectRatio' => $aspectRatio, |
||||||||||
5545 | 'keepRatio' => $keepRatio, |
||||||||||
5546 | 'cropToFit' => $cropToFit, |
||||||||||
5547 | 'fillToFit' => $fillToFit, |
||||||||||
5548 | 'crop' => $crop, |
||||||||||
5549 | 'area' => $area, |
||||||||||
5550 | 'upscale' => $upscale, |
||||||||||
5551 | |||||||||||
5552 | // Pre-processing, before resizing is done |
||||||||||
5553 | 'scale' => $scale, |
||||||||||
5554 | 'rotateBefore' => $rotateBefore, |
||||||||||
5555 | 'autoRotate' => $autoRotate, |
||||||||||
5556 | |||||||||||
5557 | // General processing options |
||||||||||
5558 | 'bgColor' => $bgColor, |
||||||||||
5559 | |||||||||||
5560 | // Post-processing, after resizing is done |
||||||||||
5561 | 'palette' => $palette, |
||||||||||
5562 | 'filters' => $filters, |
||||||||||
5563 | 'sharpen' => $sharpen, |
||||||||||
5564 | 'emboss' => $emboss, |
||||||||||
5565 | 'blur' => $blur, |
||||||||||
5566 | 'convolve' => $convolve, |
||||||||||
5567 | 'rotateAfter' => $rotateAfter, |
||||||||||
5568 | |||||||||||
5569 | // Output format |
||||||||||
5570 | 'outputFormat' => $outputFormat, |
||||||||||
5571 | 'dpr' => $dpr, |
||||||||||
5572 | |||||||||||
5573 | // Postprocessing using external tools |
||||||||||
5574 | 'lossy' => $lossy, |
||||||||||
5575 | ) |
||||||||||
5576 | ) |
||||||||||
5577 | ->loadImageDetails() |
||||||||||
5578 | ->initDimensions() |
||||||||||
5579 | ->calculateNewWidthAndHeight() |
||||||||||
5580 | ->setSaveAsExtension($saveAs) |
||||||||||
5581 | ->setJpegQuality($quality) |
||||||||||
5582 | ->setPngCompression($compress) |
||||||||||
5583 | ->useOriginalIfPossible($useOriginal) |
||||||||||
5584 | ->generateFilename($cachePath) |
||||||||||
5585 | ->useCacheIfPossible($useCache) |
||||||||||
5586 | ->load() |
||||||||||
5587 | ->preResize() |
||||||||||
5588 | ->resize() |
||||||||||
5589 | ->postResize() |
||||||||||
5590 | ->setPostProcessingOptions($postProcessing) |
||||||||||
5591 | ->save() |
||||||||||
5592 | ->linkToCacheFile($aliasTarget) |
||||||||||
5593 | ->output(); |
||||||||||
5594 | |||||||||||
5595 | |||||||||||
5596 | |||||||||||
5597 |
In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.