Issues (3099)

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.

Kunstmaan/MediaBundle/Helper/File/FileHandler.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 Kunstmaan\MediaBundle\Helper\File;
4
5
use Gaufrette\Filesystem;
6
use Kunstmaan\MediaBundle\Entity\Media;
7
use Kunstmaan\MediaBundle\Form\File\FileType;
8
use Kunstmaan\MediaBundle\Helper\ExtensionGuesserFactoryInterface;
9
use Kunstmaan\MediaBundle\Helper\Media\AbstractMediaHandler;
10
use Kunstmaan\MediaBundle\Helper\MimeTypeGuesserFactoryInterface;
11
use Kunstmaan\UtilitiesBundle\Helper\SlugifierInterface;
12
use Symfony\Component\HttpFoundation\File\File;
13
use Symfony\Component\HttpFoundation\File\MimeType\ExtensionGuesser;
14
use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser;
15
use Symfony\Component\HttpFoundation\File\UploadedFile;
16
use Symfony\Component\Mime\MimeTypesInterface;
17
18
/**
19
 * FileHandler
20
 */
21
class FileHandler extends AbstractMediaHandler
22
{
23
    /**
24
     * @var string
25
     */
26
    const TYPE = 'file';
27
28
    /**
29
     * @var string
30
     */
31
    public $mediaPath;
32
33
    /**
34
     * @var Filesystem
35
     */
36
    public $fileSystem;
37
38
    /**
39
     * @deprecated This property is deprecated since KunstmaanMediaBundle 5.7 and will be removed in KunstmaanMediaBundle 6.0. Use the `$mimeTypes` property instead.
40
     *
41
     * @var MimeTypeGuesser
42
     */
43
    public $mimeTypeGuesser;
44
45
    /**
46
     * @deprecated This property is deprecated since KunstmaanMediaBundle 5.7 and will be removed in KunstmaanMediaBundle 6.0. Use the `$mimeTypes` property instead.
47
     *
48
     * @var ExtensionGuesser
49
     */
50
    public $extensionGuesser;
51
52
    /** @var MimeTypesInterface */
53
    private $mimeTypes;
54
55
    /**
56
     * Files with a blacklisted extension will be converted to txt
57
     *
58
     * @var array
59
     */
60
    private $blacklistedExtensions = [];
61
62
    /**
63
     * @var SlugifierInterface
64
     */
65
    private $slugifier;
66
67
    /**
68
     * Constructor
69
     *
70
     * @param int                                                $priority
71
     * @param MimeTypeGuesserFactoryInterface|MimeTypesInterface $mimeTypes
72
     * @param ExtensionGuesserFactoryInterface                   $extensionGuesserFactoryInterface
73
     */
74 5
    public function __construct($priority, /*MimeTypesInterface*/ $mimeTypes, ExtensionGuesserFactoryInterface $extensionGuesserFactoryInterface = null)
75
    {
76 5
        parent::__construct($priority);
77
78
        // NEXT_MAJOR: remove type check and enable parameter typehint
79 5
        if (!$mimeTypes instanceof MimeTypesInterface && !$mimeTypes instanceof MimeTypeGuesserFactoryInterface) {
80
            throw new \InvalidArgumentException(sprintf('The "$mimeTypes" argument must implement the "%s" or "%s" interface', MimeTypesInterface::class, MimeTypeGuesserFactoryInterface::class));
81
        }
82
83 5
        if (null !== $extensionGuesserFactoryInterface) {
84
            @trigger_error(sprintf('Passing a value for "$extensionGuesserFactoryInterface" in "%s" is deprecated since KunstmaanMediaBundle 5.7 and this parameter will be removed in KunstmaanMediaBundle 6.0.', __METHOD__), E_USER_DEPRECATED);
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...
85
        }
86
87 5
        if ($mimeTypes instanceof MimeTypeGuesserFactoryInterface) {
88
            @trigger_error(sprintf('Passing an instance of "%s" for "$mimeTypes" in "%s" is deprecated since KunstmaanMediaBundle 5.7 and this parameter will be removed in KunstmaanMediaBundle 6.0. Inject the an instance of "%s" instead.', MimeTypeGuesserFactoryInterface::class, __METHOD__, MimeTypesInterface::class), E_USER_DEPRECATED);
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...
89
90
            $this->mimeTypeGuesser = $mimeTypes->get();
91
        } else {
92 5
            $this->mimeTypes = $mimeTypes;
93
        }
94
95 5
        if ($extensionGuesserFactoryInterface instanceof ExtensionGuesserFactoryInterface) {
96
            $this->extensionGuesser = $extensionGuesserFactoryInterface->get();
97
        }
98 5
    }
99
100
    /**
101
     * @param SlugifierInterface $slugifier
102
     */
103 1
    public function setSlugifier(SlugifierInterface $slugifier)
104
    {
105 1
        $this->slugifier = $slugifier;
106 1
    }
107
108
    /**
109
     * Inject the blacklisted
110
     *
111
     * @param array $blacklistedExtensions
112
     */
113
    public function setBlacklistedExtensions(array $blacklistedExtensions)
114
    {
115
        $this->blacklistedExtensions = $blacklistedExtensions;
116
    }
117
118
    /**
119
     * Inject the path used in media urls.
120
     *
121
     * @param string $mediaPath
122
     */
123
    public function setMediaPath($mediaPath)
124
    {
125
        $this->mediaPath = $mediaPath;
126
    }
127
128
    public function setFileSystem(Filesystem $fileSystem)
129
    {
130
        $this->fileSystem = $fileSystem;
131
    }
132
133
    /**
134
     * @return string
135
     */
136
    public function getName()
137
    {
138
        return 'File Handler';
139
    }
140
141
    /**
142
     * @return string
143
     */
144
    public function getType()
145
    {
146
        return FileHandler::TYPE;
147
    }
148
149
    /**
150
     * @return string
151
     */
152
    public function getFormType()
153
    {
154
        return FileType::class;
155
    }
156
157
    /**
158
     * @param mixed $object
159
     *
160
     * @return bool
161
     */
162 2
    public function canHandle($object)
163
    {
164 2
        if ($object instanceof File ||
165 2
            ($object instanceof Media &&
166 2
            (is_file($object->getContent()) || $object->getLocation() == 'local'))
167
        ) {
168 1
            return true;
169
        }
170
171 1
        return false;
172
    }
173
174
    /**
175
     * @param Media $media
176
     *
177
     * @return FileHelper
178
     */
179
    public function getFormHelper(Media $media)
180
    {
181
        return new FileHelper($media);
182
    }
183
184
    /**
185
     * @param Media $media
186
     *
187
     * @throws \RuntimeException when the file does not exist
188
     */
189 1
    public function prepareMedia(Media $media)
190
    {
191 1
        if (null === $media->getUuid()) {
192 1
            $uuid = uniqid();
193 1
            $media->setUuid($uuid);
194
        }
195
196 1
        $content = $media->getContent();
197 1
        if (empty($content)) {
198
            return;
199
        }
200
201 1
        if (!$content instanceof File) {
202
            if (!is_file($content)) {
203
                throw new \RuntimeException('Invalid file');
204
            }
205
206
            $file = new File($content);
207
            $media->setContent($file);
208
        }
209
210 1
        $contentType = $this->guessMimeType($content->getPathname());
211 1
        if ($content instanceof UploadedFile) {
212
            $pathInfo = pathinfo($content->getClientOriginalName());
213
214
            if (!\array_key_exists('extension', $pathInfo)) {
215
                $pathInfo['extension'] = $this->getExtensions($contentType);
216
            }
217
218
            $media->setOriginalFilename($this->slugifier->slugify($pathInfo['filename']).'.'.$pathInfo['extension']);
219
            $name = $media->getName();
220
221
            if (empty($name)) {
222
                $media->setName($media->getOriginalFilename());
223
            }
224
        }
225
226 1
        $media->setContentType($contentType);
227 1
        $media->setFileSize(filesize($media->getContent()));
228 1
        $media->setUrl($this->mediaPath.$this->getFilePath($media));
229 1
        $media->setLocation('local');
230 1
    }
231
232
    /**
233
     * @param Media $media
234
     */
235
    public function removeMedia(Media $media)
236
    {
237
        $adapter = $this->fileSystem->getAdapter();
238
239
        // Remove the file from filesystem
240
        $fileKey = $this->getFilePath($media);
241
        if ($adapter->exists($fileKey)) {
242
            $adapter->delete($fileKey);
243
        }
244
245
        // Remove the files containing folder if there's nothing left
246
        $folderPath = $this->getFileFolderPath($media);
247
        if ($adapter->exists($folderPath) && $adapter->isDirectory($folderPath) && !empty($folderPath)) {
248
            $allMyKeys = $adapter->keys();
249
            $everythingfromdir = preg_grep('/'.$folderPath, $allMyKeys);
250
251
            if (\count($everythingfromdir) === 1) {
252
                $adapter->delete($folderPath);
253
            }
254
        }
255
256
        $media->setRemovedFromFileSystem(true);
257
    }
258
259
    /**
260
     * {@inheritdoc}
261
     */
262
    public function updateMedia(Media $media)
263
    {
264
        $this->saveMedia($media);
265
    }
266
267
    /**
268
     * @param Media $media
269
     */
270
    public function saveMedia(Media $media)
271
    {
272
        if (!$media->getContent() instanceof File) {
273
            return;
274
        }
275
276
        $originalFile = $this->getOriginalFile($media);
277
        $originalFile->setContent(file_get_contents($media->getContent()->getRealPath()));
278
    }
279
280
    /**
281
     * @param Media $media
282
     *
283
     * @return \Gaufrette\File
284
     */
285
    public function getOriginalFile(Media $media)
286
    {
287
        return $this->fileSystem->get($this->getFilePath($media), true);
288
    }
289
290
    /**
291
     * @param mixed $data
292
     *
293
     * @return Media
294
     */
295
    public function createNew($data)
296
    {
297
        if ($data instanceof File) {
298
            /** @var $data File */
299
            $media = new Media();
300
            if (method_exists($data, 'getClientOriginalName')) {
301
                $media->setOriginalFilename($data->getClientOriginalName());
302
            } else {
303
                $media->setOriginalFilename($data->getFilename());
304
            }
305
            $media->setContent($data);
306
307
            $contentType = $this->guessMimeType($media->getContent()->getPathname());
308
            $media->setContentType($contentType);
309
310
            return $media;
311
        }
312
313
        return null;
314
    }
315
316
    /**
317
     * {@inheritdoc}
318
     */
319
    public function getShowTemplate(Media $media)
320
    {
321
        return '@KunstmaanMedia/Media/File/show.html.twig';
322
    }
323
324
    /**
325
     * @return array
326
     */
327
    public function getAddFolderActions()
328
    {
329
        return [
330
            FileHandler::TYPE => [
331
                'type' => FileHandler::TYPE,
332
                'name' => 'media.file.add',
333
            ],
334
        ];
335
    }
336
337
    /**
338
     * @param Media $media
339
     *
340
     * @return string
341
     */
342 1
    private function getFilePath(Media $media)
343
    {
344 1
        $filename = $media->getOriginalFilename();
345 1
        $filename = str_replace(['/', '\\', '%'], '', $filename);
346
347 1
        if (!empty($this->blacklistedExtensions)) {
348
            $filename = preg_replace('/\.('.implode('|', $this->blacklistedExtensions).')$/', '.txt', $filename);
349
        }
350
351 1
        $parts = pathinfo($filename);
352 1
        $filename = $this->slugifier->slugify($parts['filename']);
353 1
        if (\array_key_exists('extension', $parts)) {
354
            $filename .= '.'.strtolower($parts['extension']);
355
        }
356
357 1
        return sprintf(
358 1
            '%s/%s',
359 1
            $media->getUuid(),
360
            $filename
361
        );
362
    }
363
364
    /**
365
     * @param Media $media
366
     *
367
     * @return string
368
     */
369
    private function getFileFolderPath(Media $media)
370
    {
371
        return substr($this->getFilePath($media), 0, strrpos($this->getFilePath($media), $media->getOriginalFilename()));
372
    }
373
374 1
    private function guessMimeType($pathName)
375
    {
376
        // NEXT_MAJOR: remove method and inline guessMimeType call
377 1
        if ($this->mimeTypeGuesser instanceof MimeTypeGuesser) {
378
            return $this->mimeTypeGuesser->guess($pathName);
379
        }
380
381 1
        return $this->mimeTypes->guessMimeType($pathName);
382
    }
383
384 View Code Duplication
    private function getExtensions($mimeType)
385
    {
386
        // NEXT_MAJOR: remove method and inline getExtensions call
387
        if ($this->extensionGuesser instanceof ExtensionGuesser) {
388
            return $this->extensionGuesser->guess($mimeType);
389
        }
390
391
        return $this->mimeTypes->getExtensions($mimeType)[0] ?? '';
392
    }
393
}
394