Passed
Pull Request — master (#6)
by
unknown
01:45
created

Cropper::fromWebp()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 9
c 1
b 0
f 0
nc 1
nop 6
dl 0
loc 14
rs 9.9666
1
<?php
2
3
namespace CoffeeCode\Cropper;
4
5
/**
6
 * Class CoffeeCode Cropper
7
 *
8
 * @author Robson V. Leite <https://github.com/robsonvleite>
9
 * @package CoffeeCode\Cropper
10
 */
11
class Cropper
12
{
13
    /** @var string */
14
    private $cachePath;
15
16
    /** @var array */
17
    private $cacheSize;
18
19
    /** @var string */
20
    private $imagePath;
21
22
    /** @var string */
23
    private $imageName;
24
25
    /** @var string */
26
    private $imageMime;
27
28
    /** @var string */
29
    private $imageInfo;
30
31
    /**
32
     * Allow jpg and png to thumb and cache generate
33
     *
34
     * @var array allowed media types
35
     */
36
    private static $allowedExt = ['image/jpeg', "image/png", "image/webp"];
37
38
    /**
39
     * Cropper constructor.
40
     *
41
     * @param string $cachePath
42
     * @param int $jpgQuality
43
     * @param int $pngCompressor
44
     * @throws \Exception
45
     */
46
    public function __construct(string $cachePath, int $jpgQuality = 75, int $pngCompressor = 5)
47
    {
48
        $this->cachePath = $cachePath;
49
        $this->cacheSize = [$jpgQuality, $pngCompressor];
50
51
        if (!file_exists($this->cachePath) || !is_dir($this->cachePath)) {
52
            if (!mkdir($this->cachePath, 0755)) {
53
                throw new \Exception("Could not create cache folder");
54
            }
55
        }
56
    }
57
58
    /**
59
     * Make an thumb image
60
     *
61
     * @param string $imagePath
62
     * @param int $width
63
     * @param int|null $height
64
     * @return null|string
65
     */
66
    public function make(string $imagePath, int $width, int $height = null): ?string
67
    {
68
        if (!file_exists($imagePath)) {
69
            return "Image not found";
70
        }
71
72
        $this->imagePath = $imagePath;
73
        $this->imageMime = mime_content_type($this->imagePath);
74
        $this->imageInfo = pathinfo($this->imagePath);
75
76
        if (!in_array($this->imageMime, self::$allowedExt)) {
77
            return "Not a valid JPG or PNG image";
78
        }
79
80
        $this->imageName = $this->name($this->imagePath, $width, $height);
81
        if (file_exists("{$this->cachePath}/{$this->imageName}") && is_file("{$this->cachePath}/{$this->imageName}")) {
82
            return "{$this->cachePath}/{$this->imageName}";
83
        }
84
85
        return $this->imageCache($width, $height);
86
    }
87
88
    /**
89
     * @param string $name
90
     * @return string
91
     */
92
    protected function name(string $name, int $width = null, int $height = null): string
93
    {
94
        $filterName = filter_var(mb_strtolower(pathinfo($name)["filename"]), FILTER_SANITIZE_STRIPPED);
95
        $formats = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜüÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûýýþÿRr"!@#$%&*()_-+={[}]/?;:.,\\\'<>°ºª';
96
        $replace = 'aaaaaaaceeeeiiiidnoooooouuuuuybsaaaaaaaceeeeiiiidnoooooouuuyybyRr                                 ';
97
        $trimName = trim(strtr(utf8_decode($filterName), utf8_decode($formats), $replace));
98
        $name = str_replace(["-----", "----", "---", "--"], "-", str_replace(" ", "-", $trimName));
99
100
        $hash = $this->hash($this->imagePath);
101
        $ext = ($this->imageMime == "image/jpeg" ? ".jpg" : ".png");
102
        $widthName = ($width ? "-{$width}" : "");
103
        $heightName = ($height ? "x{$height}" : "");
104
105
        return "{$name}{$widthName}{$heightName}-{$hash}{$ext}";
106
    }
107
108
    /**
109
     * @param string $path
110
     * @return string
111
     */
112
    protected function hash(string $path): string
113
    {
114
        return hash("crc32", $path);
115
    }
116
117
    /**
118
     * Clear cache
119
     *
120
     * @param string|null $imagePath
121
     * @example $t->flush("images/image.jpg"); clear image name and variations size
122
     * @example $t->flush(); clear all image cache folder
123
     */
124
    public function flush(string $imagePath = null): void
125
    {
126
        foreach (scandir($this->cachePath) as $file) {
127
            $file = "{$this->cachePath}/{$file}";
128
            if ($imagePath && strpos($file, $this->hash($imagePath))) {
129
                $this->imageDestroy($file);
130
            } elseif (!$imagePath) {
131
                $this->imageDestroy($file);
132
            }
133
        }
134
    }
135
136
    /**
137
     * @param int $width
138
     * @param int|null $height
139
     * @return null|string
140
     */
141
    private function imageCache(int $width, int $height = null): ?string
142
    {
143
        list($src_w, $src_h) = getimagesize($this->imagePath);
144
        $height = ($height ?? ($width * $src_h) / $src_w);
145
146
        $src_x = 0;
147
        $src_y = 0;
148
149
        $cmp_x = $src_w / $width;
150
        $cmp_y = $src_h / $height;
151
152
        if ($cmp_x > $cmp_y) {
153
            $src_w = round($src_w / $cmp_x * $cmp_y);
154
            $src_x = round(($src_w - ($src_w / $cmp_x * $cmp_y))); //2
155
        } elseif ($cmp_y > $cmp_x) {
156
            $src_h = round($src_h / $cmp_y * $cmp_x);
157
            $src_y = round(($src_h - ($src_h / $cmp_y * $cmp_x))); //2
158
        }
159
160
        $src_x = (int)$src_x;
161
        $src_h = (int)$src_h;
162
        $src_y = (int)$src_y;
163
        $src_y = (int)$src_y;
164
165
        if ($this->imageMime == "image/jpeg") {
166
            return $this->fromJpg($width, $height, $src_x, $src_y, $src_w, $src_h);
167
        }
168
169
        if ($this->imageMime == "image/png") {
170
            return $this->fromPng($width, $height, $src_x, $src_y, $src_w, $src_h);
171
        }
172
        
173
        if ($this->imageMime == "image/webp") {
174
            return $this->fromWebp($width, $height, $src_x, $src_y, $src_w, $src_h);
175
        }
176
177
        return null;
178
    }
179
180
    /**
181
     * @param string $imagePatch
182
     */
183
    private function imageDestroy(string $imagePatch): void
184
    {
185
        if (file_exists($imagePatch) && is_file($imagePatch)) {
186
            unlink($imagePatch);
187
        }
188
    }
189
190
    /**
191
     * @param int $width
192
     * @param int $height
193
     * @param int $src_x
194
     * @param int $src_y
195
     * @param int $src_w
196
     * @param int $src_h
197
     * @return string
198
     */
199
    private function fromJpg(int $width, int $height, int $src_x, int $src_y, int $src_w, int $src_h): string
200
    {
201
        $thumb = imagecreatetruecolor($width, $height);
202
        $source = imagecreatefromjpeg($this->imagePath);
203
        imagecopyresized($thumb, $source, 0, 0, $src_x, $src_y, $width, $height, $src_w, $src_h);
0 ignored issues
show
Bug introduced by
It seems like $thumb can also be of type false; however, parameter $dst_image of imagecopyresized() 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 ignore-type  annotation

203
        imagecopyresized(/** @scrutinizer ignore-type */ $thumb, $source, 0, 0, $src_x, $src_y, $width, $height, $src_w, $src_h);
Loading history...
Bug introduced by
It seems like $source can also be of type false; however, parameter $src_image of imagecopyresized() 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 ignore-type  annotation

203
        imagecopyresized($thumb, /** @scrutinizer ignore-type */ $source, 0, 0, $src_x, $src_y, $width, $height, $src_w, $src_h);
Loading history...
204
        imagejpeg($thumb, "{$this->cachePath}/{$this->imageName}", $this->cacheSize[0]);
0 ignored issues
show
Bug introduced by
It seems like $thumb can also be of type false; however, parameter $image of imagejpeg() 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 ignore-type  annotation

204
        imagejpeg(/** @scrutinizer ignore-type */ $thumb, "{$this->cachePath}/{$this->imageName}", $this->cacheSize[0]);
Loading history...
205
206
        imagedestroy($thumb);
0 ignored issues
show
Bug introduced by
It seems like $thumb can also be of type false; however, parameter $image of imagedestroy() 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 ignore-type  annotation

206
        imagedestroy(/** @scrutinizer ignore-type */ $thumb);
Loading history...
207
        imagedestroy($source);
208
209
        return "{$this->cachePath}/{$this->imageName}";
210
    }
211
212
    /**
213
     * @param int $width
214
     * @param int $height
215
     * @param int $src_x
216
     * @param int $src_y
217
     * @param int $src_w
218
     * @param int $src_h
219
     * @return string
220
     */
221
    private function fromPng(int $width, int $height, int $src_x, int $src_y, int $src_w, int $src_h): string
222
    {
223
        $thumb = imagecreatetruecolor($width, $height);
224
        $source = imagecreatefrompng($this->imagePath);
225
226
        imagealphablending($thumb, false);
0 ignored issues
show
Bug introduced by
It seems like $thumb can also be of type false; however, parameter $image of imagealphablending() 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 ignore-type  annotation

226
        imagealphablending(/** @scrutinizer ignore-type */ $thumb, false);
Loading history...
227
        imagesavealpha($thumb, true);
0 ignored issues
show
Bug introduced by
It seems like $thumb can also be of type false; however, parameter $image of imagesavealpha() 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 ignore-type  annotation

227
        imagesavealpha(/** @scrutinizer ignore-type */ $thumb, true);
Loading history...
228
        imagecopyresized($thumb, $source, 0, 0, $src_x, $src_y, $width, $height, $src_w, $src_h);
0 ignored issues
show
Bug introduced by
It seems like $source can also be of type false; however, parameter $src_image of imagecopyresized() 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 ignore-type  annotation

228
        imagecopyresized($thumb, /** @scrutinizer ignore-type */ $source, 0, 0, $src_x, $src_y, $width, $height, $src_w, $src_h);
Loading history...
Bug introduced by
It seems like $thumb can also be of type false; however, parameter $dst_image of imagecopyresized() 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 ignore-type  annotation

228
        imagecopyresized(/** @scrutinizer ignore-type */ $thumb, $source, 0, 0, $src_x, $src_y, $width, $height, $src_w, $src_h);
Loading history...
229
        imagepng($thumb, "{$this->cachePath}/{$this->imageName}", $this->cacheSize[1]);
0 ignored issues
show
Bug introduced by
It seems like $thumb can also be of type false; however, parameter $image of imagepng() 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 ignore-type  annotation

229
        imagepng(/** @scrutinizer ignore-type */ $thumb, "{$this->cachePath}/{$this->imageName}", $this->cacheSize[1]);
Loading history...
230
231
        imagedestroy($thumb);
0 ignored issues
show
Bug introduced by
It seems like $thumb can also be of type false; however, parameter $image of imagedestroy() 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 ignore-type  annotation

231
        imagedestroy(/** @scrutinizer ignore-type */ $thumb);
Loading history...
232
        imagedestroy($source);
233
234
        return "{$this->cachePath}/{$this->imageName}";
235
    }
236
    
237
    private function fromWebp(int $width, int $height, int $src_x, int $src_y, int $src_w, int $src_h): string
238
    {
239
        $thumb = imagecreatetruecolor($width, $height);
240
        $source = imagecreatefromwebp($this->imagePath);
241
242
        imagealphablending($thumb, false);
0 ignored issues
show
Bug introduced by
It seems like $thumb can also be of type false; however, parameter $image of imagealphablending() 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 ignore-type  annotation

242
        imagealphablending(/** @scrutinizer ignore-type */ $thumb, false);
Loading history...
243
        imagesavealpha($thumb, true);
0 ignored issues
show
Bug introduced by
It seems like $thumb can also be of type false; however, parameter $image of imagesavealpha() 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 ignore-type  annotation

243
        imagesavealpha(/** @scrutinizer ignore-type */ $thumb, true);
Loading history...
244
        imagecopyresized($thumb, $source, 0, 0, $src_x, $src_y, $width, $height, $src_w, $src_h);
0 ignored issues
show
Bug introduced by
It seems like $source can also be of type false; however, parameter $src_image of imagecopyresized() 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 ignore-type  annotation

244
        imagecopyresized($thumb, /** @scrutinizer ignore-type */ $source, 0, 0, $src_x, $src_y, $width, $height, $src_w, $src_h);
Loading history...
Bug introduced by
It seems like $thumb can also be of type false; however, parameter $dst_image of imagecopyresized() 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 ignore-type  annotation

244
        imagecopyresized(/** @scrutinizer ignore-type */ $thumb, $source, 0, 0, $src_x, $src_y, $width, $height, $src_w, $src_h);
Loading history...
245
        imagewebp($thumb, "{$this->cachePath}/{$this->imageName}", $this->cacheSize[1]);
0 ignored issues
show
Bug introduced by
It seems like $thumb can also be of type false; however, parameter $image of imagewebp() 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 ignore-type  annotation

245
        imagewebp(/** @scrutinizer ignore-type */ $thumb, "{$this->cachePath}/{$this->imageName}", $this->cacheSize[1]);
Loading history...
246
247
        imagedestroy($thumb);
0 ignored issues
show
Bug introduced by
It seems like $thumb can also be of type false; however, parameter $image of imagedestroy() 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 ignore-type  annotation

247
        imagedestroy(/** @scrutinizer ignore-type */ $thumb);
Loading history...
248
        imagedestroy($source);
249
250
        return "{$this->cachePath}/{$this->imageName}";
251
    }
252
}
253