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 | namespace Kapersoft\FlysystemSharefile; |
||
4 | |||
5 | use Exception; |
||
6 | use League\Flysystem\Util; |
||
7 | use League\Flysystem\Config; |
||
8 | use Kapersoft\Sharefile\Client; |
||
9 | use League\Flysystem\Adapter\AbstractAdapter; |
||
10 | use League\Flysystem\Adapter\Polyfill\StreamedTrait; |
||
11 | use League\Flysystem\Adapter\Polyfill\NotSupportingVisibilityTrait; |
||
12 | |||
13 | /** |
||
14 | * Flysysten ShareFile Adapter. |
||
15 | * |
||
16 | * @author Jan Willem Kaper <[email protected]> |
||
17 | * @license MIT (see License.txt) |
||
18 | * |
||
19 | * @link http://github.com/kapersoft/flysystem-sharefile |
||
20 | */ |
||
21 | class SharefileAdapter extends AbstractAdapter |
||
22 | { |
||
23 | use StreamedTrait; |
||
24 | use NotSupportingVisibilityTrait; |
||
25 | |||
26 | /** ShareFile access control constants */ |
||
27 | const CAN_ADD_FOLDER = 'CanAddFolder'; |
||
28 | const ADD_NODE = 'CanAddNode'; |
||
29 | const CAN_VIEW = 'CanView'; |
||
30 | const CAN_DOWNLOAD = 'CanDownload'; |
||
31 | const CAN_UPLOAD = 'CanUpload'; |
||
32 | const CAN_SEND = 'CanSend'; |
||
33 | const CAN_DELETE_CURRENT_ITEM = 'CanDeleteCurrentItem'; |
||
34 | const CAN_DELETE_CHILD_ITEMS = 'CanDeleteChildItems'; |
||
35 | const CAN_MANAGE_PERMISSIONS = 'CanManagePermissions'; |
||
36 | const CAN_CREATEOFFICE_DOCUMENTS = 'CanCreateOfficeDocuments'; |
||
37 | |||
38 | /** |
||
39 | * ShareFile Client. |
||
40 | * |
||
41 | * @var \Kapersoft\Sharefile\Client; |
||
42 | * */ |
||
43 | protected $client; |
||
44 | |||
45 | /** |
||
46 | * Indicated if metadata should include the ShareFile item array. |
||
47 | * |
||
48 | * @var bool |
||
49 | * */ |
||
50 | protected $returnShareFileItem; |
||
51 | |||
52 | /** |
||
53 | * SharefileAdapter constructor. |
||
54 | * |
||
55 | * @param Client $client Instance of Kapersoft\Sharefile\Client |
||
56 | * @param string $prefix Folder prefix |
||
57 | * @param bool $returnShareFileItem Indicated if getMetadatsa/listContents should return ShareFile item array. |
||
58 | * |
||
59 | * @param string $prefix |
||
60 | */ |
||
61 | 723 | public function __construct(Client $client, string $prefix = '', bool $returnShareFileItem = false) |
|
62 | { |
||
63 | 723 | $this->client = $client; |
|
64 | |||
65 | 723 | $this->returnShareFileItem = $returnShareFileItem; |
|
66 | |||
67 | 723 | $this->setPathPrefix($prefix); |
|
68 | 723 | } |
|
69 | |||
70 | /** |
||
71 | * {@inheritdoc} |
||
72 | */ |
||
73 | 240 | public function has($path) |
|
74 | { |
||
75 | 240 | return $this->getMetadata($path); |
|
76 | } |
||
77 | |||
78 | /** |
||
79 | * {@inheritdoc} |
||
80 | */ |
||
81 | 60 | View Code Duplication | public function read($path) |
82 | { |
||
83 | 60 | if (!$item = $this->getItemByPath($path)) { |
|
84 | 30 | return false; |
|
85 | } |
||
86 | |||
87 | 30 | if (!$this->checkAccessControl($item, self::CAN_DOWNLOAD)) { |
|
88 | return false; |
||
89 | } |
||
90 | |||
91 | 30 | $contents = $this->client->getItemContents($item['Id']); |
|
92 | |||
93 | 30 | return $this->mapItemInfo($item, Util::dirname($path), $contents); |
|
94 | } |
||
95 | |||
96 | /** |
||
97 | * {@inheritdoc} |
||
98 | */ |
||
99 | 60 | public function listContents($directory = '', $recursive = false) |
|
100 | { |
||
101 | 60 | if (!$item = $this->getItemByPath($directory)) { |
|
102 | 30 | return false; |
|
0 ignored issues
–
show
|
|||
103 | } |
||
104 | |||
105 | 30 | return $this->buildItemList($item, $directory, $recursive); |
|
106 | } |
||
107 | |||
108 | /** |
||
109 | * {@inheritdoc} |
||
110 | */ |
||
111 | 540 | public function getMetadata($path) |
|
112 | { |
||
113 | 540 | if (!$item = $this->getItemByPath($path)) { |
|
114 | 180 | return false; |
|
115 | } |
||
116 | 360 | $metadata = $this->mapItemInfo($item, Util::dirname($path)); |
|
117 | |||
118 | 360 | if (in_array($path, ['/', ''], true)) { |
|
119 | $metadata['path'] = $path; |
||
120 | } |
||
121 | |||
122 | 360 | return $metadata; |
|
123 | } |
||
124 | |||
125 | /** |
||
126 | * {@inheritdoc} |
||
127 | */ |
||
128 | 60 | public function getSize($path) |
|
129 | { |
||
130 | 60 | return $this->getMetadata($path); |
|
131 | } |
||
132 | |||
133 | /** |
||
134 | * {@inheritdoc} |
||
135 | */ |
||
136 | public function getMimetype($path) |
||
137 | { |
||
138 | return $this->getMetadata($path); |
||
139 | } |
||
140 | |||
141 | /** |
||
142 | * {@inheritdoc} |
||
143 | */ |
||
144 | 60 | public function getTimestamp($path) |
|
145 | { |
||
146 | 60 | return $this->getmetaData($path); |
|
147 | } |
||
148 | |||
149 | /** |
||
150 | * {@inheritdoc} |
||
151 | */ |
||
152 | 150 | public function write($path, $contents, Config $config = null) |
|
153 | { |
||
154 | 150 | return $this->uploadFile($path, $contents, true); |
|
155 | } |
||
156 | |||
157 | /** |
||
158 | * {@inheritdoc} |
||
159 | */ |
||
160 | 150 | public function update($path, $contents, Config $config = null) |
|
161 | { |
||
162 | 150 | return $this->uploadFile($path, $contents, true); |
|
163 | } |
||
164 | |||
165 | /** |
||
166 | * {@inheritdoc} |
||
167 | */ |
||
168 | 180 | public function rename($path, $newpath) |
|
169 | { |
||
170 | 180 | if (!$targetFolderItem = $this->getItemByPath(Util::dirname($newpath))) { |
|
171 | 30 | return false; |
|
172 | } |
||
173 | |||
174 | 150 | if (!$this->checkAccessControl($targetFolderItem, self::CAN_UPLOAD)) { |
|
175 | 60 | return false; |
|
176 | } |
||
177 | |||
178 | 90 | if (!$item = $this->getItemByPath($path)) { |
|
179 | 30 | return false; |
|
180 | } |
||
181 | |||
182 | $data = [ |
||
183 | 60 | 'FileName' => basename($newpath), |
|
184 | 60 | 'Name' => basename($newpath), |
|
185 | 'Parent' => [ |
||
186 | 60 | 'Id' => $targetFolderItem['Id'], |
|
187 | ], |
||
188 | ]; |
||
189 | |||
190 | 60 | $this->client->updateItem($item['Id'], $data); |
|
191 | |||
192 | 60 | return is_array($this->has($newpath)); |
|
193 | } |
||
194 | |||
195 | /** |
||
196 | * {@inheritdoc} |
||
197 | */ |
||
198 | 180 | public function copy($path, $newpath) |
|
199 | { |
||
200 | 180 | if (!$targetFolderItem = $this->getItemByPath(Util::dirname($newpath))) { |
|
201 | 30 | return false; |
|
202 | } |
||
203 | |||
204 | 150 | if (!$this->checkAccessControl($targetFolderItem, self::CAN_UPLOAD)) { |
|
205 | 60 | return false; |
|
206 | } |
||
207 | |||
208 | 90 | if (!$item = $this->getItemByPath($path)) { |
|
209 | 30 | return false; |
|
210 | } |
||
211 | |||
212 | 60 | if (strcasecmp(Util::dirname($path), Util::dirname($newpath)) != 0 && |
|
213 | 60 | strcasecmp(basename($path), basename($newpath)) == 0) { |
|
214 | 30 | $this->client->copyItem($targetFolderItem['Id'], $item['Id'], true); |
|
215 | } else { |
||
216 | 30 | $contents = $this->client->getItemContents($item['Id']); |
|
217 | 30 | $this->uploadFile($newpath, $contents, true); |
|
218 | } |
||
219 | |||
220 | 60 | return is_array($this->has($newpath)); |
|
221 | } |
||
222 | |||
223 | /** |
||
224 | * {@inheritdoc} |
||
225 | */ |
||
226 | 60 | public function delete($path) |
|
227 | { |
||
228 | 60 | return $this->deleteDir($path); |
|
229 | } |
||
230 | |||
231 | /** |
||
232 | * {@inheritdoc} |
||
233 | */ |
||
234 | 60 | public function deleteDir($dirname) |
|
235 | { |
||
236 | 60 | if (!$item = $this->getItemByPath($dirname)) { |
|
237 | 30 | return false; |
|
238 | } |
||
239 | |||
240 | 30 | if (!$this->checkAccessControl($item, self::CAN_DELETE_CURRENT_ITEM)) { |
|
241 | return false; |
||
242 | } |
||
243 | |||
244 | 30 | $this->client->deleteItem($item['Id']); |
|
245 | |||
246 | 30 | return $this->has($dirname) === false; |
|
247 | } |
||
248 | |||
249 | /** |
||
250 | * {@inheritdoc} |
||
251 | */ |
||
252 | 120 | public function createDir($dirname, Config $config = null) |
|
253 | { |
||
254 | 120 | $parentFolder = Util::dirname($dirname); |
|
255 | 120 | $folder = basename($dirname); |
|
256 | |||
257 | 120 | if (!$parentFolderItem = $this->getItemByPath($parentFolder)) { |
|
258 | 30 | return false; |
|
259 | } |
||
260 | |||
261 | 90 | if (!$this->checkAccessControl($parentFolderItem, self::CAN_ADD_FOLDER)) { |
|
262 | 60 | return false; |
|
263 | } |
||
264 | |||
265 | 30 | $this->client->createFolder($parentFolderItem['Id'], $folder, $folder, true); |
|
266 | |||
267 | 30 | return $this->has($dirname); |
|
268 | } |
||
269 | |||
270 | /** |
||
271 | * {@inheritdoc} |
||
272 | */ |
||
273 | 120 | public function put($path, $contents) |
|
274 | { |
||
275 | 120 | return $this->uploadFile($path, $contents, true); |
|
276 | } |
||
277 | |||
278 | /** |
||
279 | * {@inheritdoc} |
||
280 | */ |
||
281 | 30 | View Code Duplication | public function readAndDelete($path) |
282 | { |
||
283 | 30 | if (!$item = $this->getItemByPath($path)) { |
|
284 | 30 | return false; |
|
285 | } |
||
286 | |||
287 | if (!$this->checkAccessControl($item, self::CAN_DOWNLOAD) || |
||
288 | !$this->checkAccessControl($item, self::CAN_DELETE_CURRENT_ITEM)) { |
||
289 | return false; |
||
290 | } |
||
291 | |||
292 | $itemContents = $this->client->getItemContents($item['Id']); |
||
293 | |||
294 | $this->delete($path); |
||
295 | |||
296 | return $itemContents; |
||
297 | } |
||
298 | |||
299 | /** |
||
300 | * Returns ShareFile client. |
||
301 | * |
||
302 | * @return Client |
||
303 | */ |
||
304 | 3 | public function getClient(): Client |
|
305 | { |
||
306 | 3 | return $this->client; |
|
307 | } |
||
308 | |||
309 | /** |
||
310 | * Upload a file to ShareFile. |
||
311 | * |
||
312 | * @param string $path File path |
||
313 | * @param string $contents Contents of the file |
||
314 | * @param bool $overwrite Overwrite file is it exists |
||
315 | * |
||
316 | * @return array|false |
||
317 | */ |
||
318 | 240 | protected function uploadFile(string $path, string $contents, bool $overwrite = false) |
|
319 | { |
||
320 | 240 | if (!$parentFolderItem = $this->getItemByPath(Util::dirname($path))) { |
|
321 | 30 | return false; |
|
322 | } |
||
323 | |||
324 | 210 | if (!$this->checkAccessControl($parentFolderItem, self::CAN_UPLOAD)) { |
|
325 | 60 | return false; |
|
326 | } |
||
327 | |||
328 | 150 | $filename = $this->prepareUploadFile(basename($path), $contents); |
|
329 | |||
330 | 150 | $this->client->uploadFileStandard($filename, $parentFolderItem['Id'], false, $overwrite); |
|
331 | |||
332 | 150 | $this->removeUploadFile($filename); |
|
333 | |||
334 | 150 | if ($metadata = $this->getMetadata($path)) { |
|
335 | 150 | $metadata['contents'] = $contents; |
|
336 | |||
337 | 150 | return $metadata; |
|
338 | } |
||
339 | |||
340 | return false; |
||
341 | } |
||
342 | |||
343 | /** |
||
344 | * Prepares upload-file. |
||
345 | * |
||
346 | * @param string $filename Filename |
||
347 | * @param string $contents Contents of the file |
||
348 | * |
||
349 | * @return string |
||
350 | */ |
||
351 | 150 | protected function prepareUploadFile(string $filename, string $contents):string |
|
352 | { |
||
353 | 150 | $filename = tempnam(sys_get_temp_dir(), '') . '/' . $filename; |
|
354 | 150 | unlink(Util::dirname($filename)); |
|
355 | 150 | mkdir(Util::dirname($filename)); |
|
356 | 150 | file_put_contents($filename, $contents); |
|
357 | |||
358 | 150 | return $filename; |
|
359 | } |
||
360 | |||
361 | /** |
||
362 | * Removes temporary directory and upload-file. |
||
363 | * |
||
364 | * @param string $filename Filename. |
||
365 | */ |
||
366 | 150 | protected function removeUploadFile(string $filename) |
|
367 | { |
||
368 | 150 | unlink($filename); |
|
369 | 150 | rmdir(Util::dirname($filename)); |
|
370 | 150 | } |
|
371 | |||
372 | /** |
||
373 | * Map ShareFile item to FlySystem metadata. |
||
374 | * |
||
375 | * @param array $item ShareFile item |
||
376 | * @param string $path Base path |
||
377 | * @param string|null $contents Contents of the file (optional) |
||
378 | * |
||
379 | * @return array |
||
380 | */ |
||
381 | 420 | protected function mapItemInfo(array $item, string $path = '', string $contents = null): array |
|
382 | { |
||
383 | 420 | $timestamp = $item['ClientModifiedDate'] ?? $item['ClientCreatedDate'] ?? |
|
384 | 420 | $item['CreationDate'] ?? $item['ProgenyEditDate'] ?? ''; |
|
385 | 420 | $timestamp = !empty($timestamp) ? strtotime($timestamp) : false; |
|
386 | |||
387 | 420 | if ($path == '.') { |
|
388 | $path = ''; |
||
389 | } |
||
390 | 420 | $path = trim($path . '/' . $item['FileName'], '/'); |
|
391 | |||
392 | 420 | if ($this->isShareFileApiModelsFile($item)) { |
|
393 | 420 | $mimetype = Util::guessMimeType($item['FileName'], $contents); |
|
394 | 420 | $type = 'file'; |
|
395 | } else { |
||
396 | 30 | $mimetype = 'inode/directory'; |
|
397 | 30 | $type = 'dir'; |
|
398 | } |
||
399 | |||
400 | 420 | return array_merge( |
|
401 | [ |
||
402 | 420 | 'timestamp' => $timestamp, |
|
403 | 420 | 'path' => $path, |
|
404 | 420 | 'mimetype' => $mimetype, |
|
405 | 420 | 'dirname' => pathinfo($path, PATHINFO_DIRNAME), |
|
406 | 420 | 'extension' => pathinfo($item['FileName'], PATHINFO_EXTENSION), |
|
407 | 420 | 'filename' => pathinfo($item['FileName'], PATHINFO_FILENAME), |
|
408 | 420 | 'basename' => pathinfo($item['FileName'], PATHINFO_FILENAME), |
|
409 | 420 | 'type' => $type, |
|
410 | 420 | 'size' => $item['FileSizeBytes'], |
|
411 | 420 | 'contents' => !empty($contents) ? $contents : false, |
|
412 | 'stream' => false, |
||
413 | ], |
||
414 | 420 | $this->returnShareFileItem ? ['sharefile_item' => $item] : [] |
|
415 | ); |
||
416 | } |
||
417 | |||
418 | /** |
||
419 | * Map list of ShareFile items with metadata. |
||
420 | * |
||
421 | * @param array $items List of ShareFile items |
||
422 | * @param string $path Base path |
||
423 | * |
||
424 | * @return array |
||
425 | */ |
||
426 | 30 | protected function mapItemList(array $items, string $path):array |
|
427 | { |
||
428 | 30 | return array_map( |
|
429 | 30 | function ($item) use ($path) { |
|
430 | 30 | return $this->mapItemInfo($item, $path); |
|
431 | 30 | }, |
|
432 | 30 | $items |
|
433 | ); |
||
434 | } |
||
435 | |||
436 | /** |
||
437 | * Build metadata list from ShareFile item. |
||
438 | * |
||
439 | * @param array $item ShareFile item |
||
440 | * @param string $path Path of the given ShareFile item |
||
441 | * @param bool $recursive Recursive mode |
||
442 | * |
||
443 | * @return array |
||
444 | */ |
||
445 | 30 | protected function buildItemList(array $item, string $path, bool $recursive = false):array |
|
446 | { |
||
447 | 30 | if ($this->isShareFileApiModelsFile($item)) { |
|
448 | 30 | return []; |
|
449 | } |
||
450 | |||
451 | 30 | $children = $this->client->getItemById($item['Id'], true); |
|
452 | |||
453 | 30 | if ($children['FileCount'] < 2 || !isset($children['Children'])) { |
|
454 | return []; |
||
455 | } |
||
456 | |||
457 | 30 | $children = $this->removeAllExceptFilesAndFolders($children['Children']); |
|
458 | |||
459 | 30 | $itemList = $this->mapItemList($children, $path); |
|
460 | |||
461 | 30 | if ($recursive) { |
|
462 | 30 | foreach ($children as $child) { |
|
463 | 30 | $path = $path . '/' . $child['FileName']; |
|
464 | |||
465 | 30 | $itemList = array_merge( |
|
466 | 30 | $itemList, |
|
467 | 30 | $this->buildItemList($child, $path, true) |
|
468 | ); |
||
469 | } |
||
470 | } |
||
471 | |||
472 | 30 | return $itemList; |
|
473 | } |
||
474 | |||
475 | /** |
||
476 | * Remove all items except files and folders in the given array of ShareFile items. |
||
477 | * |
||
478 | * @param array $items Array of ShareFile items |
||
479 | * |
||
480 | * @return array |
||
481 | */ |
||
482 | 30 | protected function removeAllExceptFilesAndFolders(array $items):array |
|
483 | { |
||
484 | 30 | return array_filter( |
|
485 | 30 | $items, |
|
486 | 30 | function ($item) { |
|
487 | 30 | return $this->isShareFileApiModelsFolder($item) || $this->isShareFileApiModelsFile($item); |
|
488 | 30 | } |
|
489 | ); |
||
490 | } |
||
491 | |||
492 | /** |
||
493 | * Check if ShareFile item is a ShareFile.Api.Models.Folder type. |
||
494 | * |
||
495 | * @param array $item |
||
496 | * |
||
497 | * @return bool |
||
498 | */ |
||
499 | 570 | protected function isShareFileApiModelsFolder(array $item):bool |
|
500 | { |
||
501 | 570 | return $item['odata.type'] == 'ShareFile.Api.Models.Folder'; |
|
502 | } |
||
503 | |||
504 | /** |
||
505 | * Check if ShareFile item is a ShareFile.Api.Models.File type. |
||
506 | * |
||
507 | * @param array $item |
||
508 | * |
||
509 | * @return bool |
||
510 | */ |
||
511 | 570 | protected function isShareFileApiModelsFile(array $item):bool |
|
512 | { |
||
513 | 570 | return $item['odata.type'] == 'ShareFile.Api.Models.File'; |
|
514 | } |
||
515 | |||
516 | /** |
||
517 | * Get ShareFile item using path. |
||
518 | * |
||
519 | * @param string $path Path of the requested file |
||
520 | * |
||
521 | * @return array|false |
||
522 | * |
||
523 | * @throws Exception |
||
524 | */ |
||
525 | 720 | protected function getItemByPath(string $path) |
|
526 | { |
||
527 | 720 | if ($path == '.') { |
|
528 | $path = ''; |
||
529 | } |
||
530 | 720 | $path = '/' . trim($this->applyPathPrefix($path), '/'); |
|
531 | |||
532 | try { |
||
533 | 720 | $item = $this->client->getItemByPath($path); |
|
534 | 570 | if ($this->isShareFileApiModelsFolder($item) || $this->isShareFileApiModelsFile($item)) { |
|
535 | 570 | return $item; |
|
536 | } |
||
537 | 240 | } catch (exception $e) { |
|
538 | 240 | return false; |
|
539 | } |
||
540 | |||
541 | return false; |
||
542 | } |
||
543 | |||
544 | /** |
||
545 | * Check access control of a ShareFile item. |
||
546 | * |
||
547 | * @param array $item ShareFile item |
||
548 | * @param string $rule Access rule |
||
549 | * |
||
550 | * @return bool |
||
551 | */ |
||
552 | 420 | protected function checkAccessControl(array $item, string $rule):bool |
|
553 | { |
||
554 | 420 | if ($this->isShareFileApiModelsFile($item)) { |
|
555 | 60 | $item = $this->client->getItemById($item['Parent']['Id']); |
|
556 | 60 | if ($rule == self::CAN_DELETE_CURRENT_ITEM) { |
|
557 | 30 | $rule = self::CAN_DELETE_CHILD_ITEMS; |
|
558 | } |
||
559 | } |
||
560 | |||
561 | 420 | if (isset($item['Info'][$rule])) { |
|
562 | 390 | return $item['Info'][$rule] == 1; |
|
563 | } else { |
||
564 | 30 | return false; |
|
565 | } |
||
566 | } |
||
567 | } |
||
568 |
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.