Issues (3)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/ImageBehavior.php (3 issues)

Upgrade to new PHP Analysis Engine

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 $_POST 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);
    }
}
Loading history...
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);
    }
}
Loading history...
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
Security Best Practice introduced by
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.');
}
Loading history...
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