Total Complexity | 158 |
Total Lines | 1304 |
Duplicated Lines | 0 % |
Changes | 0 |
Complex classes like FilesBrowserModule often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use FilesBrowserModule, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
36 | class FilesBrowserModule extends FilesListModule { |
||
37 | public const LOG_CONTEXT = "FilesBrowserModule"; // Context for the Logger |
||
38 | |||
39 | /** |
||
40 | * Creates the notifiers for this module, |
||
41 | * and register them to the Bus. |
||
42 | */ |
||
43 | public function createNotifiers() { |
||
45 | } |
||
46 | |||
47 | /** |
||
48 | * Executes all the actions in the $data variable. |
||
49 | * Exception part is used for authentication errors also. |
||
50 | * |
||
51 | * @return bool true on success or false on failure |
||
52 | */ |
||
53 | #[Override] |
||
54 | public function execute() { |
||
55 | $result = false; |
||
56 | |||
57 | foreach ($this->data as $actionType => $actionData) { |
||
58 | if (isset($actionType)) { |
||
59 | try { |
||
60 | switch ($actionType) { |
||
61 | case "checkifexists": |
||
62 | $records = $actionData["records"]; |
||
63 | $destination = $actionData["destination"] ?? false; |
||
64 | $result = $this->checkIfExists($records, $destination); |
||
65 | $response = []; |
||
66 | $response['status'] = true; |
||
67 | $response['duplicate'] = $result; |
||
68 | $this->addActionData($actionType, $response); |
||
69 | $GLOBALS["bus"]->addData($this->getResponseData()); |
||
70 | break; |
||
71 | |||
72 | case "downloadtotmp": |
||
73 | $result = $this->downloadSelectedFilesToTmp($actionType, $actionData); |
||
74 | break; |
||
75 | |||
76 | case "createdir": |
||
77 | $this->save($actionData); |
||
78 | $result = true; |
||
79 | break; |
||
80 | |||
81 | case "rename": |
||
82 | $result = $this->rename($actionType, $actionData); |
||
83 | break; |
||
84 | |||
85 | case "uploadtobackend": |
||
86 | $result = $this->uploadToBackend($actionType, $actionData); |
||
87 | break; |
||
88 | |||
89 | case "save": |
||
90 | if ((isset($actionData["props"]["sharedid"]) || isset($actionData["props"]["isshared"])) && (!isset($actionData["props"]["deleted"]) || !isset($actionData["props"]["message_size"]))) { |
||
91 | // JUST IGNORE THIS REQUEST - we don't need to interact with the backend if a share was changed |
||
92 | $response['status'] = true; |
||
93 | $folder = []; |
||
94 | $folder[$actionData['entryid']] = [ |
||
95 | 'props' => $actionData["props"], |
||
96 | 'entryid' => $actionData['entryid'], |
||
97 | 'store_entryid' => 'files', |
||
98 | 'parent_entryid' => $actionData['parent_entryid'], |
||
99 | ]; |
||
100 | |||
101 | $response['item'] = array_values($folder); |
||
102 | $this->addActionData("update", $response); |
||
103 | $GLOBALS["bus"]->addData($this->getResponseData()); |
||
104 | |||
105 | break; |
||
106 | } |
||
107 | |||
108 | /* |
||
109 | * The "message_action" object has been set, check the action_type field for |
||
110 | * the exact action which must be taken. |
||
111 | * Supported actions: |
||
112 | * - move: move record to new folder |
||
113 | */ |
||
114 | if (isset($actionData["message_action"], $actionData["message_action"]["action_type"])) { |
||
115 | switch ($actionData["message_action"]["action_type"]) { |
||
116 | case "move" : |
||
117 | $result = $this->move($actionType, $actionData); |
||
118 | break; |
||
119 | |||
120 | default: |
||
121 | // check if we should create something new or edit an existing file/folder |
||
122 | if (isset($actionData["entryid"])) { |
||
123 | $result = $this->rename($actionType, $actionData); |
||
124 | } |
||
125 | else { |
||
126 | $result = $this->save($actionData); |
||
127 | } |
||
128 | break; |
||
129 | } |
||
130 | } |
||
131 | else { |
||
132 | // check if we should create something new or edit an existing file/folder |
||
133 | if (isset($actionData["entryid"])) { |
||
134 | $result = $this->rename($actionType, $actionData); |
||
135 | } |
||
136 | else { |
||
137 | $result = $this->save($actionData); |
||
138 | } |
||
139 | } |
||
140 | break; |
||
141 | |||
142 | case "delete": |
||
143 | $result = $this->delete($actionType, $actionData); |
||
144 | break; |
||
145 | |||
146 | case "list": |
||
147 | $result = $this->loadFiles($actionType, $actionData); |
||
148 | break; |
||
149 | |||
150 | case "loadsharingdetails": |
||
151 | $result = $this->getSharingInformation($actionType, $actionData); |
||
152 | break; |
||
153 | |||
154 | case "createnewshare": |
||
155 | $result = $this->createNewShare($actionType, $actionData); |
||
156 | break; |
||
157 | |||
158 | case "updateexistingshare": |
||
159 | $result = $this->updateExistingShare($actionType, $actionData); |
||
160 | break; |
||
161 | |||
162 | case "deleteexistingshare": |
||
163 | $result = $this->deleteExistingShare($actionType, $actionData); |
||
164 | break; |
||
165 | |||
166 | case "updatecache": |
||
167 | $result = $this->updateCache($actionType, $actionData); |
||
168 | break; |
||
169 | |||
170 | default: |
||
171 | $this->handleUnknownActionType($actionType); |
||
172 | } |
||
173 | } |
||
174 | catch (MAPIException $e) { |
||
175 | $this->sendFeedback(false, $this->errorDetailsFromException($e)); |
||
176 | } |
||
177 | catch (AccountException $e) { |
||
178 | $this->sendFeedback(false, [ |
||
179 | 'type' => ERROR_GENERAL, |
||
180 | 'info' => [ |
||
181 | 'title' => $e->getTitle(), |
||
182 | 'original_message' => $e->getMessage(), |
||
183 | 'display_message' => $e->getMessage(), |
||
184 | ], |
||
185 | ]); |
||
186 | } |
||
187 | catch (BackendException $e) { |
||
188 | $this->sendFeedback(false, [ |
||
189 | 'type' => ERROR_GENERAL, |
||
190 | 'info' => [ |
||
191 | 'title' => $e->getTitle(), |
||
192 | 'original_message' => $e->getMessage(), |
||
193 | 'display_message' => $e->getMessage(), |
||
194 | 'code' => $e->getCode(), |
||
195 | ], |
||
196 | ]); |
||
197 | } |
||
198 | } |
||
199 | } |
||
200 | |||
201 | return $result; |
||
202 | } |
||
203 | |||
204 | /** |
||
205 | * loads content of current folder - list of folders and files from Files. |
||
206 | * |
||
207 | * @param string $actionType name of the current action |
||
208 | * @param array $actionData all parameters contained in this request |
||
209 | * |
||
210 | * @return bool |
||
211 | * |
||
212 | * @throws BackendException if the backend request fails |
||
213 | */ |
||
214 | public function loadFiles($actionType, $actionData) { |
||
215 | $nodeId = $actionData['id']; |
||
216 | $onlyFiles = $actionData['only_files'] ?? false; |
||
217 | $response = []; |
||
218 | $nodes = []; |
||
219 | |||
220 | $accountID = $this->accountIDFromNode($nodeId); |
||
221 | |||
222 | // check if we are in the ROOT (#R#). If so, display some kind of device/account view. |
||
223 | if (empty($accountID) || !$this->accountStore->getAccount($accountID)) { |
||
224 | $accounts = $this->accountStore->getAllAccounts(); |
||
225 | foreach ($accounts as $account) { // we have to load all accounts and their folders |
||
226 | // skip accounts that are not valid |
||
227 | if ($account->getStatus() != Account::STATUS_OK) { |
||
228 | continue; |
||
229 | } |
||
230 | // build the real node id for this folder |
||
231 | $realNodeId = $nodeId . $account->getId() . "/"; |
||
232 | |||
233 | $nodes[$realNodeId] = ['props' => [ |
||
234 | 'id' => rawurldecode($realNodeId), |
||
235 | 'folder_id' => rawurldecode($realNodeId), |
||
236 | 'path' => $realNodeId, |
||
237 | 'filename' => $account->getName(), |
||
238 | 'message_size' => -1, |
||
239 | 'lastmodified' => -1, |
||
240 | 'message_class' => "IPM.Files", |
||
241 | 'type' => 0, |
||
242 | ], |
||
243 | 'entryid' => $this->createId($realNodeId), |
||
244 | 'store_entryid' => $this->createId($realNodeId), |
||
245 | 'parent_entryid' => $this->createId($realNodeId), |
||
246 | ]; |
||
247 | } |
||
248 | } |
||
249 | else { |
||
250 | $account = $this->accountStore->getAccount($accountID); |
||
251 | |||
252 | // initialize the backend |
||
253 | $initializedBackend = $this->initializeBackend($account, true); |
||
254 | |||
255 | $starttime = microtime(true); |
||
256 | $nodes = $this->getFolderContent($nodeId, $initializedBackend, $onlyFiles); |
||
257 | Logger::debug(self::LOG_CONTEXT, "[loadfiles]: getFolderContent took: " . (microtime(true) - $starttime) . " seconds"); |
||
258 | |||
259 | $nodes = $this->sortFolderContent($nodes, $actionData, false); |
||
260 | } |
||
261 | |||
262 | $response["item"] = array_values($nodes); |
||
263 | |||
264 | $response['page'] = ["start" => 0, "rowcount" => 50, "totalrowcount" => count($response["item"])]; |
||
265 | $response['folder'] = ["content_count" => count($response["item"]), "content_unread" => 0]; |
||
266 | |||
267 | $this->addActionData($actionType, $response); |
||
268 | $GLOBALS["bus"]->addData($this->getResponseData()); |
||
269 | |||
270 | return true; |
||
271 | } |
||
272 | |||
273 | /** |
||
274 | * Forms the structure needed for frontend |
||
275 | * for the list of folders and files. |
||
276 | * |
||
277 | * @param string $nodeId the name of the current root directory |
||
278 | * @param AbstractBackend $backendInstance |
||
279 | * @param bool $onlyFiles if true, get only files |
||
280 | * |
||
281 | * @return array of nodes for current path folder |
||
282 | * |
||
283 | * @throws BackendException if the backend request fails |
||
284 | */ |
||
285 | public function getFolderContent($nodeId, $backendInstance, $onlyFiles = false) { |
||
286 | $nodes = []; |
||
287 | |||
288 | // relative node ID. We need to trim off the #R# and account ID |
||
289 | $relNodeId = substr($nodeId, strpos($nodeId, '/')); |
||
290 | $nodeIdPrefix = substr($nodeId, 0, strpos($nodeId, '/')); |
||
291 | |||
292 | $accountID = $backendInstance->getAccountID(); |
||
293 | |||
294 | // remove the trailing slash for the cache key |
||
295 | $cachePath = rtrim($relNodeId, '/'); |
||
296 | if ($cachePath === "") { |
||
297 | $cachePath = "/"; |
||
298 | } |
||
299 | |||
300 | $dir = $this->getCache($accountID, $cachePath); |
||
301 | if (is_null($dir)) { |
||
302 | $dir = $backendInstance->ls($relNodeId); |
||
303 | $this->setCache($accountID, $cachePath, $dir); |
||
304 | } |
||
305 | |||
306 | // FIXME: There is something issue with getting sharing information from owncloud. |
||
307 | // check if backend supports sharing and load the information |
||
308 | if ($backendInstance->supports(BackendStore::FEATURE_SHARING)) { |
||
309 | Logger::debug(self::LOG_CONTEXT, "Checking for shared folders! ({$relNodeId})"); |
||
310 | |||
311 | $time_start = microtime(true); |
||
312 | |||
313 | /** @var iFeatureSharing $backendInstance */ |
||
314 | $sharingInfo = $backendInstance->getShares($relNodeId); |
||
315 | $time_end = microtime(true); |
||
316 | $time = $time_end - $time_start; |
||
317 | |||
318 | Logger::debug(self::LOG_CONTEXT, "Checking for shared took {$time} s!"); |
||
319 | } |
||
320 | |||
321 | if ($dir) { |
||
322 | $updateCache = false; |
||
323 | foreach ($dir as $id => $node) { |
||
324 | $type = FILES_FILE; |
||
325 | |||
326 | if (strcmp((string) $node['resourcetype'], "collection") == 0) { // we have a folder |
||
327 | $type = FILES_FOLDER; |
||
328 | } |
||
329 | |||
330 | if ($type === FILES_FOLDER && $onlyFiles) { |
||
331 | continue; |
||
332 | } |
||
333 | |||
334 | // Check if foldernames have a trailing slash, if not, add one! |
||
335 | if ($type === FILES_FOLDER && !StringUtil::endsWith($id, "/")) { |
||
336 | $id .= "/"; |
||
337 | } |
||
338 | |||
339 | $realID = $nodeIdPrefix . $id; |
||
340 | |||
341 | Logger::debug(self::LOG_CONTEXT, "parsing: " . $id . " in base: " . $nodeId); |
||
342 | |||
343 | $filename = stringToUTF8Encode(basename((string) $id)); |
||
344 | |||
345 | $size = $node['getcontentlength'] === null ? -1 : intval($node['getcontentlength']); |
||
346 | $size = $type == FILES_FOLDER ? -1 : $size; // folder's dont have a size |
||
347 | |||
348 | $fileid = $node['fileid'] === "-1" ? -1 : intval($node['fileid']); |
||
349 | |||
350 | $shared = false; |
||
351 | $sharedid = []; |
||
352 | if (isset($sharingInfo) && count($sharingInfo[$relNodeId]) > 0) { |
||
353 | foreach ($sharingInfo[$relNodeId] as $sid => $sdetails) { |
||
354 | if ($sdetails["path"] == rtrim((string) $id, "/")) { |
||
355 | $shared = true; |
||
356 | $sharedid[] = $sid; |
||
357 | } |
||
358 | } |
||
359 | } |
||
360 | |||
361 | $nodeId = stringToUTF8Encode($id); |
||
362 | $dirName = dirname($nodeId, 1); |
||
363 | if ($dirName === '/') { |
||
364 | $path = stringToUTF8Encode($nodeIdPrefix . $dirName); |
||
365 | } |
||
366 | else { |
||
367 | $path = stringToUTF8Encode($nodeIdPrefix . $dirName . '/'); |
||
368 | } |
||
369 | |||
370 | if (!isset($node['entryid']) || !isset($node['parent_entryid']) || !isset($node['store_entryid'])) { |
||
371 | $entryid = $this->createId($realID); |
||
372 | $parentEntryid = $this->createId($path); |
||
373 | $storeEntryid = $this->createId($nodeIdPrefix . '/'); |
||
374 | |||
375 | $dir[$id]['entryid'] = $entryid; |
||
376 | $dir[$id]['parent_entryid'] = $parentEntryid; |
||
377 | $dir[$id]['store_entryid'] = $storeEntryid; |
||
378 | |||
379 | $updateCache = true; |
||
380 | } |
||
381 | else { |
||
382 | $entryid = $node['entryid']; |
||
383 | $parentEntryid = $node['parent_entryid']; |
||
384 | $storeEntryid = $node['store_entryid']; |
||
385 | } |
||
386 | |||
387 | $nodes[$nodeId] = ['props' => [ |
||
388 | 'folder_id' => stringToUTF8Encode($realID), |
||
389 | 'fileid' => $fileid, |
||
390 | 'path' => $path, |
||
391 | 'filename' => $filename, |
||
392 | 'message_size' => $size, |
||
393 | 'lastmodified' => strtotime((string) $node['getlastmodified']) * 1000, |
||
394 | 'message_class' => "IPM.Files", |
||
395 | 'isshared' => $shared, |
||
396 | 'sharedid' => $sharedid, |
||
397 | 'object_type' => $type, |
||
398 | 'type' => $type, |
||
399 | ], |
||
400 | 'entryid' => $entryid, |
||
401 | 'parent_entryid' => $parentEntryid, |
||
402 | 'store_entryid' => $storeEntryid, |
||
403 | ]; |
||
404 | } |
||
405 | |||
406 | // Update the cache. |
||
407 | if ($updateCache) { |
||
408 | $this->setCache($accountID, $cachePath, $dir); |
||
409 | } |
||
410 | } |
||
411 | else { |
||
412 | Logger::debug(self::LOG_CONTEXT, "dir was empty"); |
||
413 | } |
||
414 | |||
415 | return $nodes; |
||
416 | } |
||
417 | |||
418 | /** |
||
419 | * This functions sorts an array of nodes. |
||
420 | * |
||
421 | * @param array $nodes array of nodes to sort |
||
422 | * @param array $data all parameters contained in the request |
||
423 | * @param bool $navtree parse for navtree or browser |
||
424 | * |
||
425 | * @return array of sorted nodes |
||
426 | */ |
||
427 | public function sortFolderContent($nodes, $data, $navtree = false) { |
||
428 | $sortednodes = []; |
||
429 | |||
430 | $sortkey = "filename"; |
||
431 | $sortdir = "ASC"; |
||
432 | |||
433 | if (isset($data['sort'])) { |
||
434 | $sortkey = $data['sort'][0]['field']; |
||
435 | $sortdir = $data['sort'][0]['direction']; |
||
436 | } |
||
437 | |||
438 | Logger::debug(self::LOG_CONTEXT, "sorting by " . $sortkey . " in direction: " . $sortdir); |
||
439 | |||
440 | if ($navtree) { |
||
441 | $sortednodes = ArrayUtil::sort_by_key($nodes, $sortkey, $sortdir); |
||
442 | } |
||
443 | else { |
||
444 | $sortednodes = ArrayUtil::sort_props_by_key($nodes, $sortkey, $sortdir); |
||
445 | } |
||
446 | |||
447 | return $sortednodes; |
||
448 | } |
||
449 | |||
450 | /** |
||
451 | * Deletes the selected files on the backend server. |
||
452 | * |
||
453 | * @param string $actionType name of the current action |
||
454 | * @param array $actionData all parameters contained in this request |
||
455 | * |
||
456 | * @return bool |
||
457 | * |
||
458 | * @throws BackendException if the backend request fails |
||
459 | */ |
||
460 | private function delete($actionType, $actionData) { |
||
461 | // TODO: function is duplicate of class.hierarchylistmodule.php of delete function. |
||
462 | $result = false; |
||
463 | if (isset($actionData['records']) && is_array($actionData['records'])) { |
||
464 | foreach ($actionData['records'] as $record) { |
||
465 | $nodeId = $record['folder_id']; |
||
466 | $relNodeId = substr((string) $nodeId, strpos((string) $nodeId, '/')); |
||
467 | |||
468 | $account = $this->accountFromNode($nodeId); |
||
469 | |||
470 | // initialize the backend |
||
471 | $initializedBackend = $this->initializeBackend($account); |
||
472 | |||
473 | $result = $initializedBackend->delete($relNodeId); |
||
474 | Logger::debug(self::LOG_CONTEXT, "deleted: " . $nodeId . ", worked: " . $result); |
||
475 | |||
476 | // clear the cache |
||
477 | $this->deleteCache($account->getId(), dirname($relNodeId)); |
||
478 | $GLOBALS["bus"]->notify(REQUEST_ENTRYID, OBJECT_DELETE, [ |
||
479 | "id" => $nodeId, |
||
480 | "folder_id" => $nodeId, |
||
481 | "entryid" => $record['entryid'], |
||
482 | "parent_entryid" => $record["parent_entryid"], |
||
483 | "store_entryid" => $record["store_entryid"], |
||
484 | ]); |
||
485 | } |
||
486 | |||
487 | $response['status'] = true; |
||
488 | $this->addActionData($actionType, $response); |
||
489 | $GLOBALS["bus"]->addData($this->getResponseData()); |
||
490 | } |
||
491 | else { |
||
492 | $nodeId = $actionData['folder_id']; |
||
493 | |||
494 | $relNodeId = substr((string) $nodeId, strpos((string) $nodeId, '/')); |
||
495 | $response = []; |
||
496 | |||
497 | $account = $this->accountFromNode($nodeId); |
||
498 | $accountId = $account->getId(); |
||
499 | // initialize the backend |
||
500 | $initializedBackend = $this->initializeBackend($account); |
||
501 | |||
502 | try { |
||
503 | $result = $initializedBackend->delete($relNodeId); |
||
504 | } |
||
505 | catch (BackendException) { |
||
506 | // TODO: this might fails because the file was already deleted. |
||
507 | // fire error message if any other error occurred. |
||
508 | Logger::debug(self::LOG_CONTEXT, "deleted a directory that was no longer available"); |
||
509 | } |
||
510 | Logger::debug(self::LOG_CONTEXT, "deleted: " . $nodeId . ", worked: " . $result); |
||
511 | |||
512 | // Get old cached data. |
||
513 | $cachedDir = $this->getCache($accountId, dirname($relNodeId)); |
||
514 | if (isset($cachedDir[$relNodeId]) && !empty($cachedDir[$relNodeId])) { |
||
515 | // Delete the folder from cached data. |
||
516 | unset($cachedDir[$relNodeId]); |
||
517 | } |
||
518 | |||
519 | // clear the cache of parent directory. |
||
520 | $this->deleteCache($accountId, dirname($relNodeId)); |
||
521 | // clear the cache of selected directory. |
||
522 | $this->deleteCache($accountId, rtrim($relNodeId, '/')); |
||
523 | |||
524 | // Set data in cache. |
||
525 | $this->setCache($accountId, dirname($relNodeId), $cachedDir); |
||
526 | |||
527 | $response['status'] = $result ? true : false; |
||
528 | $this->addActionData($actionType, $response); |
||
529 | $GLOBALS["bus"]->addData($this->getResponseData()); |
||
530 | |||
531 | $GLOBALS["bus"]->notify(REQUEST_ENTRYID, OBJECT_DELETE, [ |
||
532 | "entryid" => $actionData["entryid"], |
||
533 | "parent_entryid" => $actionData["parent_entryid"], |
||
534 | "store_entryid" => $actionData["store_entryid"], |
||
535 | ]); |
||
536 | } |
||
537 | |||
538 | return true; |
||
539 | } |
||
540 | |||
541 | /** |
||
542 | * Moves the selected files on the backend server. |
||
543 | * |
||
544 | * @param string $actionType name of the current action |
||
545 | * @param array $actionData all parameters contained in this request |
||
546 | * |
||
547 | * @return bool if the backend request failed |
||
548 | */ |
||
549 | private function move($actionType, $actionData) { |
||
550 | $dst = rtrim((string) $actionData['message_action']["destination_folder_id"], '/'); |
||
551 | |||
552 | $overwrite = $actionData['message_action']["overwrite"] ?? true; |
||
553 | $isFolder = $actionData['message_action']["isFolder"] ?? false; |
||
554 | |||
555 | $pathPostfix = ""; |
||
556 | if (str_ends_with((string) $actionData['folder_id'], '/')) { |
||
557 | $pathPostfix = "/"; // we have a folder... |
||
558 | } |
||
559 | |||
560 | $source = rtrim((string) $actionData['folder_id'], '/'); |
||
561 | $fileName = basename($source); |
||
562 | $destination = $dst . '/' . basename($source); |
||
563 | |||
564 | // get dst and source account ids |
||
565 | // currently only moving within one account is supported |
||
566 | $srcAccountID = substr((string) $actionData['folder_id'], 3, strpos((string) $actionData['folder_id'], '/') - 3); // parse account id from node id |
||
567 | $dstAccountID = substr((string) $actionData['message_action']["destination_folder_id"], 3, strpos((string) $actionData['message_action']["destination_folder_id"], '/') - 3); // parse account id from node id |
||
568 | |||
569 | if ($srcAccountID !== $dstAccountID) { |
||
570 | $this->sendFeedback(false, [ |
||
571 | 'type' => ERROR_GENERAL, |
||
572 | 'info' => [ |
||
573 | 'title' => _("Files Plugin"), |
||
574 | 'original_message' => _("Moving between accounts is not implemented"), |
||
575 | 'display_message' => _("Moving between accounts is not implemented"), |
||
576 | ], |
||
577 | ]); |
||
578 | |||
579 | return false; |
||
580 | } |
||
581 | $relDst = substr($destination, strpos($destination, '/')); |
||
582 | $relSrc = substr($source, strpos($source, '/')); |
||
583 | |||
584 | $account = $this->accountFromNode($source); |
||
585 | |||
586 | // initialize the backend |
||
587 | $initializedBackend = $this->initializeBackend($account); |
||
588 | |||
589 | $result = $initializedBackend->move($relSrc, $relDst, $overwrite); |
||
590 | |||
591 | $actionId = $account->getId(); |
||
592 | // clear the cache |
||
593 | $this->deleteCache($actionId, dirname($relDst)); |
||
594 | |||
595 | $cachedFolderName = $relSrc . $pathPostfix; |
||
596 | $this->deleteCache($actionId, $cachedFolderName); |
||
597 | |||
598 | $cached = $this->getCache($actionId, dirname($relSrc)); |
||
599 | $this->deleteCache($actionId, dirname($relSrc)); |
||
600 | |||
601 | if (isset($cached[$cachedFolderName]) && !empty($cached[$cachedFolderName])) { |
||
602 | unset($cached[$cachedFolderName]); |
||
603 | $this->setCache($actionId, dirname($relSrc), $cached); |
||
604 | } |
||
605 | |||
606 | $response['status'] = !$result ? false : true; |
||
607 | |||
608 | /* create the response object */ |
||
609 | $folder = [ |
||
610 | 'props' => [ |
||
611 | 'folder_id' => ($destination . $pathPostfix), |
||
612 | 'path' => $actionData['message_action']["destination_folder_id"], |
||
613 | 'filename' => $fileName, |
||
614 | 'display_name' => $fileName, |
||
615 | 'object_type' => $isFolder ? FILES_FOLDER : FILES_FILE, |
||
616 | 'deleted' => !$result ? false : true, |
||
617 | ], |
||
618 | 'entryid' => $this->createId($destination . $pathPostfix), |
||
619 | 'store_entryid' => $actionData['store_entryid'], |
||
620 | 'parent_entryid' => $actionData['message_action']['parent_entryid'], |
||
621 | ]; |
||
622 | |||
623 | $response['item'] = $folder; |
||
624 | |||
625 | $this->addActionData("update", $response); |
||
626 | $GLOBALS["bus"]->addData($this->getResponseData()); |
||
627 | |||
628 | // Notify hierarchy only when folder was moved. |
||
629 | if ($isFolder) { |
||
630 | // Send notification to delete folder node in hierarchy. |
||
631 | $GLOBALS["bus"]->notify(REQUEST_ENTRYID, OBJECT_DELETE, [ |
||
632 | "entryid" => $actionData["entryid"], |
||
633 | "parent_entryid" => $actionData["parent_entryid"], |
||
634 | "store_entryid" => $actionData["store_entryid"], |
||
635 | ]); |
||
636 | |||
637 | // Send notification to create new folder node in hierarchy. |
||
638 | $GLOBALS["bus"]->notify(REQUEST_ENTRYID, OBJECT_SAVE, $folder); |
||
639 | } |
||
640 | |||
641 | return true; |
||
642 | } |
||
643 | |||
644 | /** |
||
645 | * Renames the selected file on the backend server. |
||
646 | * |
||
647 | * @param string $actionType name of the current action |
||
648 | * @param array $actionData all parameters contained in this request |
||
649 | * |
||
650 | * @return bool |
||
651 | * |
||
652 | * @throws BackendException if the backend request fails |
||
653 | */ |
||
654 | public function rename($actionType, $actionData) { |
||
655 | $messageProps = $this->save($actionData); |
||
656 | $notifySubFolders = $actionData['message_action']['isFolder'] ?? true; |
||
657 | if (!empty($messageProps)) { |
||
658 | $GLOBALS["bus"]->notify(REQUEST_ENTRYID, OBJECT_SAVE, $messageProps); |
||
659 | if ($notifySubFolders) { |
||
660 | $this->notifySubFolders($messageProps["props"]["folder_id"]); |
||
661 | } |
||
662 | } |
||
663 | } |
||
664 | |||
665 | /** |
||
666 | * Check if given filename or folder already exists on server. |
||
667 | * |
||
668 | * @param array $records which needs to be check for existence |
||
669 | * @param array $destination where the given records needs to be moved, uploaded, or renamed |
||
670 | * |
||
671 | * @return bool True if duplicate found, false otherwise |
||
672 | * |
||
673 | * @throws BackendException if the backend request fails |
||
674 | */ |
||
675 | private function checkIfExists($records, $destination) { |
||
676 | $duplicate = false; |
||
677 | |||
678 | if (isset($records) && is_array($records)) { |
||
679 | if (!isset($destination) || $destination == false) { |
||
680 | $destination = reset($records); |
||
681 | $destination = $destination["id"]; // we can only check files in the same folder, so one request will be enough |
||
682 | Logger::debug(self::LOG_CONTEXT, "Resetting destination to check."); |
||
683 | } |
||
684 | Logger::debug(self::LOG_CONTEXT, "Checking: " . $destination); |
||
685 | $account = $this->accountFromNode($destination); |
||
686 | |||
687 | // initialize the backend |
||
688 | $initializedBackend = $this->initializeBackend($account); |
||
689 | |||
690 | $relDirname = substr((string) $destination, strpos((string) $destination, '/')); |
||
691 | Logger::debug(self::LOG_CONTEXT, "Getting content for: " . $relDirname); |
||
692 | |||
693 | try { |
||
694 | $lsdata = $initializedBackend->ls($relDirname); // we can only check files in the same folder, so one request will be enough |
||
695 | } |
||
696 | catch (Exception) { |
||
697 | // ignore - if file not found -> does not exist :) |
||
698 | } |
||
699 | if (isset($lsdata) && is_array($lsdata)) { |
||
700 | foreach ($records as $record) { |
||
701 | $relRecId = substr((string) $record["id"], strpos((string) $record["id"], '/')); |
||
702 | Logger::debug(self::LOG_CONTEXT, "Checking rec: " . $relRecId); |
||
703 | foreach ($lsdata as $argsid => $args) { |
||
704 | if (strcmp((string) $args['resourcetype'], "collection") == 0 && $record["isFolder"] && strcmp(basename($argsid), basename($relRecId)) == 0) { // we have a folder |
||
705 | Logger::debug(self::LOG_CONTEXT, "Duplicate folder found: " . $argsid); |
||
706 | $duplicate = true; |
||
707 | break; |
||
708 | } |
||
709 | if (strcmp((string) $args['resourcetype'], "collection") != 0 && !$record["isFolder"] && strcmp(basename($argsid), basename($relRecId)) == 0) { |
||
710 | Logger::debug(self::LOG_CONTEXT, "Duplicate file found: " . $argsid); |
||
711 | $duplicate = true; |
||
712 | break; |
||
713 | } |
||
714 | $duplicate = false; |
||
715 | } |
||
716 | |||
717 | if ($duplicate) { |
||
718 | Logger::debug(self::LOG_CONTEXT, "Duplicate entry: " . $relRecId); |
||
719 | break; |
||
720 | } |
||
721 | } |
||
722 | } |
||
723 | } |
||
724 | |||
725 | return $duplicate; |
||
726 | } |
||
727 | |||
728 | /** |
||
729 | * Downloads file from the Files service and saves it in tmp |
||
730 | * folder with unique name. |
||
731 | * |
||
732 | * @param array $actionData |
||
733 | * @param mixed $actionType |
||
734 | * |
||
735 | * @throws BackendException if the backend request fails |
||
736 | */ |
||
737 | private function downloadSelectedFilesToTmp($actionType, $actionData) { |
||
738 | $ids = $actionData['ids']; |
||
739 | $dialogAttachmentId = $actionData['dialog_attachments']; |
||
740 | $response = []; |
||
741 | |||
742 | $attachment_state = new AttachmentState(); |
||
743 | $attachment_state->open(); |
||
744 | |||
745 | $account = $this->accountFromNode($ids[0]); |
||
746 | |||
747 | // initialize the backend |
||
748 | $initializedBackend = $this->initializeBackend($account); |
||
749 | |||
750 | foreach ($ids as $file) { |
||
751 | $filename = basename((string) $file); |
||
752 | $tmpname = $attachment_state->getAttachmentTmpPath($filename); |
||
753 | |||
754 | // download file from the backend |
||
755 | $relRecId = substr((string) $file, strpos((string) $file, '/')); |
||
756 | $http_status = $initializedBackend->get_file($relRecId, $tmpname); |
||
757 | |||
758 | $filesize = filesize($tmpname); |
||
759 | |||
760 | Logger::debug(self::LOG_CONTEXT, "Downloading: " . $filename . " to: " . $tmpname); |
||
761 | |||
762 | $attach_id = uniqid(); |
||
763 | $response['items'][] = [ |
||
764 | 'name' => $filename, |
||
765 | 'size' => $filesize, |
||
766 | "attach_id" => $attach_id, |
||
767 | 'tmpname' => PathUtil::getFilenameFromPath($tmpname), |
||
768 | ]; |
||
769 | |||
770 | $attachment_state->addAttachmentFile($dialogAttachmentId, PathUtil::getFilenameFromPath($tmpname), [ |
||
771 | "name" => $filename, |
||
772 | "size" => $filesize, |
||
773 | "type" => PathUtil::get_mime($tmpname), |
||
774 | "attach_id" => $attach_id, |
||
775 | "sourcetype" => 'default', |
||
776 | ]); |
||
777 | |||
778 | Logger::debug(self::LOG_CONTEXT, "filesize: " . $filesize); |
||
779 | } |
||
780 | |||
781 | $attachment_state->close(); |
||
782 | $response['status'] = true; |
||
783 | $this->addActionData($actionType, $response); |
||
784 | $GLOBALS["bus"]->addData($this->getResponseData()); |
||
785 | } |
||
786 | |||
787 | /** |
||
788 | * upload the tempfile to files. |
||
789 | * |
||
790 | * @param array $actionData |
||
791 | * @param mixed $actionType |
||
792 | * |
||
793 | * @throws BackendException if the backend request fails |
||
794 | */ |
||
795 | private function uploadToBackend($actionType, $actionData) { |
||
796 | Logger::debug(self::LOG_CONTEXT, "preparing attachment"); |
||
797 | |||
798 | $account = $this->accountFromNode($actionData["destdir"]); |
||
799 | |||
800 | // initialize the backend |
||
801 | $initializedBackend = $this->initializeBackend($account); |
||
802 | |||
803 | $result = true; |
||
804 | |||
805 | if ($actionData["type"] === "attachment") { |
||
806 | foreach ($actionData["items"] as $item) { |
||
807 | [$tmpname, $filename] = $this->prepareAttachmentForUpload($item); |
||
808 | |||
809 | $dirName = substr((string) $actionData["destdir"], strpos((string) $actionData["destdir"], '/')); |
||
810 | $filePath = $dirName . $filename; |
||
811 | |||
812 | Logger::debug(self::LOG_CONTEXT, "Uploading to: " . $filePath . " tmpfile: " . $tmpname); |
||
813 | |||
814 | $result = $result && $initializedBackend->put_file($filePath, $tmpname); |
||
815 | unlink($tmpname); |
||
816 | |||
817 | $this->updateDirCache($initializedBackend, $dirName, $filePath, $actionData); |
||
818 | } |
||
819 | } |
||
820 | elseif ($actionData["type"] === "mail") { |
||
821 | foreach ($actionData["items"] as $item) { |
||
822 | [$tmpname, $filename] = $this->prepareEmailForUpload($item); |
||
823 | |||
824 | $dirName = substr((string) $actionData["destdir"], strpos((string) $actionData["destdir"], '/')); |
||
825 | $filePath = $dirName . $filename; |
||
826 | |||
827 | Logger::debug(self::LOG_CONTEXT, "Uploading to: " . $filePath . " tmpfile: " . $tmpname); |
||
828 | |||
829 | $result = $result && $initializedBackend->put_file($filePath, $tmpname); |
||
830 | unlink($tmpname); |
||
831 | |||
832 | $this->updateDirCache($initializedBackend, $dirName, $filePath, $actionData); |
||
833 | } |
||
834 | } |
||
835 | else { |
||
836 | $this->sendFeedback(false, [ |
||
837 | 'type' => ERROR_GENERAL, |
||
838 | 'info' => [ |
||
839 | 'title' => _("Files plugin"), |
||
840 | 'original_message' => _("Unknown type - cannot save this file to the Files backend!"), |
||
841 | 'display_message' => _("Unknown type - cannot save this file to the Files backend!"), |
||
842 | ], |
||
843 | ]); |
||
844 | } |
||
845 | |||
846 | $response = []; |
||
847 | $response['status'] = $result; |
||
848 | $this->addActionData($actionType, $response); |
||
849 | $GLOBALS["bus"]->addData($this->getResponseData()); |
||
850 | } |
||
851 | |||
852 | /** |
||
853 | * Update the cache of selected directory. |
||
854 | * |
||
855 | * @param AbstractBackend $backendInstance |
||
856 | * @param string $dirName The directory name |
||
857 | * @param $filePath The file path |
||
858 | * @param $actionData The action data |
||
859 | * |
||
860 | * @throws BackendException |
||
861 | */ |
||
862 | public function updateDirCache($backendInstance, $dirName, $filePath, $actionData) { |
||
863 | $cachePath = rtrim($dirName, '/'); |
||
864 | if ($cachePath === "") { |
||
865 | $cachePath = "/"; |
||
866 | } |
||
867 | |||
868 | $dir = $backendInstance->ls($cachePath); |
||
869 | $accountID = $this->accountIDFromNode($actionData["destdir"]); |
||
870 | $cacheDir = $this->getCache($accountID, $cachePath); |
||
871 | $cacheDir[$filePath] = $dir[$filePath]; |
||
872 | $this->setCache($accountID, $cachePath, $cacheDir); |
||
873 | } |
||
874 | |||
875 | /** |
||
876 | * This function will prepare an attachment for the upload to the backend. |
||
877 | * It will store the attachment to the TMP folder and return its temporary |
||
878 | * path and filename as array. |
||
879 | * |
||
880 | * @param mixed $item |
||
881 | * |
||
882 | * @return array (tmpname, filename) or false on error |
||
883 | */ |
||
884 | private function prepareAttachmentForUpload($item) { |
||
885 | // Check which type isset |
||
886 | $openType = "attachment"; |
||
887 | |||
888 | // Get store id |
||
889 | $storeid = false; |
||
890 | if (isset($item["store"])) { |
||
891 | $storeid = $item["store"]; |
||
892 | } |
||
893 | |||
894 | // Get message entryid |
||
895 | $entryid = false; |
||
896 | if (isset($item["entryid"])) { |
||
897 | $entryid = $item["entryid"]; |
||
898 | } |
||
899 | |||
900 | // Get number of attachment which should be opened. |
||
901 | $attachNum = false; |
||
902 | if (isset($item["attachNum"])) { |
||
903 | $attachNum = $item["attachNum"]; |
||
904 | } |
||
905 | |||
906 | $tmpname = ""; |
||
907 | $filename = ""; |
||
908 | |||
909 | // Check if storeid and entryid isset |
||
910 | if ($storeid && $entryid) { |
||
911 | // Open the store |
||
912 | $store = $GLOBALS["mapisession"]->openMessageStore(hex2bin((string) $storeid)); |
||
913 | |||
914 | if ($store) { |
||
915 | // Open the message |
||
916 | $message = mapi_msgstore_openentry($store, hex2bin((string) $entryid)); |
||
917 | |||
918 | if ($message) { |
||
919 | $attachment = false; |
||
920 | |||
921 | // Check if attachNum isset |
||
922 | if ($attachNum) { |
||
923 | // Loop through the attachNums, message in message in message ... |
||
924 | for ($i = 0; $i < (count($attachNum) - 1); ++$i) { |
||
925 | // Open the attachment |
||
926 | $tempattach = mapi_message_openattach($message, (int) $attachNum[$i]); |
||
927 | if ($tempattach) { |
||
928 | // Open the object in the attachment |
||
929 | $message = mapi_attach_openobj($tempattach); |
||
930 | } |
||
931 | } |
||
932 | |||
933 | // Open the attachment |
||
934 | $attachment = mapi_message_openattach($message, (int) $attachNum[count($attachNum) - 1]); |
||
935 | } |
||
936 | |||
937 | // Check if the attachment is opened |
||
938 | if ($attachment) { |
||
939 | // Get the props of the attachment |
||
940 | $props = mapi_attach_getprops($attachment, [PR_ATTACH_LONG_FILENAME, PR_ATTACH_MIME_TAG, PR_DISPLAY_NAME, PR_ATTACH_METHOD]); |
||
941 | // Content Type |
||
942 | $contentType = "application/octet-stream"; |
||
943 | // Filename |
||
944 | $filename = "ERROR"; |
||
945 | |||
946 | // Set filename |
||
947 | if (isset($props[PR_ATTACH_LONG_FILENAME])) { |
||
948 | $filename = PathUtil::sanitizeFilename($props[PR_ATTACH_LONG_FILENAME]); |
||
949 | } |
||
950 | else { |
||
951 | if (isset($props[PR_ATTACH_FILENAME])) { |
||
952 | $filename = PathUtil::sanitizeFilename($props[PR_ATTACH_FILENAME]); |
||
953 | } |
||
954 | else { |
||
955 | if (isset($props[PR_DISPLAY_NAME])) { |
||
956 | $filename = PathUtil::sanitizeFilename($props[PR_DISPLAY_NAME]); |
||
957 | } |
||
958 | } |
||
959 | } |
||
960 | |||
961 | // Set content type |
||
962 | if (isset($props[PR_ATTACH_MIME_TAG])) { |
||
963 | $contentType = $props[PR_ATTACH_MIME_TAG]; |
||
964 | } |
||
965 | else { |
||
966 | // Parse the extension of the filename to get the content type |
||
967 | if (strrpos($filename, ".") !== false) { |
||
968 | $extension = strtolower(substr($filename, strrpos($filename, "."))); |
||
969 | $contentType = "application/octet-stream"; |
||
970 | if (is_readable("mimetypes.dat")) { |
||
971 | $fh = fopen("mimetypes.dat", "r"); |
||
972 | $ext_found = false; |
||
973 | while (!feof($fh) && !$ext_found) { |
||
974 | $line = fgets($fh); |
||
975 | preg_match("/(\\.[a-z0-9]+)[ \t]+([^ \t\n\r]*)/i", $line, $result); |
||
976 | if ($extension == $result[1]) { |
||
977 | $ext_found = true; |
||
978 | $contentType = $result[2]; |
||
979 | } |
||
980 | } |
||
981 | fclose($fh); |
||
982 | } |
||
983 | } |
||
984 | } |
||
985 | |||
986 | $tmpname = tempnam(TMP_PATH, stripslashes($filename)); |
||
987 | |||
988 | // Open a stream to get the attachment data |
||
989 | $stream = mapi_openproperty($attachment, PR_ATTACH_DATA_BIN, IID_IStream, 0, 0); |
||
990 | $stat = mapi_stream_stat($stream); |
||
991 | // File length = $stat["cb"] |
||
992 | |||
993 | Logger::debug(self::LOG_CONTEXT, "filesize: " . $stat["cb"]); |
||
994 | |||
995 | $fhandle = fopen($tmpname, 'w'); |
||
996 | $buffer = null; |
||
997 | for ($i = 0; $i < $stat["cb"]; $i += BLOCK_SIZE) { |
||
998 | // Write stream |
||
999 | $buffer = mapi_stream_read($stream, BLOCK_SIZE); |
||
1000 | fwrite($fhandle, $buffer, strlen($buffer)); |
||
1001 | } |
||
1002 | fclose($fhandle); |
||
1003 | |||
1004 | Logger::debug(self::LOG_CONTEXT, "temp attachment written to " . $tmpname); |
||
1005 | |||
1006 | return [$tmpname, $filename]; |
||
1007 | } |
||
1008 | } |
||
1009 | } |
||
1010 | else { |
||
1011 | Logger::error(self::LOG_CONTEXT, "store could not be opened"); |
||
1012 | } |
||
1013 | } |
||
1014 | else { |
||
1015 | Logger::error(self::LOG_CONTEXT, "wrong call, store and entryid have to be set"); |
||
1016 | } |
||
1017 | |||
1018 | return false; |
||
1019 | } |
||
1020 | |||
1021 | /** |
||
1022 | * Store the email as eml to a temporary directory and return its temporary filename. |
||
1023 | * |
||
1024 | * @param mixed $item |
||
1025 | * |
||
1026 | * @return array (tmpname, filename) or false on error |
||
1027 | */ |
||
1028 | private function prepareEmailForUpload($item) { |
||
1029 | // Get store id |
||
1030 | $storeid = false; |
||
1031 | if (isset($item["store"])) { |
||
1032 | $storeid = $item["store"]; |
||
1033 | } |
||
1034 | |||
1035 | // Get message entryid |
||
1036 | $entryid = false; |
||
1037 | if (isset($item["entryid"])) { |
||
1038 | $entryid = $item["entryid"]; |
||
1039 | } |
||
1040 | |||
1041 | $tmpname = ""; |
||
1042 | $filename = ""; |
||
1043 | |||
1044 | $store = $GLOBALS['mapisession']->openMessageStore(hex2bin($storeid)); |
||
1045 | $message = mapi_msgstore_openentry($store, hex2bin($entryid)); |
||
1046 | |||
1047 | // Decode smime signed messages on this message |
||
1048 | parse_smime($store, $message); |
||
1049 | |||
1050 | if ($message && $store) { |
||
1051 | // get message properties. |
||
1052 | $messageProps = mapi_getprops($message, [PR_SUBJECT, PR_MESSAGE_CLASS]); |
||
1053 | |||
1054 | $isSupportedMessage = ( |
||
1055 | (stripos((string) $messageProps[PR_MESSAGE_CLASS], 'IPM.Note') === 0) || |
||
1056 | (stripos((string) $messageProps[PR_MESSAGE_CLASS], 'Report.IPM.Note') === 0) || |
||
1057 | (stripos((string) $messageProps[PR_MESSAGE_CLASS], 'IPM.Schedule') === 0) |
||
1058 | ); |
||
1059 | |||
1060 | if ($isSupportedMessage) { |
||
1061 | // Get addressbook for current session |
||
1062 | $addrBook = $GLOBALS['mapisession']->getAddressbook(); |
||
1063 | |||
1064 | // Read the message as RFC822-formatted e-mail stream. |
||
1065 | $stream = mapi_inetmapi_imtoinet($GLOBALS['mapisession']->getSession(), $addrBook, $message, []); |
||
1066 | |||
1067 | if (!empty($messageProps[PR_SUBJECT])) { |
||
1068 | $filename = PathUtil::sanitizeFilename($messageProps[PR_SUBJECT]) . '.eml'; |
||
1069 | } |
||
1070 | else { |
||
1071 | $filename = _('Untitled') . '.eml'; |
||
1072 | } |
||
1073 | |||
1074 | $tmpname = tempnam(TMP_PATH, "email2filez"); |
||
1075 | |||
1076 | // Set the file length |
||
1077 | $stat = mapi_stream_stat($stream); |
||
1078 | |||
1079 | $fhandle = fopen($tmpname, 'w'); |
||
1080 | $buffer = null; |
||
1081 | for ($i = 0; $i < $stat["cb"]; $i += BLOCK_SIZE) { |
||
1082 | // Write stream |
||
1083 | $buffer = mapi_stream_read($stream, BLOCK_SIZE); |
||
1084 | fwrite($fhandle, $buffer, strlen($buffer)); |
||
1085 | } |
||
1086 | fclose($fhandle); |
||
1087 | |||
1088 | return [$tmpname, $filename]; |
||
1089 | } |
||
1090 | } |
||
1091 | |||
1092 | return false; |
||
1093 | } |
||
1094 | |||
1095 | /** |
||
1096 | * Get sharing information from the backend. |
||
1097 | * |
||
1098 | * @return bool |
||
1099 | */ |
||
1100 | private function getSharingInformation($actionType, $actionData) { |
||
1150 | } |
||
1151 | |||
1152 | /** |
||
1153 | * Create a new share. |
||
1154 | * |
||
1155 | * @return bool |
||
1156 | */ |
||
1157 | private function createNewShare($actionType, $actionData) { |
||
1158 | $records = $actionData["records"]; |
||
1159 | $shareOptions = $actionData["options"]; |
||
1160 | |||
1161 | if (count($records) < 1) { |
||
1162 | $this->sendFeedback(false, [ |
||
1163 | 'type' => ERROR_GENERAL, |
||
1164 | 'info' => [ |
||
1165 | 'title' => _("Files Plugin"), |
||
1166 | 'original_message' => _("No record given!"), |
||
1167 | 'display_message' => _("No record given!"), |
||
1168 | ], |
||
1169 | ]); |
||
1170 | } |
||
1171 | |||
1172 | $account = $this->accountFromNode($records[0]); |
||
1173 | |||
1174 | // initialize the backend |
||
1175 | $initializedBackend = $this->initializeBackend($account); |
||
1176 | |||
1177 | $sharingRecords = []; |
||
1178 | foreach ($records as $record) { |
||
1179 | $path = substr((string) $record, strpos((string) $record, '/')); // remove account id |
||
1180 | $sharingRecords[$path] = $shareOptions; // add options |
||
1181 | } |
||
1182 | |||
1183 | try { |
||
1184 | $sInfo = $initializedBackend->share($sharingRecords); |
||
1185 | } |
||
1186 | catch (Exception $e) { |
||
1187 | $response['status'] = false; |
||
1188 | $response['header'] = _('Sharing failed'); |
||
1189 | $response['message'] = $e->getMessage(); |
||
1190 | $this->addActionData("error", $response); |
||
1191 | $GLOBALS["bus"]->addData($this->getResponseData()); |
||
1192 | |||
1193 | return false; |
||
1194 | } |
||
1195 | |||
1196 | $sharingInfo = []; |
||
1197 | foreach ($sInfo as $path => $details) { |
||
1198 | $realPath = "#R#" . $account->getId() . $path; |
||
1199 | $sharingInfo[$realPath] = $details; // add account id again |
||
1200 | } |
||
1201 | |||
1202 | $response = []; |
||
1203 | $response['status'] = true; |
||
1204 | $response['shares'] = $sharingInfo; |
||
1205 | $this->addActionData($actionType, $response); |
||
1206 | $GLOBALS["bus"]->addData($this->getResponseData()); |
||
1207 | |||
1208 | return true; |
||
1209 | } |
||
1210 | |||
1211 | /** |
||
1212 | * Update a existing share. |
||
1213 | * |
||
1214 | * @return bool |
||
1215 | */ |
||
1216 | private function updateExistingShare($actionType, $actionData) { |
||
1217 | $records = $actionData["records"]; |
||
1218 | $accountID = $actionData["accountid"]; |
||
1219 | $shareOptions = $actionData["options"]; |
||
1220 | |||
1221 | if (count($records) < 1) { |
||
1222 | $this->sendFeedback(false, [ |
||
1223 | 'type' => ERROR_GENERAL, |
||
1224 | 'info' => [ |
||
1225 | 'title' => _("Files Plugin"), |
||
1226 | 'original_message' => _("No record given!"), |
||
1227 | 'display_message' => _("No record given!"), |
||
1228 | ], |
||
1229 | ]); |
||
1230 | } |
||
1231 | |||
1232 | $account = $this->accountStore->getAccount($accountID); |
||
1233 | |||
1234 | // initialize the backend |
||
1235 | $initializedBackend = $this->initializeBackend($account); |
||
1236 | |||
1237 | $sharingRecords = []; |
||
1238 | foreach ($records as $record) { |
||
1239 | $sharingRecords[$record] = $shareOptions; // add options |
||
1240 | } |
||
1241 | |||
1242 | try { |
||
1243 | $sInfo = $initializedBackend->share($sharingRecords, true); |
||
1244 | } |
||
1245 | catch (Exception $e) { |
||
1246 | $response['status'] = false; |
||
1247 | $response['header'] = _('Updating share failed'); |
||
1248 | $response['message'] = $e->getMessage(); |
||
1249 | $this->addActionData("error", $response); |
||
1250 | $GLOBALS["bus"]->addData($this->getResponseData()); |
||
1251 | |||
1252 | return false; |
||
1253 | } |
||
1254 | |||
1255 | $response = []; |
||
1256 | $response['status'] = true; |
||
1257 | $response['shares'] = $sInfo; |
||
1258 | $this->addActionData($actionType, $response); |
||
1259 | $GLOBALS["bus"]->addData($this->getResponseData()); |
||
1260 | |||
1261 | return true; |
||
1262 | } |
||
1263 | |||
1264 | /** |
||
1265 | * Delete one or more shares. |
||
1266 | * |
||
1267 | * @return bool |
||
1268 | */ |
||
1269 | private function deleteExistingShare($actionType, $actionData) { |
||
1308 | } |
||
1309 | |||
1310 | /** |
||
1311 | * Function will use to update the cache. |
||
1312 | * |
||
1313 | * @param string $actionType name of the current action |
||
1314 | * @param array $actionData all parameters contained in this request |
||
1315 | * |
||
1316 | * @return bool true on success or false on failure |
||
1317 | */ |
||
1318 | public function updateCache($actionType, $actionData) { |
||
1340 | } |
||
1341 | } |
||
1342 |
Let?s assume that you have a directory layout like this:
and let?s assume the following content of
Bar.php
:If both files
OtherDir/Foo.php
andSomeDir/Foo.php
are loaded in the same runtime, you will see a PHP error such as the following:PHP Fatal error: Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php
However, as
OtherDir/Foo.php
does not necessarily have to be loaded and the error is only triggered if it is loaded beforeOtherDir/Bar.php
, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias: