This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * Image behavior for ActiveRecord |
||
4 | * |
||
5 | * @link https://github.com/inblank/yii2-image |
||
6 | * @copyright Copyright (c) 2016 Pavel Aleksandrov <[email protected]> |
||
7 | * @license http://opensource.org/licenses/MIT |
||
8 | */ |
||
9 | |||
10 | namespace inblank\image; |
||
11 | |||
12 | use Imagine\Filter\Advanced\Canvas; |
||
13 | use Imagine\Filter\Transformation; |
||
14 | use Imagine\Image\Box; |
||
15 | use Imagine\Image\Color; |
||
16 | use Imagine\Image\ImageInterface; |
||
17 | use Imagine\Image\Point; |
||
18 | use yii; |
||
19 | use yii\base\Behavior; |
||
20 | use yii\db\ActiveRecord; |
||
21 | |||
22 | /** |
||
23 | * Image Behavior Class |
||
24 | * |
||
25 | * @property ActiveRecord $owner |
||
26 | * @property $imageDefaultUrl URL for default image |
||
27 | * @property $imageUrl image URL for model. If model not have image, will equal $imageDefaultUrl |
||
28 | * @property $imagePath path for image relative document root |
||
29 | * @property $imageAbsolutePath absolute path to image file in filesystem |
||
30 | * @property $imageFile full, with absolute path, image file name in filesystem |
||
31 | */ |
||
32 | class ImageBehavior extends Behavior |
||
33 | { |
||
34 | /** Just proportional resize image to fit size */ |
||
35 | const NONE = 0; |
||
36 | /** Crop image resize strategy */ |
||
37 | const CROP = 1; |
||
38 | /** Add frame image resize strategy */ |
||
39 | const FRAME = 2; |
||
40 | /** Transparent color */ |
||
41 | const COLOR_TRANSPARENT = null; |
||
42 | /** |
||
43 | * Name of attribute to store the image |
||
44 | * @var string |
||
45 | */ |
||
46 | public $imageAttribute = "image"; |
||
47 | /** |
||
48 | * Default image name |
||
49 | * @var string |
||
50 | */ |
||
51 | public $imageDefault = "image.png"; |
||
52 | /** |
||
53 | * Path to store image files. |
||
54 | * If empty will be init to /images/<ActiveRecord Class Name> |
||
55 | * @var string |
||
56 | */ |
||
57 | public $imagePath; |
||
58 | /** |
||
59 | * Size to convert image |
||
60 | * If array: [width, height]. |
||
61 | * If integer: use value for with and height. |
||
62 | * If not set: image save as is. |
||
63 | * @var integer|array |
||
64 | */ |
||
65 | public $imageSize; |
||
66 | /** |
||
67 | * Image resize strategy |
||
68 | * @var int |
||
69 | */ |
||
70 | public $imageResizeStrategy = self::NONE; |
||
71 | /** |
||
72 | * Image frame color |
||
73 | * @var |
||
74 | */ |
||
75 | public $imageFrameColor = "#FFF"; |
||
76 | /** |
||
77 | * Calculated absolute image path relative to webroot |
||
78 | * @var |
||
79 | */ |
||
80 | protected $_imageAbsolutePath; |
||
81 | |||
82 | /** |
||
83 | * @inheritdoc |
||
84 | */ |
||
85 | 3 | public function events() |
|
86 | { |
||
87 | return [ |
||
88 | 3 | ActiveRecord::EVENT_AFTER_INSERT => 'afterSave', |
|
89 | 3 | ActiveRecord::EVENT_AFTER_UPDATE => 'afterSave', |
|
90 | 3 | ActiveRecord::EVENT_AFTER_DELETE => 'afterDelete', |
|
91 | 3 | ActiveRecord::EVENT_BEFORE_UPDATE => 'beforeUpdate', |
|
92 | 3 | ]; |
|
93 | } |
||
94 | |||
95 | /** |
||
96 | * Before update action |
||
97 | */ |
||
98 | public function beforeUpdate() |
||
99 | { |
||
100 | // prevent save empty image name value and also for correct remove old image |
||
101 | $this->owner->setAttribute($this->imageAttribute, $this->owner->getOldAttribute($this->imageAttribute)); |
||
102 | } |
||
103 | |||
104 | /** |
||
105 | * After save action |
||
106 | */ |
||
107 | 2 | public function afterSave() |
|
108 | { |
||
109 | 2 | $this->imageChangeByUpload(); |
|
110 | 2 | } |
|
111 | |||
112 | /** |
||
113 | * After delete action |
||
114 | */ |
||
115 | 1 | public function afterDelete() |
|
116 | { |
||
117 | 1 | $this->imageRemoveFile(); |
|
118 | 1 | } |
|
119 | |||
120 | /** |
||
121 | * Get image path |
||
122 | * @return string |
||
123 | */ |
||
124 | 3 | public function getImagePath() |
|
125 | { |
||
126 | 3 | if ($this->imagePath === null) { |
|
127 | 3 | $this->imagePath = '/images/' . strtolower((new \ReflectionClass($this->owner))->getShortName()); |
|
128 | 3 | } |
|
129 | 3 | return $this->imagePath; |
|
130 | } |
||
131 | |||
132 | /** |
||
133 | * Get default image URL |
||
134 | * @return string |
||
135 | * @throws yii\base\InvalidConfigException |
||
136 | */ |
||
137 | public function getImageDefaultUrl() |
||
138 | { |
||
139 | return $this->_imageUrl($this->imageDefault); |
||
140 | } |
||
141 | |||
142 | /** |
||
143 | * Get absolute team image path in filesystem |
||
144 | * @return string |
||
145 | */ |
||
146 | 3 | public function getImageAbsolutePath() |
|
147 | { |
||
148 | 3 | if ($this->_imageAbsolutePath === null) { |
|
149 | 3 | $this->_imageAbsolutePath = Yii::getAlias('@webroot') . |
|
150 | 3 | '/' . (defined('IS_BACKEND') ? '../' : '') . |
|
151 | 3 | ltrim($this->getImagePath(), '/'); |
|
152 | 3 | if (!file_exists($this->_imageAbsolutePath)) { |
|
153 | yii\helpers\FileHelper::createDirectory($this->_imageAbsolutePath); |
||
154 | } |
||
155 | 3 | } |
|
156 | 3 | return $this->_imageAbsolutePath; |
|
157 | } |
||
158 | |||
159 | /** |
||
160 | * Check team image |
||
161 | * @return bool |
||
162 | * @throws yii\base\InvalidConfigException |
||
163 | */ |
||
164 | 3 | public function hasImage() |
|
165 | { |
||
166 | 3 | $image = $this->owner->getAttribute($this->imageAttribute); |
|
167 | 3 | return !empty($image) && $image != $this->imageDefault; |
|
168 | } |
||
169 | |||
170 | /** |
||
171 | * Check that image file exists |
||
172 | */ |
||
173 | public function imageFileExists() |
||
174 | { |
||
175 | return file_exists($this->getImageFile()); |
||
176 | } |
||
177 | |||
178 | /** |
||
179 | * Get team image URL |
||
180 | * @return string |
||
181 | * @throws yii\base\InvalidConfigException |
||
182 | */ |
||
183 | public function getImageUrl() |
||
184 | { |
||
185 | return !$this->hasImage() ? |
||
186 | $this->getImageDefaultUrl() : |
||
187 | $this->_imageUrl($this->owner->getAttribute($this->imageAttribute)); |
||
188 | } |
||
189 | |||
190 | /** |
||
191 | * Return filename in filesystem |
||
192 | * @return string |
||
193 | */ |
||
194 | 3 | public function getImageFile() |
|
195 | { |
||
196 | 3 | return $this->getImageAbsolutePath() . '/' . $this->owner->getAttribute($this->imageAttribute); |
|
197 | } |
||
198 | |||
199 | /** |
||
200 | * Change image by uploaded file |
||
201 | */ |
||
202 | 2 | public function imageChangeByUpload() |
|
0 ignored issues
–
show
imageChangeByUpload uses the super-global variable $_FILES which is generally not recommended.
Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable: // Bad
class Router
{
public function generate($path)
{
return $_SERVER['HOST'].$path;
}
}
// Better
class Router
{
private $host;
public function __construct($host)
{
$this->host = $host;
}
public function generate($path)
{
return $this->host.$path;
}
}
class Controller
{
public function myAction(Request $request)
{
// Instead of
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
// Better (assuming you use the Symfony2 request)
$page = $request->query->get('page', 1);
}
}
![]() |
|||
203 | { |
||
204 | 2 | $formName = $this->owner->formName(); |
|
205 | 2 | if (!empty($_POST[$formName][$this->imageAttribute]) && $_POST[$formName][$this->imageAttribute] == 'empty') { |
|
206 | // reset image |
||
207 | $this->imageReset(); |
||
208 | } else { |
||
209 | // upload new |
||
210 | 2 | if (!empty($_FILES[$formName]['tmp_name'][$this->imageAttribute])) { |
|
211 | $this->imageChange( |
||
212 | [$_FILES[$formName]['name'][$this->imageAttribute] => $_FILES[$formName]['tmp_name'][$this->imageAttribute]] |
||
213 | ); |
||
214 | } |
||
215 | } |
||
216 | 2 | } |
|
217 | |||
218 | /** |
||
219 | * Change image |
||
220 | * @param string|array $sourceFile source file. if set as array ['fileName' => 'file_in_filesystem'] |
||
221 | * @return bool true, if image was changed and old image file was deleted. false, if image not changed |
||
222 | * @throws yii\base\InvalidConfigException |
||
223 | */ |
||
224 | 3 | public function imageChange($sourceFile) |
|
225 | { |
||
226 | 3 | if (is_array($sourceFile)) { |
|
227 | $fileName = key($sourceFile); |
||
228 | $sourceFile = current($sourceFile); |
||
229 | } else { |
||
230 | 3 | $fileName = $sourceFile; |
|
231 | } |
||
232 | 3 | if (!file_exists($sourceFile)) { |
|
233 | 1 | return false; |
|
234 | } |
||
235 | 3 | $imageName = $this->imageAttribute . '_' . |
|
236 | 3 | md5(implode('-', (array)$this->owner->getPrimaryKey()) . microtime(true) . rand()) . |
|
237 | 3 | '.' . pathinfo($fileName)['extension']; |
|
238 | 3 | $destinationFile = $this->getImageAbsolutePath() . '/' . $imageName; |
|
239 | 3 | if (!copy($sourceFile, $destinationFile)) { |
|
240 | return false; |
||
241 | } |
||
242 | 3 | $this->imageRemoveFile(); |
|
243 | 3 | if (!empty($this->imageSize)) { |
|
244 | 1 | $size = $this->imageSize; |
|
245 | 1 | if (!is_array($size)) { |
|
246 | 1 | $size = [$size, $size]; |
|
247 | 1 | } |
|
248 | 1 | $newBox = new Box($size[0], $size[1]); |
|
249 | 1 | $image = (new Transformation())->thumbnail( |
|
250 | 1 | $newBox, |
|
251 | 1 | $this->imageResizeStrategy == self::CROP ? |
|
252 | 1 | ImageInterface::THUMBNAIL_OUTBOUND : ImageInterface::THUMBNAIL_INSET |
|
253 | 1 | )->apply(yii\imagine\Image::getImagine()->open($destinationFile)); |
|
254 | 1 | $currentBox = $image->getSize(); |
|
255 | 1 | if ($this->imageResizeStrategy === self::FRAME) { |
|
256 | if ($this->imageFrameColor === self::COLOR_TRANSPARENT) { |
||
257 | $frameColor = '#fff'; |
||
258 | $alpha = 100; |
||
259 | } else { |
||
260 | $frameColor = $this->imageFrameColor; |
||
261 | $alpha = 0; |
||
262 | } |
||
263 | $image = (new Transformation())->add( |
||
264 | new Canvas( |
||
265 | yii\imagine\Image::getImagine(), |
||
266 | $newBox, |
||
267 | $size[0] == $currentBox->getWidth() ? |
||
268 | new Point(0, ($size[1] - $currentBox->getHeight()) / 2) : |
||
269 | new Point(($size[0] - $currentBox->getWidth()) / 2, 0), |
||
270 | new Color($frameColor, $alpha) |
||
271 | ) |
||
272 | )->apply($image); |
||
273 | } |
||
274 | 1 | $image->save($destinationFile); |
|
275 | 1 | } |
|
276 | 3 | $this->owner->setAttribute($this->imageAttribute, $imageName); |
|
277 | 3 | $this->owner->updateAttributes([$this->imageAttribute]); |
|
278 | 3 | return true; |
|
279 | } |
||
280 | |||
281 | /** |
||
282 | * Reset image to default |
||
283 | * @throws yii\base\InvalidConfigException |
||
284 | */ |
||
285 | 1 | public function imageReset() |
|
286 | { |
||
287 | 1 | $this->imageRemoveFile(); |
|
288 | 1 | $this->owner->setAttribute($this->imageAttribute, null); |
|
289 | 1 | $this->owner->updateAttributes([$this->imageAttribute]); |
|
290 | 1 | } |
|
291 | |||
292 | /** |
||
293 | * Remove current image |
||
294 | * @throws yii\base\InvalidConfigException |
||
295 | */ |
||
296 | 3 | protected function imageRemoveFile() |
|
297 | { |
||
298 | 3 | if ($this->hasImage()) { |
|
299 | 2 | @unlink($this->getImageFile()); |
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
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.');
}
![]() |
|||
300 | 2 | } |
|
301 | 3 | } |
|
302 | |||
303 | /** |
||
304 | * Make image URL |
||
305 | * @param string $imageFileName image filename |
||
306 | * @return string |
||
307 | * @throws yii\base\InvalidConfigException |
||
308 | */ |
||
309 | protected function _imageUrl($imageFileName) |
||
310 | { |
||
311 | return $this->getImagePath() . '/' . $imageFileName; |
||
312 | } |
||
313 | |||
314 | } |
||
315 |
Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable: