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 | * Upload Manager. |
||
4 | * |
||
5 | * This file contains upload manager. |
||
6 | * |
||
7 | * @author Martin Stolz <[email protected]> |
||
8 | */ |
||
9 | |||
10 | namespace herroffizier\yii2um; |
||
11 | |||
12 | use Yii; |
||
13 | use yii\base\Component; |
||
14 | use yii\base\InvalidParamException; |
||
15 | use yii\web\UploadedFile; |
||
16 | use yii\helpers\FileHelper; |
||
17 | |||
18 | class UploadManager extends Component |
||
19 | { |
||
20 | /** |
||
21 | * Throw exception when trying to overwrite existing file. |
||
22 | */ |
||
23 | const STRATEGY_KEEP = 0; |
||
24 | |||
25 | /** |
||
26 | * Overwrite existing file silently. |
||
27 | */ |
||
28 | const STRATEGY_OVERWRITE = 1; |
||
29 | |||
30 | /** |
||
31 | * Rename new file if file with same name exists. |
||
32 | */ |
||
33 | const STRATEGY_RENAME = 2; |
||
34 | |||
35 | /** |
||
36 | * Path to upload folder. |
||
37 | * |
||
38 | * @var string |
||
39 | */ |
||
40 | public $uploadDir = '@webroot/upload'; |
||
41 | |||
42 | /** |
||
43 | * URL to upload folder. |
||
44 | * |
||
45 | * @var string |
||
46 | */ |
||
47 | public $uploadUrl = '@web/upload'; |
||
48 | |||
49 | /** |
||
50 | * Generate partition name based on file name. |
||
51 | * |
||
52 | * @param string $name |
||
53 | * |
||
54 | * @return string |
||
55 | */ |
||
56 | 20 | protected function getPartitionName($name) |
|
57 | { |
||
58 | 20 | return substr(md5(mb_substr($name, 0, 2)), 0, 2); |
|
59 | } |
||
60 | |||
61 | /** |
||
62 | * Add partition folder to given path. |
||
63 | * |
||
64 | * @param string $path |
||
65 | * @param string $name |
||
66 | * |
||
67 | * @return string |
||
68 | */ |
||
69 | 20 | protected function getPartitionedPath($path, $name) |
|
70 | { |
||
71 | 20 | $subfolder = $this->getPartitionName($name); |
|
72 | 20 | $path = FileHelper::normalizePath($path).'/'.$subfolder; |
|
73 | |||
74 | 20 | return $path; |
|
75 | } |
||
76 | |||
77 | /** |
||
78 | * Get prefixed path. |
||
79 | * |
||
80 | * @param string $path |
||
81 | * @param string $prefix |
||
82 | * |
||
83 | * @return string |
||
84 | */ |
||
85 | 36 | protected function getPrefixedPath($path, $prefix) |
|
86 | { |
||
87 | 36 | if (substr($path, 0, 1) !== '/') { |
|
88 | 36 | $path = '/'.$path; |
|
89 | 27 | } |
|
90 | 36 | $path = FileHelper::normalizePath($path); |
|
91 | 36 | $prefixedPath = Yii::getAlias($prefix.$path); |
|
92 | |||
93 | 36 | return $prefixedPath; |
|
94 | } |
||
95 | |||
96 | /** |
||
97 | * Add index to file name. |
||
98 | * |
||
99 | * @param string $name |
||
100 | * @param int $index |
||
101 | * |
||
102 | * @return string |
||
103 | */ |
||
104 | 4 | protected function addIndexToName($name, $index) |
|
105 | { |
||
106 | 4 | $pathinfo = pathinfo($name); |
|
107 | |||
108 | 4 | if (empty($pathinfo['extension'])) { |
|
109 | 4 | return $pathinfo['basename'].'-'.$index; |
|
110 | } else { |
||
111 | 4 | return $pathinfo['filename'].'-'.$index.'.'.$pathinfo['extension']; |
|
112 | } |
||
113 | } |
||
114 | |||
115 | /** |
||
116 | * Pick up file name according to overwrite strategy and create path. |
||
117 | * |
||
118 | * @throws InvalidParamException when file cannot be created. |
||
119 | * |
||
120 | * @param string $path |
||
121 | * @param string $name |
||
122 | * @param int $overwriteStrategy |
||
123 | * |
||
124 | * @return string |
||
125 | */ |
||
126 | 16 | protected function createFilePath($path, $name, $overwriteStrategy) |
|
127 | { |
||
128 | 16 | $partitionedPath = $this->getPartitionedPath($path, $name); |
|
129 | 16 | $absolutePath = $this->getAbsolutePath($partitionedPath); |
|
130 | |||
131 | 16 | if (file_exists($absolutePath.'/'.$name)) { |
|
132 | switch ($overwriteStrategy) { |
||
133 | 4 | case self::STRATEGY_KEEP: |
|
134 | // File overwrtiting is forbidden. |
||
135 | 4 | throw new InvalidParamException('File '.$name.' already exists in '.$path.'.'); |
|
136 | |||
137 | 4 | case self::STRATEGY_RENAME: |
|
138 | 4 | $index = 0; |
|
139 | do { |
||
140 | 4 | ++$index; |
|
141 | 4 | $indexedName = $this->addIndexToName($name, $index); |
|
142 | |||
143 | 4 | $partitionedPath = $this->getPartitionedPath($path, $name); |
|
144 | 4 | $absolutePath = $this->getAbsolutePath($partitionedPath); |
|
145 | 4 | } while (file_exists($absolutePath.'/'.$indexedName)); |
|
146 | 4 | $name = $indexedName; |
|
147 | 4 | break; |
|
148 | |||
149 | 4 | case self::STRATEGY_OVERWRITE: |
|
150 | 4 | if (is_dir($absolutePath.'/'.$name)) { |
|
151 | // Cannot overwrtite folder. |
||
152 | 4 | throw new InvalidParamException($path.'/'.$name.' is a directory and cannot be overwritten.'); |
|
153 | } |
||
154 | 4 | break; |
|
155 | } |
||
156 | 3 | } |
|
157 | |||
158 | 16 | $this->createPath($partitionedPath); |
|
159 | |||
160 | 16 | return $partitionedPath.'/'.$name; |
|
161 | } |
||
162 | |||
163 | /** |
||
164 | * Get relative URL for relative path. |
||
165 | * |
||
166 | * @param string $path |
||
167 | * |
||
168 | * @return string |
||
169 | */ |
||
170 | 4 | public function getUrl($path) |
|
171 | { |
||
172 | 4 | return $this->getPrefixedPath($path, $this->uploadUrl); |
|
173 | } |
||
174 | |||
175 | /** |
||
176 | * Get absolute path for relative path. |
||
177 | * |
||
178 | * @param string $path |
||
179 | * |
||
180 | * @return string |
||
181 | */ |
||
182 | 32 | public function getAbsolutePath($path) |
|
183 | { |
||
184 | 32 | return $this->getPrefixedPath($path, $this->uploadDir); |
|
185 | } |
||
186 | |||
187 | /** |
||
188 | * Create given folder tree in upload folder. |
||
189 | * |
||
190 | * Returns absolute path of given path. |
||
191 | * |
||
192 | * @throws InvalidParamException when file cannot be created. |
||
193 | * |
||
194 | * @param string $path |
||
195 | * |
||
196 | * @return string |
||
197 | */ |
||
198 | 24 | public function createPath($path) |
|
199 | { |
||
200 | 24 | $absolutePath = $this->getAbsolutePath($path); |
|
201 | 24 | if (!file_exists($absolutePath)) { |
|
202 | // FIXME Check return value. |
||
203 | 24 | FileHelper::createDirectory($absolutePath); |
|
204 | 22 | } elseif (!is_dir($absolutePath)) { |
|
205 | 4 | throw new InvalidParamException($path.' is a file, cannot create folder with the same name.'); |
|
206 | } |
||
207 | |||
208 | 24 | return $absolutePath; |
|
209 | } |
||
210 | |||
211 | /** |
||
212 | * Create folder tree appended with partition folder in upload folder. |
||
213 | * |
||
214 | * Partition folder name depends on given file name. |
||
215 | * |
||
216 | * Returns absolute path of given path. |
||
217 | * |
||
218 | * @param string $path |
||
219 | * @param string $name |
||
220 | * |
||
221 | * @return string |
||
222 | */ |
||
223 | 4 | public function createPartitionedPath($path, $name) |
|
224 | { |
||
225 | 4 | $path = $this->getPartitionedPath($path, $name); |
|
226 | |||
227 | 4 | return $this->createPath($path); |
|
228 | } |
||
229 | |||
230 | /** |
||
231 | * Whether file with given relative path exists. |
||
232 | * |
||
233 | * @param string $filePath |
||
234 | * |
||
235 | * @return bool |
||
236 | */ |
||
237 | 4 | public function exists($filePath) |
|
238 | { |
||
239 | 4 | $absoluteFilePath = $this->getAbsolutePath($filePath); |
|
240 | |||
241 | 4 | return file_exists($absoluteFilePath); |
|
242 | } |
||
243 | |||
244 | /** |
||
245 | * Save data stored in $content as file to $path/$name in upload folder. |
||
246 | * |
||
247 | * Returns relative path with partition folder. |
||
248 | * |
||
249 | * @param string $path |
||
250 | * @param string $name |
||
251 | * @param string $content |
||
252 | * @param int[optional] $overwriteStrategy |
||
253 | * |
||
254 | * @return string |
||
255 | */ |
||
256 | 4 | View Code Duplication | public function saveContent($path, $name, $content, $overwriteStrategy = self::STRATEGY_KEEP) |
0 ignored issues
–
show
|
|||
257 | { |
||
258 | 4 | $filePath = $this->createFilePath($path, $name, $overwriteStrategy); |
|
259 | 4 | $absoluteFilePath = $this->getAbsolutePath($filePath); |
|
260 | |||
261 | 4 | file_put_contents($absoluteFilePath, $content); |
|
262 | 4 | unset($content); |
|
263 | |||
264 | 4 | return $filePath; |
|
265 | } |
||
266 | |||
267 | /** |
||
268 | * Save $upload file to $path in upload folder. |
||
269 | * |
||
270 | * Returns relative path with partition folder. |
||
271 | * |
||
272 | * @param string $path |
||
273 | * @param UploadedFile $upload |
||
274 | * @param int[optional] $overwriteStrategy |
||
275 | * |
||
276 | * @return string |
||
277 | */ |
||
278 | 4 | View Code Duplication | public function saveUpload($path, UploadedFile $upload, $overwriteStrategy = self::STRATEGY_KEEP) |
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
279 | { |
||
280 | 4 | $filePath = $this->createFilePath($path, $upload->name, $overwriteStrategy); |
|
281 | 4 | $absoluteFilePath = $this->getAbsolutePath($filePath); |
|
282 | |||
283 | 4 | $upload->saveAs($absoluteFilePath); |
|
284 | |||
285 | 4 | return $filePath; |
|
286 | } |
||
287 | |||
288 | /** |
||
289 | * Move or copy file. |
||
290 | * |
||
291 | * @param string $path |
||
292 | * @param string $absoluteFilePath |
||
293 | * @param int[optional] $overwriteStrategy |
||
294 | * @param string $function |
||
295 | * |
||
296 | * @return string |
||
297 | */ |
||
298 | 8 | View Code Duplication | protected function saveFileInternal($path, $absoluteFilePath, $overwriteStrategy, $function) |
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
299 | { |
||
300 | 8 | $filePath = $this->createFilePath($path, pathinfo($absoluteFilePath, PATHINFO_BASENAME), $overwriteStrategy); |
|
301 | 8 | $newAbsoluteFilePath = $this->getAbsolutePath($filePath); |
|
302 | |||
303 | 8 | $function($absoluteFilePath, $newAbsoluteFilePath); |
|
304 | |||
305 | 8 | return $filePath; |
|
306 | } |
||
307 | |||
308 | /** |
||
309 | * Save $absoluteFilePath file to $path in upload folder. |
||
310 | * |
||
311 | * Returns relative path with partition folder. |
||
312 | * |
||
313 | * @param string $path |
||
314 | * @param string $absoluteFilePath |
||
315 | * @param int[optional] $overwriteStrategy |
||
316 | * |
||
317 | * @return string |
||
318 | */ |
||
319 | 8 | public function saveFile($path, $absoluteFilePath, $overwriteStrategy = self::STRATEGY_KEEP) |
|
320 | { |
||
321 | 8 | return $this->saveFileInternal($path, $absoluteFilePath, $overwriteStrategy, 'copy'); |
|
322 | } |
||
323 | |||
324 | /** |
||
325 | * Move $absoluteFilePath file to $path in upload folder. |
||
326 | * |
||
327 | * Returns relative path with partition folder. |
||
328 | * |
||
329 | * @param string $path |
||
330 | * @param string $absoluteFilePath |
||
331 | * @param int[optional] $overwriteStrategy |
||
332 | * |
||
333 | * @return string |
||
334 | */ |
||
335 | 4 | public function moveFile($path, $absoluteFilePath, $overwriteStrategy = self::STRATEGY_KEEP) |
|
336 | { |
||
337 | 4 | return $this->saveFileInternal($path, $absoluteFilePath, $overwriteStrategy, 'rename'); |
|
338 | } |
||
339 | } |
||
340 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.