Issues (195)

Security Analysis    not enabled

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.

Alpha/View/Widget/Image.php (2 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
namespace Alpha\View\Widget;
4
5
use Alpha\Util\Logging\Logger;
6
use Alpha\Util\Config\ConfigProvider;
7
use Alpha\Model\Type\Integer;
8
use Alpha\Model\Type\Enum;
9
use Alpha\Model\Type\Boolean;
10
use Alpha\Model\Type\Double;
11
use Alpha\Exception\IllegalArguementException;
12
use Alpha\Controller\Controller;
13
use Alpha\Controller\Front\FrontController;
14
15
/**
16
 * A widget that can generate an image which is scaled to the screen resolution of the
17
 * user, and can be made secured to prevent hot-linking from remote sites.  Note that by
18
 * default, a jpg file will be returned (the source file can be jpg, png, or gif).
19
 *
20
 * @since 1.0
21
 *
22
 * @author John Collins <[email protected]>
23
 * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
24
 * @copyright Copyright (c) 2019, John Collins (founder of Alpha Framework).
25
 * All rights reserved.
26
 *
27
 * <pre>
28
 * Redistribution and use in source and binary forms, with or
29
 * without modification, are permitted provided that the
30
 * following conditions are met:
31
 *
32
 * * Redistributions of source code must retain the above
33
 *   copyright notice, this list of conditions and the
34
 *   following disclaimer.
35
 * * Redistributions in binary form must reproduce the above
36
 *   copyright notice, this list of conditions and the
37
 *   following disclaimer in the documentation and/or other
38
 *   materials provided with the distribution.
39
 * * Neither the name of the Alpha Framework nor the names
40
 *   of its contributors may be used to endorse or promote
41
 *   products derived from this software without specific
42
 *   prior written permission.
43
 *
44
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
45
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
46
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
47
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
48
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
49
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
51
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
52
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
54
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
55
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
56
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57
 * </pre>
58
 */
59
class Image
60
{
61
    /**
62
     * The title of the image for alt text (optional).
63
     *
64
     * @var string
65
     *
66
     * @since 1.0
67
     */
68
    private $title;
69
70
    /**
71
     * The absolute path to the source image.
72
     *
73
     * @var string
74
     *
75
     * @since 1.0
76
     */
77
    private $source;
78
79
    /**
80
     * The width of the image (can differ from the source file when scale=true).
81
     *
82
     * @var \Alpha\Model\Type\Integer
83
     *
84
     * @since 1.0
85
     */
86
    private $width;
87
88
    /**
89
     * The height of the image (can differ from the source file when scale=true).
90
     *
91
     * @var \Alpha\Model\Type\Integer
92
     *
93
     * @since 1.0
94
     */
95
    private $height;
96
97
    /**
98
     * The file type of the source image (gif, jpg, or png supported).
99
     *
100
     * @var \Alpha\Model\Type\Enum
101
     *
102
     * @since 1.0
103
     */
104
    private $sourceType;
105
106
    /**
107
     * The quality of the jpg image generated (0.00 to 1.00, 0.75 by default).
108
     *
109
     * @var \Alpha\Model\Type\Double
110
     *
111
     * @since 1.0
112
     */
113
    private $quality;
114
115
    /**
116
     * Flag to determine if the image will scale to match the target resolution (false
117
     * by default).
118
     *
119
     * @var \Alpha\Model\Type\Boolean
120
     *
121
     * @since 1.0
122
     */
123
    private $scale;
124
125
    /**
126
     * Flag to determine if the link to the image will change every 24hrs, making hot-linking
127
     * to the image difficult (false by default).
128
     *
129
     * @var \Alpha\Model\Type\Boolean
130
     *
131
     * @since 1.0
132
     */
133
    private $secure;
134
135
    /**
136
     * The auto-generated name of the cache file for the image.
137
     *
138
     * @var string
139
     *
140
     * @since 1.0
141
     */
142
    private $filename;
143
144
    /**
145
     * Trace logger.
146
     *
147
     * @var \Alpha\Util\Logging\Logger
148
     *
149
     * @since 1.0
150
     */
151
    private static $logger = null;
152
153
    /**
154
     * The constructor.
155
     *
156
     * @param string $source
157
     * @param $width
158
     * @param $height
159
     * @param $sourceType
160
     * @param $quality
161
     * @param $scale
162
     *
163
     * @throws \Alpha\Exception\IllegalArguementException
164
     *
165
     * @since 1.0
166
     */
167
    public function __construct($source, $width, $height, $sourceType, $quality = 0.75, $scale = false, $secure = false)
168
    {
169
        self::$logger = new Logger('Image');
170
        self::$logger->debug('>>__construct(source=['.$source.'], width=['.$width.'], height=['.$height.'], sourceType=['.$sourceType.'], quality=['.$quality.'], scale=['.$scale.'], secure=['.$secure.'])');
171
172
        if (file_exists($source)) {
173
            $this->source = $source;
174
        } else {
175
            throw new IllegalArguementException('The source file for the Image widget ['.$source.'] cannot be found!');
176
        }
177
178
        $this->sourceType = new Enum();
179
        $this->sourceType->setOptions(array('jpg', 'png', 'gif'));
180
        $this->sourceType->setValue($sourceType);
181
182
        if ($quality < 0.0 || $quality > 1.0) {
183
            throw new IllegalArguementException('The quality setting of ['.$quality.'] is outside of the allowable range of 0.0 to 1.0');
184
        }
185
186
        $this->quality = new Double($quality);
187
        $this->scale = new Boolean($scale);
188
        $this->secure = new Boolean($secure);
189
190
        $this->width = new Integer($width);
191
        $this->height = new Integer($height);
192
193
        $this->setFilename();
194
195
        self::$logger->debug('<<__construct');
196
    }
197
198
    /**
199
     * Renders the HTML <img> tag to the ViewImage controller, with all of the correct params to render the source
200
     * image in the desired resolution.
201
     *
202
     * @param $altText Set this value to render alternate text as part of the HTML link (defaults to no alternate text)
203
     *
204
     * @return string
205
     *
206
     * @since 1.0
207
     */
208
    public function renderHTMLLink($altText = '')
209
    {
210
        $config = ConfigProvider::getInstance();
211
212
        $url = '';
0 ignored issues
show
$url is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
213
214
        if ($this->secure->getBooleanValue()) {
215
            $params = Controller::generateSecurityFields();
216
217
            $url = FrontController::generateSecureURL('act=Alpha\Controller\ImageController&source='.$this->source.'&width='.$this->width->getValue().'&height='.$this->height->getValue().'&type='.$this->sourceType->getValue().'&quality='.$this->quality->getValue().'&scale='.$this->scale->getValue().'&secure='.$this->secure->getValue().'&var1='.$params[0].'&var2='.$params[1]);
218
        } else {
219
            $url = FrontController::generateSecureURL('act=Alpha\Controller\ImageController&source='.$this->source.'&width='.$this->width->getValue().'&height='.$this->height->getValue().'&type='.$this->sourceType->getValue().'&quality='.$this->quality->getValue().'&scale='.$this->scale->getValue().'&secure='.$this->secure->getValue());
220
        }
221
222
        return '<img src="'.$url.'"'.(empty($altText) ? '' : ' alt="'.$altText.'"').($config->get('cms.images.widget.bootstrap.responsive') ? ' class="img-responsive"' : '').'/>';
223
    }
224
225
    /**
226
     * Setter for the filename, which also creates a sub-directory under /cache for images when required.
227
     *
228
     * @since 1.0
229
     *
230
     * @throws \Alpha\Exception\AlphaException
231
     */
232
    private function setFilename()
233
    {
234
        $config = ConfigProvider::getInstance();
235
236
        if (!strpos($this->source, 'attachments/article_')) {
237
            // checking to see if we will write a jpg or png to the cache
238
            if ($this->sourceType->getValue() == 'png' && $config->get('cms.images.perserve.png')) {
239
                $this->filename = $config->get('app.file.store.dir').'cache/images/'.basename($this->source, '.'.$this->sourceType->getValue()).'_'.$this->width->getValue().'x'.$this->height->getValue().'.png';
240
            } else {
241
                $this->filename = $config->get('app.file.store.dir').'cache/images/'.basename($this->source, '.'.$this->sourceType->getValue()).'_'.$this->width->getValue().'x'.$this->height->getValue().'.jpg';
242
            }
243
        } else {
244
            // make a cache dir for the article
245
            $cacheDir = $config->get('app.file.store.dir').'cache/images/article_'.mb_substr($this->source, mb_strpos($this->source, 'attachments/article_')+20, 11);
246
            if (!file_exists($cacheDir)) {
247
                $success = mkdir($cacheDir, 0777, true);
248
249
                if (!$success) {
250
                    throw new AlphaException('Unable to create the folder '.$cacheDir.' for the cache image, source file is '.$this->source);
251
                }
252
253
                if (!$success) {
254
                    throw new AlphaException('Unable to set write permissions on the folder ['.$cacheDir.'].');
255
                }
256
            }
257
258
            // now set the filename to include the new cache directory
259
            if ($this->sourceType->getValue() == 'png' && $config->get('cms.images.perserve.png')) {
260
                $this->filename = $cacheDir.'/'.basename($this->source, '.'.$this->sourceType->getValue()).'_'.$this->width->getValue().'x'.$this->height->getValue().'.png';
261
            } else {
262
                $this->filename = $cacheDir.'/'.basename($this->source, '.'.$this->sourceType->getValue()).'_'.$this->width->getValue().'x'.$this->height->getValue().'.jpg';
263
            }
264
        }
265
266
        self::$logger->debug('Image filename is ['.$this->filename.']');
267
    }
268
269
    /**
270
     * Gets the auto-generated filename for the image in the /cache directory.
271
     *
272
     * @since 1.0
273
     */
274
    public function getFilename()
275
    {
276
        return $this->filename;
277
    }
278
279
    /**
280
     * Renders the actual binary image using GD library calls.
281
     *
282
     * @since 1.0
283
     */
284
    public function renderImage()
285
    {
286
        $config = ConfigProvider::getInstance();
287
288
        // check the image cache first before we proceed
289
        if ($this->checkCache()) {
290
            $this->loadCache();
291
        } else {
292
            // now get the old image
293
            switch ($this->sourceType->getValue()) {
294
                case 'gif':
295
                    $oldImage = imagecreatefromgif($this->source);
296
                break;
297
                case 'jpg':
298
                    $oldImage = imagecreatefromjpeg($this->source);
299
                break;
300
                default:
301
                    $oldImage = imagecreatefrompng($this->source);
302
            }
303
304
            if (!$oldImage) {
305
                $im = imagecreatetruecolor($this->width->getValue(), $this->height->getValue());
306
                $bgc = imagecolorallocate($im, 255, 255, 255);
307
                $tc = imagecolorallocate($im, 0, 0, 0);
308
                imagefilledrectangle($im, 0, 0, $this->width->getValue(), $this->height->getValue(), $bgc);
309
310
                imagestring($im, 1, 5, 5, "Error loading $this->source", $tc);
311
                if ($this->sourceType->getValue() == 'png' && $config->get('cms.images.perserve.png')) {
312
                    imagepng($im);
313
                } else {
314
                    imagejpeg($im);
315
                }
316
                imagedestroy($im);
317
            } else {
318
                // the dimensions of the source image
319
                $oldWidth = imagesx($oldImage);
320
                $oldHeight = imagesy($oldImage);
321
322
                // now create the new image
323
                $newImage = imagecreatetruecolor($this->width->getValue(), $this->height->getValue());
324
325
                // set a transparent background for PNGs
326
                if ($this->sourceType->getValue() == 'png' && $config->get('cms.images.perserve.png')) {
327
                    // Turn off transparency blending (temporarily)
328
                    imagealphablending($newImage, false);
329
330
                    // Create a new transparent color for image
331
                    $color = imagecolorallocatealpha($newImage, 255, 0, 0, 0);
332
333
                    // Completely fill the background of the new image with allocated color.
334
                    imagefill($newImage, 0, 0, $color);
335
336
                    // Restore transparency blending
337
                    imagesavealpha($newImage, true);
338
                }
339
                // copy the old image to the new image (in memory, not the file!)
340
                imagecopyresampled($newImage, $oldImage, 0, 0, 0, 0, $this->width->getValue(), $this->height->getValue(), $oldWidth, $oldHeight);
341
342
                if ($this->sourceType->getValue() == 'png' && $config->get('cms.images.perserve.png')) {
343
                    imagepng($newImage);
344
                } else {
345
                    imagejpeg($newImage, null, 100*$this->quality->getValue());
346
                }
347
348
                $this->cache($newImage);
0 ignored issues
show
$newImage is of type resource, but the function expects a object<Alpha\View\Widget\Image>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
349
                imagedestroy($oldImage);
350
                imagedestroy($newImage);
351
            }
352
        }
353
    }
354
355
    /**
356
     * Caches the image to the cache directory.
357
     *
358
     * @param image $image the binary GD image stream to save
359
     *
360
     * @since 1.0
361
     */
362
    private function cache($image)
363
    {
364
        $config = ConfigProvider::getInstance();
365
366
        if ($this->sourceType->getValue() == 'png' && $config->get('cms.images.perserve.png')) {
367
            imagepng($image, $this->filename);
368
        } else {
369
            imagejpeg($image, $this->filename, 100*$this->quality->getValue());
370
        }
371
    }
372
373
    /**
374
     * Used to check the image cache for the image jpeg cache file.
375
     *
376
     * @return bool
377
     *
378
     * @since 1.0
379
     */
380
    private function checkCache()
381
    {
382
        return file_exists($this->filename);
383
    }
384
385
    /**
386
     * Method to load the content of the image cache file to the standard output stream (the browser).
387
     *
388
     * @since 1.0
389
     */
390
    private function loadCache()
391
    {
392
        readfile($this->filename);
393
    }
394
395
    /**
396
     * Converts a URL for an image to a relative file system path for the image, assuming it is
397
     * hosted on the same server as the application.
398
     *
399
     * @param string $imgURL
400
     *
401
     * @return string the path of the image
402
     *
403
     * @since 1.0
404
     */
405
    public static function convertImageURLToPath($imgURL)
406
    {
407
        $config = ConfigProvider::getInstance();
408
409
        $imgPath = str_replace($config->get('app.url').'/', '', $imgURL);
410
411
        return $imgPath;
412
    }
413
}
414