phpthumb_functions   F
last analyzed

Complexity

Total Complexity 228

Size/Duplication

Total Lines 943
Duplicated Lines 0 %

Importance

Changes 6
Bugs 0 Features 0
Metric Value
eloc 579
dl 0
loc 943
rs 2
c 6
b 0
f 0
wmc 228

46 Methods

Rating   Name   Duplication   Size   Complexity  
A FunctionIsDisabled() 0 18 5
C SafeURLread() 0 87 16
A ImageHexColorAllocate() 0 15 6
A filesize_remote() 0 19 5
A PixelColorDifferencePercent() 0 7 2
B GetAllFilesInSubfolders() 0 31 8
B ProportionalResize() 0 23 8
C URLreadFsock() 0 52 15
A gd_is_bundled() 0 8 2
A gd_version() 0 14 3
A version_compare_replacement() 0 26 4
A exif_info() 0 24 5
A ImageTypeToMIMEtype() 0 36 5
A LittleEndian2String() 0 8 2
A GrayscaleValue() 0 3 1
B ImageCopyRespectAlpha() 0 23 9
A md5_file_safe() 0 16 4
B ScaleToFitInBox() 0 20 9
A SanitizeFilename() 0 7 2
F version_compare_replacement_sub() 0 58 20
A ParseURLbetter() 0 10 4
B SafeExec() 0 39 9
A ImageCreateFunction() 0 13 5
A IsHexColor() 0 3 1
A phpinfo_array() 0 11 2
A URLschemeDefaultPort() 0 8 2
A OneOfThese() 0 10 3
A CaseInsensitiveInArray() 0 11 4
A builtin_function_exists() 0 10 3
A escapeshellarg_replacement() 0 6 3
A ApacheLookupURIarray() 0 15 4
A HexCharDisplay() 0 8 2
A user_function_exists() 0 10 3
A PasswordStrength() 0 8 1
A is_windows() 0 3 1
A filedate_remote() 0 19 5
A ImageCopyResampleBicubic() 0 46 4
A GetPixelColor() 0 6 4
A GrayscalePixel() 0 4 1
A TranslateWHbyAngle() 0 8 2
A GrayscalePixelRGB() 0 6 1
A nonempty_min() 0 10 3
A HexColorXOR() 0 3 1
A ImageColorAllocateAlphaSafe() 0 6 3
C EnsureDirectoryExists() 0 44 12
F CleanUpURLencoding() 0 37 14

How to fix   Complexity   

Complex Class

Complex classes like phpthumb_functions often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use phpthumb_functions, and based on these observations, apply Extract Interface, too.

1
<?php
2
//////////////////////////////////////////////////////////////
3
//   phpThumb() by James Heinrich <[email protected]>   //
4
//        available at http://phpthumb.sourceforge.net      //
5
//         and/or https://github.com/JamesHeinrich/phpThumb //
6
//////////////////////////////////////////////////////////////
7
///                                                         //
8
// phpthumb.functions.php - general support functions       //
9
//                                                         ///
10
//////////////////////////////////////////////////////////////
11
12
class phpthumb_functions
13
{
14
    public static function is_windows()
15
    {
16
        return (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN');
17
    }
18
19
    public static function user_function_exists($functionname)
20
    {
21
        if (function_exists('get_defined_functions')) {
22
            static $get_defined_functions = [];
23
            if (empty($get_defined_functions)) {
24
                $get_defined_functions = get_defined_functions();
25
            }
26
            return in_array(strtolower($functionname), $get_defined_functions['user']);
27
        }
28
        return function_exists($functionname);
29
    }
30
31
    public static function builtin_function_exists($functionname)
32
    {
33
        if (function_exists('get_defined_functions')) {
34
            static $get_defined_functions = [];
35
            if (empty($get_defined_functions)) {
36
                $get_defined_functions = get_defined_functions();
37
            }
38
            return in_array(strtolower($functionname), $get_defined_functions['internal']);
39
        }
40
        return function_exists($functionname);
41
    }
42
43
    public static function version_compare_replacement_sub($version1, $version2, $operator = '')
44
    {
45
        // If you specify the third optional operator argument, you can test for a particular relationship.
46
        // The possible operators are: <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne respectively.
47
        // Using this argument, the function will return 1 if the relationship is the one specified by the operator, 0 otherwise.
48
49
        // If a part contains special version strings these are handled in the following order:
50
        // (any string not found in this list) < (dev) < (alpha = a) < (beta = b) < (RC = rc) < (#) < (pl = p)
51
        static $versiontype_lookup = [];
52
        if (empty($versiontype_lookup)) {
53
            $versiontype_lookup['dev']   = 10001;
54
            $versiontype_lookup['a']     = 10002;
55
            $versiontype_lookup['alpha'] = 10002;
56
            $versiontype_lookup['b']     = 10003;
57
            $versiontype_lookup['beta']  = 10003;
58
            $versiontype_lookup['RC']    = 10004;
59
            $versiontype_lookup['rc']    = 10004;
60
            $versiontype_lookup['#']     = 10005;
61
            $versiontype_lookup['pl']    = 10006;
62
            $versiontype_lookup['p']     = 10006;
63
        }
64
        $version1 = (isset($versiontype_lookup[$version1]) ? $versiontype_lookup[$version1] : $version1);
65
        $version2 = (isset($versiontype_lookup[$version2]) ? $versiontype_lookup[$version2] : $version2);
66
67
        switch ($operator) {
68
            case '<':
69
            case 'lt':
70
                return (int)($version1 < $version2);
71
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
72
            case '<=':
73
            case 'le':
74
                return (int)($version1 <= $version2);
75
                break;
76
            case '>':
77
            case 'gt':
78
                return (int)($version1 > $version2);
79
                break;
80
            case '>=':
81
            case 'ge':
82
                return (int)($version1 >= $version2);
83
                break;
84
            case '==':
85
            case '=':
86
            case 'eq':
87
                return (int)($version1 == $version2);
88
                break;
89
            case '!=':
90
            case '<>':
91
            case 'ne':
92
                return (int)($version1 != $version2);
93
                break;
94
        }
95
        if ($version1 == $version2) {
96
            return 0;
97
        } elseif ($version1 < $version2) {
98
            return -1;
99
        }
100
        return 1;
101
    }
102
103
    public static function version_compare_replacement($version1, $version2, $operator = '')
104
    {
105
        if (function_exists('version_compare')) {
106
            // built into PHP v4.1.0+
107
            return version_compare($version1, $version2, $operator);
108
        }
109
110
        // The function first replaces _, - and + with a dot . in the version strings
111
        $version1 = strtr($version1, '_-+', '...');
112
        $version2 = strtr($version2, '_-+', '...');
113
114
        // and also inserts dots . before and after any non number so that for example '4.3.2RC1' becomes '4.3.2.RC.1'.
115
        // Then it splits the results like if you were using explode('.',$ver). Then it compares the parts starting from left to right.
116
        $version1 = preg_replace('#([\d]+)([A-Z]+)([\d]+)#i', '$1.$2.$3', $version1);
117
        $version2 = preg_replace('#([\d]+)([A-Z]+)([\d]+)#i', '$1.$2.$3', $version2);
118
119
        $parts1      = explode('.', $version1);
120
        $parts2      = explode('.', $version1);
121
        $parts_count = max(count($parts1), count($parts2));
122
        for ($i = 0; $i < $parts_count; $i++) {
123
            $comparison = self::version_compare_replacement_sub($version1, $version2, $operator);
124
            if ($comparison != 0) {
125
                return $comparison;
126
            }
127
        }
128
        return 0;
129
    }
130
131
    public static function escapeshellarg_replacement($arg)
132
    {
133
        if (function_exists('escapeshellarg') && !self::FunctionIsDisabled('escapeshellarg')) {
134
            return escapeshellarg($arg);
135
        }
136
        return '\'' . str_replace('\'', '\\\'', $arg) . '\'';
137
    }
138
139
    public static function phpinfo_array()
140
    {
141
        static $phpinfo_array = [];
142
        if (empty($phpinfo_array)) {
143
            ob_start();
144
            phpinfo();
145
            $phpinfo = ob_get_contents();
146
            ob_end_clean();
147
            $phpinfo_array = explode("\n", $phpinfo);
148
        }
149
        return $phpinfo_array;
150
    }
151
152
    public static function exif_info()
153
    {
154
        static $exif_info = [];
155
        if (empty($exif_info)) {
156
            // based on code by johnschaefer at gmx dot de
157
            // from PHP help on gd_info()
158
            $exif_info     = [
159
                'EXIF Support'           => '',
160
                'EXIF Version'           => '',
161
                'Supported EXIF Version' => '',
162
                'Supported filetypes'    => '',
163
            ];
164
            $phpinfo_array = self::phpinfo_array();
165
            foreach ($phpinfo_array as $line) {
166
                $line = trim(strip_tags($line));
167
                foreach ($exif_info as $key => $value) {
168
                    if (strpos($line, $key) === 0) {
169
                        $newvalue        = trim(str_replace($key, '', $line));
170
                        $exif_info[$key] = $newvalue;
171
                    }
172
                }
173
            }
174
        }
175
        return $exif_info;
176
    }
177
178
    public static function ImageTypeToMIMEtype($imagetype)
179
    {
180
        if (function_exists('image_type_to_mime_type') && ($imagetype >= 1) && ($imagetype <= 18)) {
181
            // PHP v4.3.0+
182
            return image_type_to_mime_type($imagetype);
183
        }
184
        static $image_type_to_mime_type = [
185
            1  => 'image/gif',                     // IMAGETYPE_GIF
186
            2  => 'image/jpeg',                    // IMAGETYPE_JPEG
187
            3  => 'image/png',                     // IMAGETYPE_PNG
188
            4  => 'application/x-shockwave-flash', // IMAGETYPE_SWF
189
            5  => 'image/psd',                     // IMAGETYPE_PSD
190
            6  => 'image/bmp',                     // IMAGETYPE_BMP
191
            7  => 'image/tiff',                    // IMAGETYPE_TIFF_II (intel byte order)
192
            8  => 'image/tiff',                    // IMAGETYPE_TIFF_MM (motorola byte order)
193
            9  => 'application/octet-stream',      // IMAGETYPE_JPC
194
            10 => 'image/jp2',                     // IMAGETYPE_JP2
195
            11 => 'application/octet-stream',      // IMAGETYPE_JPX
196
            12 => 'application/octet-stream',      // IMAGETYPE_JB2
197
            13 => 'application/x-shockwave-flash', // IMAGETYPE_SWC
198
            14 => 'image/iff',                     // IMAGETYPE_IFF
199
            15 => 'image/vnd.wap.wbmp',            // IMAGETYPE_WBMP
200
            16 => 'image/xbm',                     // IMAGETYPE_XBM
201
            17 => 'image/x-icon',                  // IMAGETYPE_ICO
202
            18 => 'image/webp',                    // IMAGETYPE_WEBP
203
204
            'gif'  => 'image/gif',                 // IMAGETYPE_GIF
205
            'jpg'  => 'image/jpeg',                // IMAGETYPE_JPEG
206
            'jpeg' => 'image/jpeg',                // IMAGETYPE_JPEG
207
            'png'  => 'image/png',                 // IMAGETYPE_PNG
208
            'bmp'  => 'image/bmp',                 // IMAGETYPE_BMP
209
            'ico'  => 'image/x-icon',              // IMAGETYPE_ICO
210
            'webp' => 'image/webp',                // IMAGETYPE_WEBP
211
        ];
212
213
        return (isset($image_type_to_mime_type[$imagetype]) ? $image_type_to_mime_type[$imagetype] : false);
214
    }
215
216
    public static function TranslateWHbyAngle($width, $height, $angle)
217
    {
218
        if (($angle % 180) == 0) {
219
            return [$width, $height];
220
        }
221
        $newwidth  = (abs(sin(deg2rad($angle))) * $height) + (abs(cos(deg2rad($angle))) * $width);
222
        $newheight = (abs(sin(deg2rad($angle))) * $width) + (abs(cos(deg2rad($angle))) * $height);
223
        return [$newwidth, $newheight];
224
    }
225
226
    public static function HexCharDisplay($string)
227
    {
228
        $len    = strlen($string);
229
        $output = '';
230
        for ($i = 0; $i < $len; $i++) {
231
            $output .= ' 0x' . str_pad(dechex(ord($string[$i])), 2, '0', STR_PAD_LEFT);
232
        }
233
        return $output;
234
    }
235
236
    public static function IsHexColor($HexColorString)
237
    {
238
        return preg_match('#^[0-9A-F]{6}$#i', $HexColorString);
239
    }
240
241
    public static function ImageColorAllocateAlphaSafe(&$gdimg_hexcolorallocate, $R, $G, $B, $alpha = false)
242
    {
243
        if (self::version_compare_replacement(PHP_VERSION, '4.3.2', '>=') && ($alpha !== false)) {
244
            return imagecolorallocatealpha($gdimg_hexcolorallocate, $R, $G, $B, (int)$alpha);
245
        } else {
246
            return imagecolorallocate($gdimg_hexcolorallocate, $R, $G, $B);
247
        }
248
    }
249
250
    public static function ImageHexColorAllocate(&$gdimg_hexcolorallocate, $HexColorString, $dieOnInvalid = false, $alpha = false)
251
    {
252
        if (!is_resource($gdimg_hexcolorallocate) && !(is_object($gdimg_hexcolorallocate) && $gdimg_hexcolorallocate instanceof \GdImage)) {
253
            die('$gdimg_hexcolorallocate is not a GD resource in ImageHexColorAllocate()');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
254
        }
255
        if (self::IsHexColor($HexColorString)) {
256
            $R = hexdec(substr($HexColorString, 0, 2));
257
            $G = hexdec(substr($HexColorString, 2, 2));
258
            $B = hexdec(substr($HexColorString, 4, 2));
259
            return self::ImageColorAllocateAlphaSafe($gdimg_hexcolorallocate, $R, $G, $B, $alpha);
260
        }
261
        if ($dieOnInvalid) {
262
            die('Invalid hex color string: "' . $HexColorString . '"');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
263
        }
264
        return imagecolorallocate($gdimg_hexcolorallocate, 0x00, 0x00, 0x00);
265
    }
266
267
    public static function HexColorXOR($hexcolor)
268
    {
269
        return strtoupper(str_pad(dechex(~hexdec($hexcolor) & 0xFFFFFF), 6, '0', STR_PAD_LEFT));
270
    }
271
272
    public static function GetPixelColor(&$img, $x, $y)
273
    {
274
        if (!is_resource($img) && !(is_object($img) && $img instanceof \GdImage)) {
275
            return false;
276
        }
277
        return @imagecolorsforindex($img, @imagecolorat($img, $x, $y));
278
    }
279
280
    public static function PixelColorDifferencePercent($currentPixel, $targetPixel)
281
    {
282
        $diff = 0;
283
        foreach ($targetPixel as $channel => $currentvalue) {
284
            $diff = max($diff, (max($currentPixel[$channel], $targetPixel[$channel]) - min($currentPixel[$channel], $targetPixel[$channel])) / 255);
285
        }
286
        return $diff * 100;
287
    }
288
289
    public static function GrayscaleValue($r, $g, $b)
290
    {
291
        return round(($r * 0.30) + ($g * 0.59) + ($b * 0.11));
292
    }
293
294
    public static function GrayscalePixel($OriginalPixel)
295
    {
296
        $gray = self::GrayscaleValue($OriginalPixel['red'], $OriginalPixel['green'], $OriginalPixel['blue']);
297
        return ['red' => $gray, 'green' => $gray, 'blue' => $gray];
298
    }
299
300
    public static function GrayscalePixelRGB($rgb)
301
    {
302
        $r = ($rgb >> 16) & 0xFF;
303
        $g = ($rgb >> 8) & 0xFF;
304
        $b = $rgb & 0xFF;
305
        return ($r * 0.299) + ($g * 0.587) + ($b * 0.114);
306
    }
307
308
    public static function ScaleToFitInBox($width, $height, $maxwidth = null, $maxheight = null, $allow_enlarge = true, $allow_reduce = true)
309
    {
310
        $maxwidth  = (null === $maxwidth ? $width : $maxwidth);
311
        $maxheight = (null === $maxheight ? $height : $maxheight);
312
        $scale_x   = 1;
313
        $scale_y   = 1;
314
        if (($width > $maxwidth) || ($width < $maxwidth)) {
315
            $scale_x = ($maxwidth / $width);
316
        }
317
        if (($height > $maxheight) || ($height < $maxheight)) {
318
            $scale_y = ($maxheight / $height);
319
        }
320
        $scale = min($scale_x, $scale_y);
321
        if (!$allow_enlarge) {
322
            $scale = min($scale, 1);
323
        }
324
        if (!$allow_reduce) {
325
            $scale = max($scale, 1);
326
        }
327
        return $scale;
328
    }
329
330
    public static function ImageCopyResampleBicubic($dst_img, $src_img, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h)
331
    {
332
        // ron at korving dot demon dot nl
333
        // http://www.php.net/imagecopyresampled
334
335
        $scaleX = ($src_w - 1) / $dst_w;
336
        $scaleY = ($src_h - 1) / $dst_h;
337
338
        $scaleX2 = $scaleX / 2.0;
339
        $scaleY2 = $scaleY / 2.0;
340
341
        $isTrueColor = imageistruecolor($src_img);
342
343
        for ($y = $src_y; $y < $src_y + $dst_h; $y++) {
344
            $sY   = $y * $scaleY;
345
            $siY  = (int)$sY;
346
            $siY2 = (int)$sY + $scaleY2;
347
348
            for ($x = $src_x; $x < $src_x + $dst_w; $x++) {
349
                $sX   = $x * $scaleX;
350
                $siX  = (int)$sX;
351
                $siX2 = (int)$sX + $scaleX2;
352
353
                if ($isTrueColor) {
354
                    $c1 = imagecolorat($src_img, $siX, $siY2);
355
                    $c2 = imagecolorat($src_img, $siX, $siY);
356
                    $c3 = imagecolorat($src_img, $siX2, $siY2);
357
                    $c4 = imagecolorat($src_img, $siX2, $siY);
358
359
                    $r = (($c1 + $c2 + $c3 + $c4) >> 2) & 0xFF0000;
360
                    $g = ((($c1 & 0x00FF00) + ($c2 & 0x00FF00) + ($c3 & 0x00FF00) + ($c4 & 0x00FF00)) >> 2) & 0x00FF00;
361
                    $b = ((($c1 & 0x0000FF) + ($c2 & 0x0000FF) + ($c3 & 0x0000FF) + ($c4 & 0x0000FF)) >> 2);
362
                } else {
363
                    $c1 = imagecolorsforindex($src_img, imagecolorat($src_img, $siX, $siY2));
364
                    $c2 = imagecolorsforindex($src_img, imagecolorat($src_img, $siX, $siY));
365
                    $c3 = imagecolorsforindex($src_img, imagecolorat($src_img, $siX2, $siY2));
366
                    $c4 = imagecolorsforindex($src_img, imagecolorat($src_img, $siX2, $siY));
367
368
                    $r = ($c1['red'] + $c2['red'] + $c3['red'] + $c4['red']) << 14;
369
                    $g = ($c1['green'] + $c2['green'] + $c3['green'] + $c4['green']) << 6;
370
                    $b = ($c1['blue'] + $c2['blue'] + $c3['blue'] + $c4['blue']) >> 2;
371
                }
372
                imagesetpixel($dst_img, $dst_x + $x - $src_x, $dst_y + $y - $src_y, $r + $g + $b);
373
            }
374
        }
375
        return true;
376
    }
377
378
    public static function ImageCreateFunction($x_size, $y_size)
379
    {
380
        $ImageCreateFunction = 'imagecreate';
381
        if (self::gd_version() >= 2.0) {
382
            $ImageCreateFunction = 'imagecreatetruecolor';
383
        }
384
        if (!function_exists($ImageCreateFunction)) {
385
            return phpthumb::ErrorImage($ImageCreateFunction . '() does not exist - no GD support?');
0 ignored issues
show
Bug Best Practice introduced by
The method phpthumb::ErrorImage() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

385
            return phpthumb::/** @scrutinizer ignore-call */ ErrorImage($ImageCreateFunction . '() does not exist - no GD support?');
Loading history...
386
        }
387
        if (($x_size <= 0) || ($y_size <= 0)) {
388
            return phpthumb::ErrorImage('Invalid image dimensions: ' . $ImageCreateFunction . '(' . $x_size . ', ' . $y_size . ')');
389
        }
390
        return $ImageCreateFunction(round($x_size), round($y_size));
391
    }
392
393
    public static function ImageCopyRespectAlpha(&$dst_im, &$src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $opacity_pct = 100)
394
    {
395
        $opacipct = $opacity_pct / 100;
396
        for ($x = $src_x; $x < $src_w; $x++) {
397
            for ($y = $src_y; $y < $src_h; $y++) {
398
                $RealPixel    = self::GetPixelColor($dst_im, $dst_x + $x, $dst_y + $y);
399
                $OverlayPixel = self::GetPixelColor($src_im, $x, $y);
400
                $alphapct     = $OverlayPixel['alpha'] / 127;
401
                $overlaypct   = (1 - $alphapct) * $opacipct;
402
403
                $newcolor = self::ImageColorAllocateAlphaSafe(
404
                    $dst_im,
405
                    $RealPixel['alpha'] == 127 ? $OverlayPixel['red'] : ($OverlayPixel['alpha'] == 127 ? $RealPixel['red'] : (round($RealPixel['red'] * (1 - $overlaypct)) + ($OverlayPixel['red'] * $overlaypct))),
406
                    $RealPixel['alpha'] == 127 ? $OverlayPixel['green'] : ($OverlayPixel['alpha'] == 127 ? $RealPixel['green'] : (round($RealPixel['green'] * (1 - $overlaypct)) + ($OverlayPixel['green'] * $overlaypct))),
407
                    $RealPixel['alpha'] == 127 ? $OverlayPixel['blue'] : ($OverlayPixel['alpha'] == 127 ? $RealPixel['blue'] : (round($RealPixel['blue'] * (1 - $overlaypct)) + ($OverlayPixel['blue'] * $overlaypct))),
408
                    //					0);
409
                    min([$RealPixel['alpha'], floor($OverlayPixel['alpha'] * $opacipct)])
410
                );
411
412
                imagesetpixel($dst_im, $dst_x + $x, $dst_y + $y, $newcolor);
413
            }
414
        }
415
        return true;
416
    }
417
418
    public static function ProportionalResize($old_width, $old_height, $new_width = false, $new_height = false)
419
    {
420
        $old_aspect_ratio = $old_width / $old_height;
421
        if (($new_width === false) && ($new_height === false)) {
422
            return false;
423
        } elseif ($new_width === false) {
424
            $new_width = $new_height * $old_aspect_ratio;
425
        } elseif ($new_height === false) {
426
            $new_height = $new_width / $old_aspect_ratio;
427
        }
428
        $new_aspect_ratio = $new_width / $new_height;
429
        if ($new_aspect_ratio == $old_aspect_ratio) {
430
            // great, done
431
        } elseif ($new_aspect_ratio < $old_aspect_ratio) {
432
            // limited by width
433
            $new_height = $new_width / $old_aspect_ratio;
434
        } elseif ($new_aspect_ratio > $old_aspect_ratio) {
435
            // limited by height
436
            $new_width = $new_height * $old_aspect_ratio;
437
        }
438
        return [
439
            (int)round($new_width),
440
            (int)round($new_height),
441
        ];
442
    }
443
444
    public static function FunctionIsDisabled($function)
445
    {
446
        static $DisabledFunctions = null;
447
        if (null === $DisabledFunctions) {
448
            $disable_functions_local  = explode(',', strtolower(@ini_get('disable_functions')));
0 ignored issues
show
Bug introduced by
It seems like @ini_get('disable_functions') can also be of type false; however, parameter $string of strtolower() 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 ignore-type  annotation

448
            $disable_functions_local  = explode(',', strtolower(/** @scrutinizer ignore-type */ @ini_get('disable_functions')));
Loading history...
449
            $disable_functions_global = explode(',', strtolower(@get_cfg_var('disable_functions')));
450
            foreach ($disable_functions_local as $key => $value) {
451
                $DisabledFunctions[trim($value)] = 'local';
452
            }
453
            foreach ($disable_functions_global as $key => $value) {
454
                $DisabledFunctions[trim($value)] = 'global';
455
            }
456
            if (@ini_get('safe_mode')) {
457
                $DisabledFunctions['shell_exec']     = 'local';
458
                $DisabledFunctions['set_time_limit'] = 'local';
459
            }
460
        }
461
        return isset($DisabledFunctions[strtolower($function)]);
462
    }
463
464
    public static function SafeExec($command)
465
    {
466
        static $AllowedExecFunctions = [];
467
        if (empty($AllowedExecFunctions)) {
468
            $AllowedExecFunctions = ['shell_exec' => true, 'passthru' => true, 'system' => true, 'exec' => true];
469
            foreach ($AllowedExecFunctions as $key => $value) {
470
                $AllowedExecFunctions[$key] = !self::FunctionIsDisabled($key);
471
            }
472
        }
473
        $command .= ' 2>&1'; // force redirect stderr to stdout
474
        foreach ($AllowedExecFunctions as $execfunction => $is_allowed) {
475
            if (!$is_allowed) {
476
                continue;
477
            }
478
            $returnvalue = false;
479
            switch ($execfunction) {
480
                case 'passthru':
481
                case 'system':
482
                    ob_start();
483
                    $execfunction($command);
484
                    $returnvalue = ob_get_contents();
485
                    ob_end_clean();
486
                    break;
487
488
                case 'exec':
489
                    $output      = [];
490
                    $lastline    = $execfunction($command, $output);
0 ignored issues
show
Unused Code introduced by
The assignment to $lastline is dead and can be removed.
Loading history...
491
                    $returnvalue = implode("\n", $output);
492
                    break;
493
494
                case 'shell_exec':
495
                    ob_start();
496
                    $returnvalue = $execfunction($command);
497
                    ob_end_clean();
498
                    break;
499
            }
500
            return $returnvalue;
501
        }
502
        return false;
503
    }
504
505
    public static function ApacheLookupURIarray($filename)
506
    {
507
        // apache_lookup_uri() only works when PHP is installed as an Apache module.
508
        if (PHP_SAPI == 'apache') {
509
            //$property_exists_exists = function_exists('property_exists');
510
            $keys = ['status', 'the_request', 'status_line', 'method', 'content_type', 'handler', 'uri', 'filename', 'path_info', 'args', 'boundary', 'no_cache', 'no_local_copy', 'allowed', 'send_bodyct', 'bytes_sent', 'byterange', 'clength', 'unparsed_uri', 'mtime', 'request_time'];
511
            if ($apacheLookupURIobject = @apache_lookup_uri($filename)) {
512
                $apacheLookupURIarray = [];
513
                foreach ($keys as $key) {
514
                    $apacheLookupURIarray[$key] = @$apacheLookupURIobject->$key;
515
                }
516
                return $apacheLookupURIarray;
517
            }
518
        }
519
        return false;
520
    }
521
522
    public static function gd_is_bundled()
523
    {
524
        static $isbundled = null;
525
        if (null === $isbundled) {
526
            $gd_info   = gd_info();
527
            $isbundled = (strpos($gd_info['GD Version'], 'bundled') !== false);
528
        }
529
        return $isbundled;
530
    }
531
532
    public static function gd_version($fullstring = false)
533
    {
534
        static $cache_gd_version = [];
535
        if (empty($cache_gd_version)) {
536
            $gd_info = gd_info();
537
            if (preg_match('#bundled \((.+)\)$#i', $gd_info['GD Version'], $matches)) {
538
                $cache_gd_version[1] = $gd_info['GD Version'];  // e.g. "bundled (2.0.15 compatible)"
539
                $cache_gd_version[0] = (float)$matches[1];     // e.g. "2.0" (not "bundled (2.0.15 compatible)")
540
            } else {
541
                $cache_gd_version[1] = $gd_info['GD Version'];                       // e.g. "1.6.2 or higher"
542
                $cache_gd_version[0] = (float)substr($gd_info['GD Version'], 0, 3); // e.g. "1.6" (not "1.6.2 or higher")
543
            }
544
        }
545
        return $cache_gd_version[(int)$fullstring];
546
    }
547
548
    public static function filesize_remote($remotefile, $timeout = 10)
549
    {
550
        $size       = false;
551
        $parsed_url = self::ParseURLbetter($remotefile);
552
        if ($fp = @fsockopen($parsed_url['host'], $parsed_url['port'], $errno, $errstr, $timeout)) {
553
            fwrite($fp, 'HEAD ' . $parsed_url['path'] . $parsed_url['query'] . ' HTTP/1.0' . "\r\n" . 'Host: ' . $parsed_url['host'] . "\r\n\r\n");
554
            if (self::version_compare_replacement(PHP_VERSION, '4.3.0', '>=')) {
555
                stream_set_timeout($fp, $timeout);
556
            }
557
            while (!feof($fp)) {
558
                $headerline = fgets($fp, 4096);
559
                if (preg_match('#^Content-Length: (.*)#i', $headerline, $matches)) {
560
                    $size = (int)$matches[1];
561
                    break;
562
                }
563
            }
564
            fclose($fp);
565
        }
566
        return $size;
567
    }
568
569
    public static function filedate_remote($remotefile, $timeout = 10)
570
    {
571
        $date       = false;
572
        $parsed_url = self::ParseURLbetter($remotefile);
573
        if ($fp = @fsockopen($parsed_url['host'], $parsed_url['port'], $errno, $errstr, $timeout)) {
574
            fwrite($fp, 'HEAD ' . $parsed_url['path'] . $parsed_url['query'] . ' HTTP/1.0' . "\r\n" . 'Host: ' . $parsed_url['host'] . "\r\n\r\n");
575
            if (self::version_compare_replacement(PHP_VERSION, '4.3.0', '>=')) {
576
                stream_set_timeout($fp, $timeout);
577
            }
578
            while (!feof($fp)) {
579
                $headerline = fgets($fp, 4096);
580
                if (preg_match('#^Last-Modified: (.*)#i', $headerline, $matches)) {
581
                    $date = strtotime($matches[1]) - date('Z');
582
                    break;
583
                }
584
            }
585
            fclose($fp);
586
        }
587
        return $date;
588
    }
589
590
    public static function md5_file_safe($filename)
591
    {
592
        // md5_file() doesn't exist in PHP < 4.2.0
593
        if (function_exists('md5_file')) {
594
            return md5_file($filename);
595
        }
596
        if ($fp = @fopen($filename, 'rb')) {
597
            $rawData = '';
598
            do {
599
                $buffer  = fread($fp, 8192);
600
                $rawData .= $buffer;
601
            } while (strlen($buffer) > 0);
602
            fclose($fp);
603
            return md5($rawData);
604
        }
605
        return false;
606
    }
607
608
    public static function nonempty_min()
609
    {
610
        $arg_list   = func_get_args();
611
        $acceptable = [];
612
        foreach ($arg_list as $arg) {
613
            if ($arg) {
614
                $acceptable[] = $arg;
615
            }
616
        }
617
        return min($acceptable);
618
    }
619
620
    public static function LittleEndian2String($number, $minbytes = 1)
621
    {
622
        $intstring = '';
623
        while ($number > 0) {
624
            $intstring .= chr($number & 255);
625
            $number    >>= 8;
626
        }
627
        return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT);
628
    }
629
630
    public static function OneOfThese()
631
    {
632
        // return the first useful (non-empty/non-zero/non-false) value from those passed
633
        $arg_list = func_get_args();
634
        foreach ($arg_list as $key => $value) {
635
            if ($value) {
636
                return $value;
637
            }
638
        }
639
        return false;
640
    }
641
642
    public static function CaseInsensitiveInArray($needle, $haystack)
643
    {
644
        $needle = strtolower($needle);
645
        foreach ($haystack as $key => $value) {
646
            if (is_array($value)) {
647
                // skip?
648
            } elseif ($needle == strtolower($value)) {
649
                return true;
650
            }
651
        }
652
        return false;
653
    }
654
655
    public static function URLreadFsock($host, $file, &$errstr, $successonly = true, $port = -1, $timeout = 10)
656
    {
657
        if (!function_exists('fsockopen') || self::FunctionIsDisabled('fsockopen')) {
658
            $errstr = 'URLreadFsock says: function fsockopen() unavailable';
659
            return false;
660
        }
661
        $port = (int)($port ? $port : -1); // passing anything as the $port parameter (even empty values like null, false, 0, "") will override the default -1. fsockopen uses -1 as the default port value.
662
        //if ($fp = @fsockopen($host, $port, $errno, $errstr, $timeout)) {
663
        if ($fp = @fsockopen((($port == 443) ? 'ssl://' : '') . $host, $port, $errno, $errstr, $timeout)) { // https://github.com/JamesHeinrich/phpThumb/issues/39
664
            $out = 'GET ' . $file . ' HTTP/1.0' . "\r\n";
665
            $out .= 'Host: ' . $host . "\r\n";
666
            $out .= 'Connection: Close' . "\r\n\r\n";
667
            fwrite($fp, $out);
668
669
            $isHeader           = true;
670
            $data_header        = '';
671
            $data_body          = '';
672
            $header_newlocation = '';
673
            while (!feof($fp)) {
674
                $line = fgets($fp, 1024);
675
                if ($isHeader) {
676
                    $data_header .= $line;
677
                } else {
678
                    $data_body .= $line;
679
                }
680
                if (preg_match('#^HTTP/[\\.\d]+ ([\d]+)\s*(.+)?$#i', rtrim($line), $matches)) {
681
                    [, $errno, $errstr] = $matches;
682
                    $errno = (int)$errno;
683
                } elseif (preg_match('#^Location: (.*)$#i', rtrim($line), $matches)) {
684
                    $header_newlocation = $matches[1];
685
                }
686
                if ($isHeader && ($line == "\r\n")) {
687
                    $isHeader = false;
688
                    if ($successonly) {
689
                        switch ($errno) {
690
                            case 200:
691
                                // great, continue
692
                                break;
693
694
                            default:
695
                                $errstr = $errno . ' ' . $errstr . ($header_newlocation ? '; Location: ' . $header_newlocation : '');
696
                                fclose($fp);
697
                                return false;
698
                                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
699
                        }
700
                    }
701
                }
702
            }
703
            fclose($fp);
704
            return $data_body;
705
        }
706
        return null;
707
    }
708
709
    public static function CleanUpURLencoding($url, $queryseperator = '&')
710
    {
711
        if (!0 === stripos($url, "http")) {
712
            return $url;
713
        }
714
        $parsed_url        = self::ParseURLbetter($url);
715
        $pathelements      = explode('/', $parsed_url['path']);
716
        $CleanPathElements = [];
717
        $TranslationMatrix = [' ' => '%20'];
718
        foreach ($pathelements as $key => $pathelement) {
719
            $CleanPathElements[] = strtr($pathelement, $TranslationMatrix);
720
        }
721
        foreach ($CleanPathElements as $key => $value) {
722
            if ($value === '') {
723
                unset($CleanPathElements[$key]);
724
            }
725
        }
726
727
        $queries      = explode($queryseperator, $parsed_url['query']);
728
        $CleanQueries = [];
729
        foreach ($queries as $key => $query) {
730
            @list($param, $value) = explode('=', $query);
731
            $CleanQueries[] = strtr($param, $TranslationMatrix) . ($value ? '=' . strtr($value, $TranslationMatrix) : '');
732
        }
733
        foreach ($CleanQueries as $key => $value) {
734
            if ($value === '') {
735
                unset($CleanQueries[$key]);
736
            }
737
        }
738
739
        $cleaned_url = $parsed_url['scheme'] . '://';
740
        $cleaned_url .= ($parsed_url['user'] ? $parsed_url['user'] . ($parsed_url['pass'] ? ':' . $parsed_url['pass'] : '') . '@' : '');
741
        $cleaned_url .= $parsed_url['host'];
742
        $cleaned_url .= (($parsed_url['port'] && ($parsed_url['port'] != self::URLschemeDefaultPort($parsed_url['scheme']))) ? ':' . $parsed_url['port'] : '');
743
        $cleaned_url .= '/' . implode('/', $CleanPathElements);
744
        $cleaned_url .= (!empty($CleanQueries) ? '?' . implode($queryseperator, $CleanQueries) : '');
745
        return $cleaned_url;
746
    }
747
748
    public static function URLschemeDefaultPort($scheme)
749
    {
750
        static $schemePort = [
751
            'ftp'   => 21,
752
            'http'  => 80,
753
            'https' => 443,
754
        ];
755
        return (isset($schemePort[strtolower($scheme)]) ? $schemePort[strtolower($scheme)] : null);
756
    }
757
758
    public static function ParseURLbetter($url)
759
    {
760
        $parsedURL = @parse_url($url);
761
        foreach (['scheme', 'host', 'port', 'user', 'pass', 'path', 'query', 'fragment'] as $key) { // ensure all possible array keys are always returned
762
            if (!array_key_exists($key, $parsedURL)) {
763
                $parsedURL[$key] = null;
764
            }
765
        }
766
        $parsedURL['port'] = ($parsedURL['port'] ? $parsedURL['port'] : self::URLschemeDefaultPort($parsedURL['scheme']));
767
        return $parsedURL;
768
    }
769
770
    public static function SafeURLread($url, &$error, $timeout = 10, $followredirects = true)
771
    {
772
        $error   = '';
773
        $errstr  = '';
774
        $rawData = '';
775
776
        $parsed_url                      = self::ParseURLbetter($url);
777
        $alreadyLookedAtURLs[trim($url)] = true;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$alreadyLookedAtURLs was never initialized. Although not strictly required by PHP, it is generally a good practice to add $alreadyLookedAtURLs = array(); before regardless.
Loading history...
778
779
        while (true) {
780
            $tryagain = false;
781
            $rawData  = self::URLreadFsock($parsed_url['host'], $parsed_url['path'] . '?' . $parsed_url['query'], $errstr, true, $parsed_url['port'], $timeout);
782
            if ($followredirects && preg_match('#302 [a-z ]+; Location\\: (http.*)#i', $errstr, $matches)) {
783
                $matches[1] = trim(@$matches[1]);
784
                if (!@$alreadyLookedAtURLs[$matches[1]]) {
785
                    // loop through and examine new URL
786
                    $error .= 'URL "' . $url . '" redirected to "' . $matches[1] . '"';
787
788
                    $tryagain                         = true;
789
                    $alreadyLookedAtURLs[$matches[1]] = true;
790
                    $parsed_url                       = self::ParseURLbetter($matches[1]);
791
                }
792
            }
793
            if (!$tryagain) {
794
                break;
795
            }
796
        }
797
798
        if ($rawData === false) {
799
            $error .= 'Error opening "' . $url . '":' . "\n\n" . $errstr;
800
            return false;
801
        } elseif ($rawData === null) {
0 ignored issues
show
introduced by
The condition $rawData === null is always false.
Loading history...
802
            // fall through
803
            $error .= 'Error opening "' . $url . '":' . "\n\n" . $errstr;
804
        } else {
805
            return $rawData;
806
        }
807
808
        if (function_exists('curl_version') && !self::FunctionIsDisabled('curl_exec')) {
809
            $ch = curl_init();
810
            curl_setopt($ch, CURLOPT_URL, $url);
811
            curl_setopt($ch, CURLOPT_HEADER, false);
812
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
813
            curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
0 ignored issues
show
introduced by
The constant CURLOPT_BINARYTRANSFER has been deprecated: 5.1.3 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

813
            curl_setopt($ch, /** @scrutinizer ignore-deprecated */ CURLOPT_BINARYTRANSFER, true);
Loading history...
814
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
815
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
816
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, (bool)$followredirects);
817
            curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
818
            $rawData = curl_exec($ch);
819
            curl_close($ch);
820
            if (strlen($rawData) > 0) {
821
                $error .= 'CURL succeeded (' . strlen($rawData) . ' bytes); ';
822
                return $rawData;
823
            }
824
            $error .= 'CURL available but returned no data; ';
825
        } else {
826
            $error .= 'CURL unavailable; ';
827
        }
828
829
        $BrokenURLfopenPHPversions = ['4.4.2'];
830
        if (in_array(PHP_VERSION, $BrokenURLfopenPHPversions)) {
831
            $error .= 'fopen(URL) broken in PHP v' . PHP_VERSION . '; ';
832
        } elseif (@ini_get('allow_url_fopen')) {
833
            $rawData     = '';
834
            $error_fopen = '';
835
            ob_start();
836
            if ($fp = fopen($url, 'rb')) {
837
                do {
838
                    $buffer  = fread($fp, 8192);
839
                    $rawData .= $buffer;
840
                } while (strlen($buffer) > 0);
841
                fclose($fp);
842
            } else {
843
                $error_fopen .= trim(strip_tags(ob_get_contents()));
844
            }
845
            ob_end_clean();
846
            $error .= $error_fopen;
847
            if (!$error_fopen) {
848
                $error .= '; "allow_url_fopen" succeeded (' . strlen($rawData) . ' bytes); ';
849
                return $rawData;
850
            }
851
            $error .= '; "allow_url_fopen" enabled but returned no data (' . $error_fopen . '); ';
852
        } else {
853
            $error .= '"allow_url_fopen" disabled; ';
854
        }
855
856
        return false;
857
    }
858
859
    public static function EnsureDirectoryExists($dirname, $mask = 0755)
860
    {
861
        // https://www.php.net/manual/en/ini.core.php#ini.open-basedir says:
862
        // "Under Windows, separate the directories with a semicolon. On all other systems, separate the directories with a colon."
863
        $config_open_basedir = ini_get('open_basedir');
864
        $startoffset         = 2; // 1-based counting, first element to left of first directory separator will either be drive letter (Windows) or blank (unix). May be overridden below.
865
        if (self::is_windows()) {
866
            $delimiter                 = ';';
867
            $case_insensitive_pathname = true;
868
            // unix OSs will always use "/", some Windows configurations you may find "/" used interchangeably with the OS-correct "\", so standardize for ease of comparison
869
            $dirname             = str_replace('/', DIRECTORY_SEPARATOR, $dirname);
870
            $config_open_basedir = str_replace('/', DIRECTORY_SEPARATOR, $config_open_basedir);
871
        } else {
872
            $delimiter                 = ':';
873
            $case_insensitive_pathname = false;
874
        }
875
        $open_basedirs = explode($delimiter, $config_open_basedir);
876
        foreach ($open_basedirs as $key => $open_basedir) {
877
            if (preg_match('#^' . preg_quote($open_basedir) . '#' . ($case_insensitive_pathname ? 'i' : ''), $dirname) && (strlen($dirname) > strlen($open_basedir))) {
878
                $startoffset = substr_count($open_basedir, DIRECTORY_SEPARATOR) + 1;
879
                break;
880
            }
881
        }
882
883
        $directory_elements = explode(DIRECTORY_SEPARATOR, $dirname);
884
        $endoffset          = count($directory_elements);
885
        for ($i = $startoffset; $i <= $endoffset; $i++) {
886
            $test_directory = implode(DIRECTORY_SEPARATOR, array_slice($directory_elements, 0, $i));
887
            if (!$test_directory) {
888
                continue;
889
            }
890
            if (!@is_dir($test_directory)) {
891
                if (@file_exists($test_directory)) {
892
                    // directory name already exists as a file
893
                    return false;
894
                }
895
                @mkdir($test_directory, $mask);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for mkdir(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

895
                /** @scrutinizer ignore-unhandled */ @mkdir($test_directory, $mask);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
896
                @chmod($test_directory, $mask);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for chmod(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

896
                /** @scrutinizer ignore-unhandled */ @chmod($test_directory, $mask);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
897
                if (!@is_dir($test_directory) || !@is_writable($test_directory)) {
898
                    return false;
899
                }
900
            }
901
        }
902
        return true;
903
    }
904
905
    public static function GetAllFilesInSubfolders($dirname)
906
    {
907
        $AllFiles = [];
908
        $dirname  = rtrim(realpath($dirname), '/\\');
909
        if ($dirhandle = @opendir($dirname)) {
910
            while (($file = readdir($dirhandle)) !== false) {
911
                $fullfilename = $dirname . DIRECTORY_SEPARATOR . $file;
912
                if (is_file($fullfilename)) {
913
                    $AllFiles[] = $fullfilename;
914
                } elseif (is_dir($fullfilename)) {
915
                    switch ($file) {
916
                        case '.':
917
                        case '..':
918
                            break;
919
920
                        default:
921
                            $AllFiles[] = $fullfilename;
922
                            $subfiles   = self::GetAllFilesInSubfolders($fullfilename);
923
                            foreach ($subfiles as $filename) {
924
                                $AllFiles[] = $filename;
925
                            }
926
                            break;
927
                    }
928
                } else {
929
                    // ignore?
930
                }
931
            }
932
            closedir($dirhandle);
933
        }
934
        sort($AllFiles);
935
        return array_unique($AllFiles);
936
    }
937
938
    public static function SanitizeFilename($filename)
939
    {
940
        $filename = preg_replace('/[^' . preg_quote(' !#$%^()+,-.;<>=@[]_{}') . 'a-zA-Z0-9]/', '_', $filename);
941
        if (self::version_compare_replacement(PHP_VERSION, '4.1.0', '>=')) {
942
            $filename = trim($filename, '.');
943
        }
944
        return $filename;
945
    }
946
947
    public static function PasswordStrength($password)
948
    {
949
        $strength = 0;
950
        $strength += strlen(preg_replace('#[^a-z]#', '', $password)) * 0.5; // lowercase characters are weak
951
        $strength += strlen(preg_replace('#[^A-Z]#', '', $password)) * 0.8; // uppercase characters are somewhat better
952
        $strength += strlen(preg_replace('#[^0-9]#', '', $password)) * 1.0; // numbers are somewhat better
953
        $strength += strlen(preg_replace('#[a-zA-Z0-9]#', '', $password)) * 2.0; // other non-alphanumeric characters are best
954
        return $strength;
955
    }
956
}
957
958
////////////// END: class phpthumb_functions //////////////
959
960
if (!function_exists('gd_info')) {
961
    // built into PHP v4.3.0+ (with bundled GD2 library)
962
    function gd_info()
963
    {
964
        static $gd_info = [];
965
        if (empty($gd_info)) {
966
            // based on code by johnschaefer at gmx dot de
967
            // from PHP help on gd_info()
968
            $gd_info       = [
969
                'GD Version'         => '',
970
                'FreeType Support'   => false,
971
                'FreeType Linkage'   => '',
972
                'T1Lib Support'      => false,
973
                'GIF Read Support'   => false,
974
                'GIF Create Support' => false,
975
                'JPG Support'        => false,
976
                'PNG Support'        => false,
977
                'WBMP Support'       => false,
978
                'XBM Support'        => false,
979
            ];
980
            $phpinfo_array = phpthumb_functions::phpinfo_array();
981
            foreach ($phpinfo_array as $line) {
982
                $line = trim(strip_tags($line));
983
                foreach ($gd_info as $key => $value) {
984
                    //if (strpos($line, $key) !== false) {
985
                    if (strpos($line, $key) === 0) {
986
                        $newvalue      = trim(str_replace($key, '', $line));
987
                        $gd_info[$key] = $newvalue;
988
                    }
989
                }
990
            }
991
            if (empty($gd_info['GD Version'])) {
992
                // probable cause: "phpinfo() disabled for security reasons"
993
                if (function_exists('imagetypes')) {
994
                    $imagetypes = imagetypes();
995
                    if ($imagetypes & IMG_PNG) {
996
                        $gd_info['PNG Support'] = true;
997
                    }
998
                    if ($imagetypes & IMG_GIF) {
999
                        $gd_info['GIF Create Support'] = true;
1000
                    }
1001
                    if ($imagetypes & IMG_JPG) {
1002
                        $gd_info['JPG Support'] = true;
1003
                    }
1004
                    if ($imagetypes & IMG_WBMP) {
1005
                        $gd_info['WBMP Support'] = true;
1006
                    }
1007
                }
1008
                // to determine capability of GIF creation, try to use imagecreatefromgif on a 1px GIF
1009
                if (function_exists('imagecreatefromgif')) {
1010
                    if ($tempfilename = phpthumb::phpThumb_tempnam()) {
0 ignored issues
show
Bug Best Practice introduced by
The method phpthumb::phpThumb_tempnam() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1010
                    if ($tempfilename = phpthumb::/** @scrutinizer ignore-call */ phpThumb_tempnam()) {
Loading history...
1011
                        if ($fp_tempfile = @fopen($tempfilename, 'wb')) {
1012
                            fwrite($fp_tempfile, base64_decode('R0lGODlhAQABAIAAAH//AP///ywAAAAAAQABAAACAUQAOw==')); // very simple 1px GIF file base64-encoded as string
1013
                            fclose($fp_tempfile);
1014
                            $phpthumb_temp = new phpthumb();
1015
                            @chmod($tempfilename, $phpthumb_temp->getParameter('config_file_create_mask'));
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for chmod(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

1015
                            /** @scrutinizer ignore-unhandled */ @chmod($tempfilename, $phpthumb_temp->getParameter('config_file_create_mask'));

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1016
1017
                            // if we can convert the GIF file to a GD image then GIF create support must be enabled, otherwise it's not
1018
                            $gd_info['GIF Read Support'] = (bool)@imagecreatefromgif($tempfilename);
1019
                        }
1020
                        unlink($tempfilename);
1021
                    }
1022
                }
1023
                if (function_exists('imagecreatetruecolor') && @imagecreatetruecolor(1, 1)) {
1024
                    $gd_info['GD Version'] = '2.0.1 or higher (assumed)';
1025
                } elseif (function_exists('imagecreate') && @imagecreate(1, 1)) {
1026
                    $gd_info['GD Version'] = '1.6.0 or higher (assumed)';
1027
                }
1028
            }
1029
        }
1030
        return $gd_info;
1031
    }
1032
}
1033
1034
if (!function_exists('is_executable')) {
1035
    // in PHP v3+, but v5.0+ for Windows
1036
    function is_executable($filename)
1037
    {
1038
        // poor substitute, but better than nothing
1039
        return file_exists($filename);
1040
    }
1041
}
1042
1043
if (!function_exists('preg_quote')) {
1044
    // included in PHP v3.0.9+, but may be unavailable if not compiled in
1045
    function preg_quote($string, $delimiter = '\\')
1046
    {
1047
        static $preg_quote_array = [];
1048
        if (empty($preg_quote_array)) {
1049
            $escapeables = '.\\+*?[^]$(){}=!<>|:';
1050
            for ($i = 0, $iMax = strlen($escapeables); $i < $iMax; $i++) {
1051
                $strtr_preg_quote[$escapeables[$i]] = $delimiter . $escapeables[$i];
1052
            }
1053
        }
1054
        return strtr($string, $strtr_preg_quote);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $strtr_preg_quote does not seem to be defined for all execution paths leading up to this point.
Loading history...
1055
    }
1056
}
1057
1058
if (!function_exists('file_get_contents')) {
1059
    // included in PHP v4.3.0+
1060
    function file_get_contents($filename)
1061
    {
1062
        if (preg_match('#^(f|ht)tp\://#i', $filename)) {
1063
            return SafeURLread($filename, $error);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $error seems to be never defined.
Loading history...
Bug introduced by
The function SafeURLread was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1063
            return /** @scrutinizer ignore-call */ SafeURLread($filename, $error);
Loading history...
1064
        }
1065
        if ($fp = @fopen($filename, 'rb')) {
1066
            $rawData = '';
1067
            do {
1068
                $buffer  = fread($fp, 8192);
1069
                $rawData .= $buffer;
1070
            } while (strlen($buffer) > 0);
1071
            fclose($fp);
1072
            return $rawData;
1073
        }
1074
        return false;
1075
    }
1076
}
1077
1078
if (!function_exists('file_put_contents')) {
1079
    // included in PHP v5.0.0+
1080
    function file_put_contents($filename, $filedata)
1081
    {
1082
        if ($fp = @fopen($filename, 'wb')) {
1083
            fwrite($fp, $filedata);
1084
            fclose($fp);
1085
            return true;
1086
        }
1087
        return false;
1088
    }
1089
}
1090
1091
if (!function_exists('imagealphablending')) {
1092
    // built-in function requires PHP v4.0.6+ *and* GD v2.0.1+
1093
    function imagealphablending(&$img, $blendmode = true)
0 ignored issues
show
Unused Code introduced by
The parameter $img 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 ignore-unused  annotation

1093
    function imagealphablending(/** @scrutinizer ignore-unused */ &$img, $blendmode = true)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $blendmode 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 ignore-unused  annotation

1093
    function imagealphablending(&$img, /** @scrutinizer ignore-unused */ $blendmode = true)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1094
    {
1095
        // do nothing, this function is declared here just to
1096
        // prevent runtime errors if GD2 is not available
1097
        return true;
1098
    }
1099
}
1100
1101
if (!function_exists('imagesavealpha')) {
1102
    // built-in function requires PHP v4.3.2+ *and* GD v2.0.1+
1103
    function imagesavealpha(&$img, $blendmode = true)
0 ignored issues
show
Unused Code introduced by
The parameter $blendmode 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 ignore-unused  annotation

1103
    function imagesavealpha(&$img, /** @scrutinizer ignore-unused */ $blendmode = true)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $img 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 ignore-unused  annotation

1103
    function imagesavealpha(/** @scrutinizer ignore-unused */ &$img, $blendmode = true)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1104
    {
1105
        // do nothing, this function is declared here just to
1106
        // prevent runtime errors if GD2 is not available
1107
        return true;
1108
    }
1109
}
1110