[BUGFIX] Catch FileDoesNotExistException during persisting records
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Resource / Filter / FileExtensionFilter.php
1 <?php
2 namespace TYPO3\CMS\Core\Resource\Filter;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\DataHandling\DataHandler;
18 use TYPO3\CMS\Core\Resource\Driver\DriverInterface;
19 use TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException;
20 use TYPO3\CMS\Core\Resource\ResourceFactory;
21 use TYPO3\CMS\Core\Utility\GeneralUtility;
22 use TYPO3\CMS\Core\Utility\PathUtility;
23
24 /**
25 * Utility methods for filtering filenames
26 */
27 class FileExtensionFilter
28 {
29 /**
30 * Allowed file extensions. If NULL, all extensions are allowed.
31 *
32 * @var array
33 */
34 protected $allowedFileExtensions;
35
36 /**
37 * Disallowed file extensions. If NULL, no extension is disallowed (i.e. all are allowed).
38 *
39 * @var array
40 */
41 protected $disallowedFileExtensions;
42
43 /**
44 * Entry method for use as DataHandler "inline" field filter
45 *
46 * @param array $parameters
47 * @param DataHandler $dataHandler
48 * @return array
49 */
50 public function filterInlineChildren(array $parameters, DataHandler $dataHandler)
51 {
52 $values = $parameters['values'];
53 if ($parameters['allowedFileExtensions']) {
54 $this->setAllowedFileExtensions($parameters['allowedFileExtensions']);
55 }
56 if ($parameters['disallowedFileExtensions']) {
57 $this->setDisallowedFileExtensions($parameters['disallowedFileExtensions']);
58 }
59 $cleanValues = [];
60 if (is_array($values)) {
61 foreach ($values as $value) {
62 if (empty($value)) {
63 continue;
64 }
65 $parts = GeneralUtility::revExplode('_', $value, 2);
66 $fileReferenceUid = $parts[count($parts) - 1];
67 try {
68 $fileReference = ResourceFactory::getInstance()->getFileReferenceObject($fileReferenceUid);
69 $file = $fileReference->getOriginalFile();
70 if ($this->isAllowed($file->getExtension())) {
71 $cleanValues[] = $value;
72 } else {
73 // Remove the erroneously created reference record again
74 $dataHandler->deleteAction('sys_file_reference', $fileReferenceUid);
75 }
76 } catch (FileDoesNotExistException $e) {
77 // do nothing
78 }
79 }
80 }
81 return $cleanValues;
82 }
83
84 /**
85 * Entry method for use as filelist filter.
86 *
87 * We have to use -1 as the „don't include“ return value, as call_user_func() will return FALSE
88 * if calling the method failed and thus we can't use that as a return value.
89 *
90 * @param string $itemName
91 * @param string $itemIdentifier
92 * @param string $parentIdentifier
93 * @param array $additionalInformation Additional information about the inspected item
94 * @param DriverInterface $driver
95 * @return bool|int -1 if the file should not be included in a listing
96 */
97 public function filterFileList($itemName, $itemIdentifier, $parentIdentifier, array $additionalInformation, DriverInterface $driver)
98 {
99 $returnCode = true;
100 // Early return in case no file filters are set at all
101 if ($this->allowedFileExtensions === null && $this->disallowedFileExtensions === null) {
102 return $returnCode;
103 }
104 // Check that this is a file and not a folder
105 if ($driver->fileExists($itemIdentifier)) {
106 try {
107 $fileInfo = $driver->getFileInfoByIdentifier($itemIdentifier, ['extension']);
108 } catch (\InvalidArgumentException $e) {
109 $fileInfo = [];
110 }
111 if (!isset($fileInfo['extension'])) {
112 trigger_error('Guessing FAL file extensions has been deprecated in v9.3 and will be removed in v10. The FAL (' . get_class($driver) . ') driver method getFileInfoByIdentifier() should return the file extension', E_USER_DEPRECATED);
113 $fileInfo['extension'] = PathUtility::pathinfo($itemIdentifier, PATHINFO_EXTENSION);
114 }
115 if (!$this->isAllowed($fileInfo['extension'])) {
116 $returnCode = -1;
117 }
118 }
119 return $returnCode;
120 }
121
122 /**
123 * Checks whether a file is allowed according to the criteria defined in the class variables ($this->allowedFileExtensions etc.)
124 *
125 * @param string $fileExt
126 * @return bool
127 */
128 protected function isAllowed($fileExt)
129 {
130 $fileExt = strtolower($fileExt);
131 $result = true;
132 // Check allowed file extensions
133 if ($this->allowedFileExtensions !== null && !empty($this->allowedFileExtensions) && !in_array($fileExt, $this->allowedFileExtensions)) {
134 $result = false;
135 }
136 // Check disallowed file extensions
137 if ($this->disallowedFileExtensions !== null && !empty($this->disallowedFileExtensions) && in_array($fileExt, $this->disallowedFileExtensions)) {
138 $result = false;
139 }
140 return $result;
141 }
142
143 /**
144 * Set allowed file extensions
145 *
146 * @param mixed $allowedFileExtensions Comma-separated list or array, of allowed file extensions
147 */
148 public function setAllowedFileExtensions($allowedFileExtensions)
149 {
150 $this->allowedFileExtensions = $this->convertToLowercaseArray($allowedFileExtensions);
151 }
152
153 /**
154 * Set disallowed file extensions
155 *
156 * @param mixed $disallowedFileExtensions Comma-separated list or array, of allowed file extensions
157 */
158 public function setDisallowedFileExtensions($disallowedFileExtensions)
159 {
160 $this->disallowedFileExtensions = $this->convertToLowercaseArray($disallowedFileExtensions);
161 }
162
163 /**
164 * Converts mixed (string or array) input arguments into an array, NULL if empty.
165 *
166 * All array values will be converted to lower case.
167 *
168 * @param mixed $inputArgument Comma-separated list or array.
169 * @return array
170 */
171 protected function convertToLowercaseArray($inputArgument)
172 {
173 $returnValue = null;
174 if (is_array($inputArgument)) {
175 $returnValue = $inputArgument;
176 } elseif ((string)$inputArgument !== '') {
177 $returnValue = GeneralUtility::trimExplode(',', $inputArgument);
178 }
179
180 if (is_array($returnValue)) {
181 $returnValue = array_map('strtolower', $returnValue);
182 }
183
184 return $returnValue;
185 }
186 }