rs = $rs; $this->em = $em; $this->ts = $ts; $this->sm = $sm; $this->fmps = $fmps; $this->ums = $ums; $this->tbs = $tbs; $this->avs = $avs; $this->pathDataWarehouse = $pathDataWarehouse; $this->dataQueue = $dataQueue; $this->fileOrmRepo = $em->getRepository('FileManagerBundle:FileItem'); $this->groupManagerService = $groupManagerService; } /** * @param FileItem $file * @return bool */ public function quickUpdate(FileItem $file){ if(empty($file)) return false; try { if(!$this->em->contains($file)) $this->em->persist($file); $this->em->flush(); } catch (OptimisticLockException $e) { //die('Exception : '.$e->getMessage()); return false; } catch (ORMException $e) { return false; } return true; } /** * @param FileItem $file * @return bool */ public function update(FileItem $file){ if(empty($file)) return false; /* do some shit in here */ $path = $file->getPath(); if(isset($path) && !empty($path) && $file->getFilePreview() instanceof FilePreview){ $actual = $file->getFilePreview()->getMainFile(); if($path !== $actual){ //generate thumbs $file->getFilePreview()->setMainFile($path); $file->getFilePreview()->setMainMime($file->getMime()); try { $this->em->flush(); } catch (OptimisticLockException $o){ return false; } catch (ORMException $e) { return false; } $this->tbs->generate($file->getFilePreview()); } } return $this->quickUpdate($file); } /** * @param string $msg * @param null $desc * @return array */ protected function reportError($msg = "An error occured", $desc = null){ $ret = array( 'error' => true, 'msg' => $msg ); if(!is_null($desc)) $ret['description'] = $desc; return $ret; } /** * @param string $msg * @param array $append * @return array */ protected function reportSuccess($msg = "Operation successful", $append = array()){ $ret = array( 'error' => false, 'msg' => $msg ); return array_merge($ret,$append); } /** * @param FolderItem $folderItem * @return bool */ public function updateFolder(FolderItem $folderItem){ if(empty($folderItem)) return false; /* do some shit in here */ return $this->quickUpdateFolder($folderItem); } /** * @param FolderItem $folderItem * @return bool */ public function quickUpdateFolder(FolderItem $folderItem){ if(empty($folderItem)) return false; try { if(!$this->em->contains($folderItem)) $this->em->persist($folderItem); $this->em->flush(); } catch (OptimisticLockException $e) { //die('Exception : '.$e->getMessage()); return false; } catch (ORMException $e) { return false; } return true; } /** * @param $bytes * @param int $precision * @return string */ private function formatBytes($bytes, $precision = 2) { $units = array('B', 'KB', 'MB', 'GB', 'TB'); $bytes = max($bytes, 0); $pow = floor(($bytes ? log($bytes) : 0) / log(1024)); $pow = min($pow, count($units) - 1); // Uncomment one of the following alternatives $bytes /= pow(1024, $pow); // $bytes /= (1 << (10 * $pow)); return round($bytes, $precision) . ' ' . $units[$pow]; } /** * @param $guid * @param bool $getHidden * @return FileItem|array */ public function getFileFromGuid($guid, $getHidden = false){ $f = $this->getFileItemFromGuid($guid, $getHidden); if(is_null($f) || !$f instanceof FileItem) return $this->reportError('File not found'); else{ if($this->fmps->canRead($f)){ return $f; } else return $this->reportError('Operation Not Allowed'); } } /** * @param $guid * @param bool $getHidden * @return FileItem|null */ public function getFileItemFromGuid($guid, $getHidden = false){ $search = array('guid' => $guid); if(!$getHidden) array('guid' => $guid,'hidden' => false); return $this->fileOrmRepo->findOneBy($search); } /** * @param string $guid * @return UploadRequestItem|null */ public function getUploadRequestItemFromGuid($guid){ $search = array('guid' => $guid); return $this->em->getRepository('FileManagerBundle:UploadRequestItem')->findOneBy($search); } /** * check if actual user|$u can access file/folder w/ $guid * * @param $guid * @param null|CustomUserInterface $u aliased user for permission * @return bool */ public function canAccessItem($guid, $u = null){ if(str_contains('-',$guid)){ $f = $this->getFileItemFromGuid($guid); if(!$f instanceof FileItem) return false; return $this->canAccessFile($f,$u); }else{ $f = $this->getFolderFromGuid($guid); if(!$f instanceof FolderItem) return false; return $this->canAccessFolder($f,$u); } } public function canAccessFile(FileItem $fileItem, $u = null){ if($u instanceof CustomUserInterface){ $this->fmps->setAliasedUser($u); } $ret = false; if($this->fmps->canRead($fileItem)) $ret = true; if($u instanceof CustomUserInterface){ $this->fmps->setAliasedUser(null); } return $ret; } public function canAccessFolder(FolderItem $folderItem, $u = null){ if($u instanceof CustomUserInterface){ $this->fmps->setAliasedUser($u); } $ret = false; if($this->fmps->canReadFolder($folderItem)) $ret = true; if($u instanceof CustomUserInterface){ $this->fmps->setAliasedUser(null); } return $ret; } /** * Request an upload for given user/anonymous * * @param $filename * @param $fileSize * @param $remoteIp * @param null $parentFolder * @param bool $bindToUser * @param bool $directMode * @param bool $hiddenFile * @param null $fileNameAtt * @return array|UploadRequestItem */ public function createUploadRequest($filename, $fileSize, $remoteIp, $parentFolder = null, $bindToUser = true, $directMode = false, $hiddenFile = false, $fileNameAtt = null) { $user = $this->ts->getToken()->getUser(); if(!$user instanceof UserFileOwnerInterface) $user = false; if($user !== false && isset($parentFolder) && is_string($parentFolder)){ $parentFolder = $this->getFolderItemFromGuid($parentFolder); if(!$this->fmps->canEditFolder($parentFolder)){ return $this->reportError("Permission denied"); } } if($user === false) $maxSize = $this->sm->get('NET15.FILEMANAGER.SIZE.LIMIT.ANONYMOUS',5000000,true,"fileManager"); else $maxSize = $this->sm->get('NET15.FILEMANAGER.SIZE.LIMIT.LOGGED',2130000000,true,"fileManager"); if($maxSize < $fileSize) return $this->reportError('File over the max size '.$this->formatBytes($maxSize)); /* if($user === false){ $typeParse = $this->sm->get('NET15.FILEMANAGER.TYPE.LIMIT.ANONYMOUS',false,true,"fileManager"); if($typeParse){ $default = serialize(array()); $arrayAuth = $this->sm->get('NET15.FILEMANAGER.TYPE.LIMIT.MIME.ARRAY.ANONYMOUS',$default,true,"fileManager"); $arrayAuth = unserialize($arrayAuth); if(is_array($arrayAuth) && !in_array($fileMimeAttribute,$arrayAuth)){ return $this->reportError('File format not accepted '.$fileMimeAttribute); } } }//*/ $params = array( 'bindToUser' => $bindToUser, 'directMode' => $directMode, 'hiddenFile' => $hiddenFile, 'fileNameAtt' => $fileNameAtt, ); if($parentFolder instanceof FolderItem) $params['parentFolder'] = $parentFolder->getGuid(); else $params['parentFolder'] = $parentFolder; $requestUpload = new UploadRequestItem(); $requestUpload ->setRemoteIp($remoteIp) ->setFilesize((int)$fileSize) ->setSourceParams(serialize($params)) ->setFilename($filename); if($parentFolder instanceof FolderItem) $requestUpload->setFolderTargetGuid($parentFolder->getGuid()); $requestUpload->generateGuid(); if($user !== false) $requestUpload->setUserFileOwnerInterface($user); try { if(!$this->em->contains($requestUpload)) $this->em->persist($requestUpload); $this->em->flush(); } catch (OptimisticLockException $e) { return $this->reportError("error while registering uploadRequest"); } catch (ORMException $e) { return $this->reportError("error while registering uploadRequest"); } return $requestUpload; } /** * @param null $parentFolder * @param bool $bindToUser * @param bool $directMode * @param bool $hiddenFile * @param null $fileNameAtt * @return array|FileItem */ public function loadVirtualFile($parentFolder = null, $bindToUser = true, $directMode = false, $hiddenFile = false, $fileNameAtt = null){ $path = $this->getPath().'virtual/'; if(!is_dir($path)) @mkdir($path,0777,true); $file = time().md5(mt_rand(1,999)); touch($path.$file); file_put_contents($path.$file,'42'); if(!is_file($path.$file)) return $this->reportError("Error while creating the file"); return $this->loadFile($path.$file, $parentFolder, $bindToUser, $directMode, $hiddenFile, $fileNameAtt,true); } private function temporaryFile($name, $content) { $file = DIRECTORY_SEPARATOR . trim(sys_get_temp_dir(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . ltrim($name, DIRECTORY_SEPARATOR); file_put_contents($file, $content); register_shutdown_function(function() use($file) { unlink($file); }); return $file; } /** * create a deepcopy without permissions * * @param FileItem $original * @param FolderItem $folder * @param bool $deleteOldOne * @return FileItem|null */ public function copyFileItem(FileItem $original, FolderItem $folder, bool $deleteOldOne= false){ $oriFile = $original->getPath(); $copyPath = $this->temporaryFile(md5(mt_rand(1111111,9999999)),''); $src = fopen($oriFile, 'r'); $dest1 = fopen($copyPath, 'w'); stream_copy_to_stream($src, $dest1); fclose($src); fclose($dest1); $f = $this->loadFile($copyPath,$folder, false,true,false,$original->getName(),true); if(!$f instanceof FileItem || is_array($f)) return null; $folder->addFile($f); $r = $this->quickUpdateFolder($folder); if(!$r) return null; if($deleteOldOne) $this->deleteFileFromGuid($original->getGuid(),false); return $f; } /** * @param string $filename represent either the $_FILE name or the absolute path to a file * @param null $parentFolder * @param bool $bindToUser * @param bool $directMode * @param bool $hiddenFile * @param null $fileNameAtt * @param bool $forceMoove * @return array|FileItem */ public function loadFile($filename, $parentFolder = null, $bindToUser = true, $directMode = false, $hiddenFile = false, $fileNameAtt = null, $forceMoove = false){ /** * @var $media UploadedFile */ $media = $this->rs->getCurrentRequest()->files->get((string)$filename); if($directMode){ if(is_file($filename)){ $directPath = $filename; } else { $directPath = null; } } else $directPath = null; $folder = $this->rs->getCurrentRequest()->get('folder',null); if(isset($folder) && is_string($folder)) $parentFolder = $this->getFolderItemFromGuid($folder); if(isset($parentFolder) && is_string($parentFolder)) $parentFolder = $this->getFolderItemFromGuid($parentFolder); if(is_null($media) && is_null($directPath)) return $this->reportError('no file received'); $document = new FileItem($this->getPath()); if($directMode){ $filenameAttribute = $filename; } else $filenameAttribute = $media->getFilename(); $hash = $this->generateFileHash($filenameAttribute); $preview = new FilePreview(); if($directMode) $filePathAttribute = $filename; else $filePathAttribute = $media->getPathName(); //filebaseName if($directMode){ $fileBasenameAttribute = basename($filename); if(!is_null($fileNameAtt)) $fileBasenameAttribute = $fileNameAtt; } else $fileBasenameAttribute = $media->getClientOriginalName(); $document ->setGuid($hash) ->setFilePreview($preview) ->setInQueue($this->hasToQueue()) ->setPath($filePathAttribute) ->setName($this->sanitizeFileName($fileBasenameAttribute)) ; if($hiddenFile) $document->setHidden(true); if(!$directMode){ $document->setFile($media); } else{ $document ->setMove(true) ->setOriginalHash(hash_file('sha256',$filename)) ->setSize((int)filesize($filename)); } if($forceMoove) $document->setMove(true); if($directMode){ $fileMimeAttribute = mime_content_type($filename); $document->setMime($fileMimeAttribute); $fileSizeAttribute = 0; } else { $fileMimeAttribute = $media->getMimeType(); $fileSizeAttribute = $media->getSize(); } $matchRules = true; $user = $this->getUser(); if($bindToUser instanceof CustomUserInterface) $user = $bindToUser; if(is_bool($user)){ //anonymous $maxSize = $this->sm->get('NET15.FILEMANAGER.SIZE.LIMIT.ANONYMOUS',5000000,true,"fileManager"); if($fileSizeAttribute > $maxSize) return $this->reportError('File over the max size '.$this->formatBytes($maxSize)); $typeParse = $this->sm->get('NET15.FILEMANAGER.TYPE.LIMIT.ANONYMOUS',false,true,"fileManager"); if($typeParse){ $default = serialize(array()); $arrayAuth = $this->sm->get('NET15.FILEMANAGER.TYPE.LIMIT.MIME.ARRAY.ANONYMOUS',$default,true,"fileManager"); $arrayAuth = unserialize($arrayAuth); if(\is_array($arrayAuth) && !\in_array($fileMimeAttribute,$arrayAuth)){ return $this->reportError('File format not accepted '.$fileMimeAttribute); } } }elseif($user instanceof UserInterface){ //logged $maxSize = $this->sm->get('NET15.FILEMANAGER.SIZE.LIMIT.LOGGED',2130000000,true,"fileManager"); if($fileSizeAttribute > $maxSize) return $this->reportError('File over the max size '.$this->formatBytes($maxSize)); $typeParse = $this->sm->get('NET15.FILEMANAGER.TYPE.LIMIT.LOGGED',false,true,"fileManager"); if($typeParse){ $default = serialize(array()); $arrayAuth = $this->sm->get('NET15.FILEMANAGER.TYPE.LIMIT.MIME.ARRAY.LOGGED',$default,true,"fileManager"); $arrayAuth = unserialize($arrayAuth); if(\is_array($arrayAuth) && !\in_array($fileMimeAttribute,$arrayAuth)){ return $this->reportError('File format not accepted '.$fileMimeAttribute); } } } else { return $this->reportError('Identification Error'); } if(!$matchRules) return $this->reportError('File validation error'); if(!$this->quickUpdate($document)) return $this->reportError('Error while registering file'); if($bindToUser){ if($bindToUser instanceof CustomUserInterface) $u = $bindToUser; else $u = null; $bindRet = $this->bindFileToUserIfAny($document,$parentFolder,$u); if(\is_array($bindRet)) return $bindRet; } if(!$this->avs->isFileSafe($document->getPath(),$document->getName())){ $this->deleteFileItem($document,false); return $this->reportError('malicious file detected, file removed'); } if(!$this->update($document)) return $this->reportError('Error while registering file [2]'); return $document; } /** * Load all files * * @param null|FolderItem $parentFolder * @param bool $bindToUser * @return array */ public function loadAllFiles($parentFolder = null, $bindToUser = true){ $filesArray = $this->rs->getCurrentRequest()->files->all(); $return = array(); foreach($filesArray as $key=>$file){ $return[$key] = $this->loadFile($file,$parentFolder,$bindToUser); } return $return; } /** * delete fileitem from guid * * * @param string $guid * @param bool $applyPermissions * @return array|bool */ public function deleteFileFromGuid(string $guid, bool $applyPermissions = true){ $fileItem = $this->getFileItemFromGuid($guid); if($fileItem instanceof FileItem) return $this->deleteFileItem($fileItem,$applyPermissions); return false; } public function deleteFileItem(FileItem $fileItem, bool $applyPermissions = true){ $id = $fileItem->getId(); if($id !== null){ if(!$applyPermissions){ //on applique pas les droits #YOLO try{ $this->em->remove($fileItem); $this->em->flush(); } catch (OptimisticLockException $o){ return $this->reportError('Operation error!'); } catch (ORMException $e) { return $this->reportError('Operation error!'); } return true; } else { //on applique les droits if($this->fmps->canDelete($fileItem)){ try{ $this->em->remove($fileItem); $this->em->flush(); } catch (OptimisticLockException $o){ return $this->reportError('Operation error!'); } catch (ORMException $e) { return $this->reportError('Operation error!'); } return true; } else return $this->reportError('Operation not allowed!'); } } else return $this->reportError('File not found!'); } /** * Bind user to actual file as owner * * @param FileItem $file * @param FolderItem|null $parentFolder * @param null|CustomUserInterface $userTarget * @return array|bool */ public function bindFileToUserIfAny(FileItem $file, FolderItem $parentFolder = null, $userTarget = null){ if(is_null($userTarget) && !($u = $this->getUser())){ $this->fmps->anonymousAddFileInWallet($file->getGuid()); return true; } if($userTarget instanceof CustomUserInterface){ $u = $userTarget; $this->fmps->setAliasedUser($u); } else{ $u = $this->getUser(); } $link = new FileOwner($u,$file,FilePermission::OWNER); $file->addFileOwner($link); $this->update($file); //la if(!is_bool($parentFolder)){ if(is_null($parentFolder) || !$parentFolder instanceof FolderItem){ $f = $this->userDropbox($u); if($f instanceof FolderItem){ $f->addFile($file); $this->quickUpdateFolder($f); } else { return $this->reportError('Folder not found'); } }else { if($this->fmps->canEditFolder($parentFolder)){ $parentFolder->addFile($file); $this->quickUpdateFolder($parentFolder); } else return $this->reportError('Operation denied in folder'); } } $this->fmps->setAliasedUser(null); return true; } /** * return path ending with "/" * * @return string */ public function getPath(){ if(!$this->hasToQueue()) return $this->pathDataWarehouse; else return $this->dataQueue; } /** * check if data warehouse server is available return true if file has to be queued * * @return bool */ protected function hasToQueue(){ if(is_file($this->pathDataWarehouse.'coucou')) return false; else return true; } /** * Return User object or false if none found * * @return bool|mixed */ protected function getUser(){ $user = $this->ts->getToken()->getUser(); if($user instanceof UserInterface) return $user; return false; } /** * return hash for current file * * @param $input * @return string */ public function generateFileHash($input){ $options = array( 'cost' => 11, ); return time().'-'.base64_encode(password_hash($input, PASSWORD_BCRYPT, $options)); } /** * @param null|CustomUserInterface $user * @return array|FolderItem */ public function userDropbox($user = null){ if(is_null($user) || !$user instanceof CustomUserInterface) $user = $this->ts->getToken()->getUser(); if(!$user instanceof UserInterface) return $this->reportError('Error authentication needed'); /** * @var UserFileOwnerInterface|CustomUserInterface $user */ $f = $user->getDropboxFolder(); if(is_null($f)){ $obj = $this->userInitDropbox($user); return $obj; } else if($f instanceof FolderItem) return $f; else return $this->reportError('Folder type error'); } /** * @param null|CustomUserInterface $user * @return array|FolderItem */ public function userTrash($user = null){ if(is_null($user) || !$user instanceof CustomUserInterface) $user = $this->ts->getToken()->getUser(); if(!$user instanceof UserInterface) return $this->reportError('Error authentication needed'); /** * @var UserFileOwnerInterface|CustomUserInterface $user */ $f = $user->getTrashFolder(); if(is_null($f)){ $obj = $this->userInitTrash($user); return $obj; } else if($f instanceof FolderItem) return $f; else return $this->reportError('Folder type error'); } /** * @param UserFileOwnerInterface|UserInterface $user * @return array|FolderItem */ protected function userInitDropbox(UserFileOwnerInterface $user){ $folder = $this->userCreateFolder("My Box",$user,"Base folder"); /** * @var UserFileOwnerInterface|CustomUserInterface $user */ if($folder instanceof FolderItem){ $user->setDropboxFolder($folder); if(!$this->ums->quickUpdate($user)) return $this->reportError('Error while updating user'); else return $folder; } else return $folder; } /** * @param UserFileOwnerInterface $user * @return array|FolderItem */ protected function userInitTrash(UserFileOwnerInterface $user){ $folder = $this->userCreateFolder("Trash",$user,"trash folder"); $folder->setTrash(true); /** * @var UserFileOwnerInterface|CustomUserInterface $user */ if($folder instanceof FolderItem){ $user->setTrashFolder($folder); if(!$this->ums->quickUpdate($user)) return $this->reportError('Error while updating user'); else return $folder; } else return $folder; } /** * @return FolderItem|null */ public function getSystemBox(){ $f = $this->em->getRepository('FileManagerBundle:FolderItem')->findOneBy(['systemBox' => true]); if($f instanceof FolderItem) return $f; return $this->createSystemBox(); } /** * @return FolderItem|null */ private function createSystemBox(){ $f = new FolderItem(); $f ->setName('systembox') ->setSystemBox(true) ; $r = $this->updateFolder($f); if(!$r) return null; $g = new UserGroup(); $g->setDefault('systembox'); $r = $this->groupManagerService->registerGroup($g); if(!$r) return null; $folderPermission = new FolderGroupPermission(); $folderPermission->setDefault($g,$f,FilePermission::OWNER); $r = $this->fmps->updateFolderGroupPermission($folderPermission); if(!$r) return null; return $f; } /** * @param $guid * @return FolderItem|array */ public function getFolderFromGuid($guid){ $f = $this->getFolderItemFromGuid($guid); if(is_null($f) || !$f instanceof FolderItem) return $this->reportError('Folder not found'); else{ if($this->fmps->canReadFolder($f)){ return $f; } else return $this->reportError('Operation Not Allowed'); } } /** * @param $guid * @return FolderItem|null */ public function getFolderItemFromGuid($guid){ return $this->em->getRepository('FileManagerBundle:FolderItem')->findOneBy(array('guid' => $guid)); } /** * @param string $guid * @return array */ public function deleteFolderFromGuid(string $guid){ $folderItem = $this->getFolderItemFromGuid($guid); $id = $folderItem->getId(); if(isset($id)){ if($folderItem->isBase()) return $this->reportError('Operation not allowed on base folder!'); if($this->fmps->canDeleteFolder($folderItem)){ try { $this->searchAndReplacePreviousFolder($folderItem); $this->em->remove($folderItem); } catch (ORMException $e) { return $this->reportError('Operation error! 1'); } try { $this->em->flush(); } catch (OptimisticLockException $o){ return $this->reportError('Operation error! 2'); } catch (ORMException $e) { return $this->reportError('Operation error! 3'); } return $this->reportSuccess('deleted',array('guid'=>$guid)); } else return $this->reportError('Operation not allowed!'); } else return $this->reportError('Folder not found!'); } /** * @param FolderItem $old * @param FolderItem $new */ public function searchAndReplacePreviousFolder(FolderItem $old, ?FolderItem $new = null){ $repo = $this->em->getRepository('FileManagerBundle:FolderItem'); $all = $repo->findBy(array('previousParentFolder' => $old)); //var_dump($old->getName()); foreach ($all as $f) { /** * @var $f FolderItem */ //var_dump($f->getName()); $f->setPreviousParentFolder($new); $this->quickUpdateFolder($f); } $allFiles = $this->fileOrmRepo->findBy(array('previousParentFolder'=>$old)); foreach ($allFiles as $file) { /** * @var $f FileItem */ //var_dump($f->getName()); $file->setPreviousParentFolder($new); $this->quickUpdate($file); } } /** * @param $folderName * @param null $user * @param string $description * @param int $permission * @param null|FolderItem|String $parent * @return array|FolderItem */ public function userCreateFolder($folderName, $user = null, $description = "", $permission = FilePermission::OWNER, $parent = null){ if(!is_string($folderName) || empty($folderName)) return $this->reportError('Error folder\'s name can\'t be empty'); if(is_null($user)) $user = $this->ts->getToken()->getUser(); if(!$user instanceof UserInterface) return $this->reportError('Error authentication needed'); $folder = new FolderItem(); //try to instantiate from guid if(is_string($parent)){ $parent = $this->getFolderItemFromGuid($parent); if(!$parent instanceof FolderItem){ return $this->reportError('Error on parent folder'); } } if($parent instanceof FolderItem){ // var_dump($parent->getGuid()); // var_dump('truc'); // var_dump($this->fmps->canEditFolder($parent)); if($this->fmps->canEditFolder($parent)) $folder->setParent($parent); else return $this->reportError('Operation denied'); } else { $folder->setBase(true); } $folder->setName($this->sanitizeFileName($folderName)); if(!empty($description)) $folder->setDescription($description); if(!$this->quickUpdateFolder($folder)) return $this->reportError('Error while registering folder'); $folderPermission = new FolderOwner($user,$folder,$permission); try { if(!$this->em->contains($folderPermission)) $this->em->persist($folderPermission); } catch (ORMException $e) { return $this->reportError('Error while registering Folder'); } try { $this->em->flush(); } catch (OptimisticLockException $om){ return $this->reportError('Error while registering Folder'); } catch (ORMException $e) { return $this->reportError('Error while registering Folder'); } $folder->addFolderOwners($folderPermission); if(!$this->quickUpdateFolder($folder)) return $this->reportError('Error while registering permissions'); return $folder; } /** * @param $itemGuid * @return array|FileItem|FolderItem|null */ public function restoreItem($itemGuid){ if(strpos($itemGuid, '-') !== false){ return $this->restoreFile($itemGuid); } else { return $this->restoreFolder($itemGuid); } } public function restoreFile($file){ if(is_string($file)){ $file = $this->getFileItemFromGuid($file); } if(!$file instanceof FileItem){ return $this->reportError('Error on file'); } if(!$this->fmps->canDelete($file)) return $this->reportError('Operation denied : missing permissions on file'); $folder = $file->getPreviousParentFolder(); if(!$folder instanceof FolderItem || $this->isTrashedFolder($folder)){ $folder = $this->userDropbox(); if(!$folder instanceof FolderItem) return $this->reportError('Operation impossible : no previous container and no box'); } $folder->addFile($file); $this->quickUpdateFolder($folder); $this->quickUpdate($file); return $file; } /** * @param FolderItem|string $folder * @return array|FolderItem */ public function restoreFolder($folder){ if(is_string($folder)){ $folder = $this->getFolderItemFromGuid($folder); } if(!$folder instanceof FolderItem){ return $this->reportError('Error on folder'); } if(!$this->fmps->canDeleteFolder($folder)) return $this->reportError('Operation denied : missing permissions on source folder'); $targetFolder = $folder->getPreviousParentFolder(); if(!$targetFolder instanceof FolderItem || $this->isTrashedFolder($targetFolder)){ $targetFolder = $this->userDropbox(); if(!$targetFolder instanceof FolderItem) return $this->reportError('Operation impossible : no previous container and no box'); } $targetFolder->addChildren($folder); $this->quickUpdateFolder($targetFolder); $this->quickUpdateFolder($folder); return $folder; } /** * move item (file or folder) to target folder by guid * * @param $itemGuid * @param $guidTarget * @return array|FileItem|FolderItem */ public function moveItemInFolder($itemGuid, $guidTarget){ if(strpos($itemGuid, '-') !== false){ return $this->moveFileInFolder($itemGuid,$guidTarget); } else { return $this->moveFolderInFolder($itemGuid,$guidTarget); } } /** * @param FolderItem|String $folder * @param FolderItem|String $targetFolder * @return FolderItem|array */ public function moveFolderInFolder($folder,$targetFolder){ if(is_string($folder)){ $folder = $this->getFolderItemFromGuid($folder); } if(!$folder instanceof FolderItem){ return $this->reportError('Error on source folder'); } if(is_string($targetFolder)){ $targetFolder = $this->getFolderItemFromGuid($targetFolder); if(!$targetFolder instanceof FolderItem){ return $this->reportError('Error on target folder'); } } if(!$this->fmps->canDeleteFolder($folder)) return $this->reportError('Operation denied : missing permissions on source folder'); if(!$this->fmps->canEditFolder($targetFolder)) return $this->reportError('Operation denied : missing permissions on target folder'); $targetFolder->addChildren($folder); $this->quickUpdateFolder($targetFolder); $this->quickUpdateFolder($folder); return $folder; } /** * move $file in given $folder * no update needed * * @param FileItem|String $file * @param FolderItem|String $folder * @return FileItem|array */ public function moveFileInFolder($file, $folder) { if(is_string($file)){ $file = $this->getFileItemFromGuid($file); } if(!$file instanceof FileItem){ return $this->reportError('Error on file'); } if(is_string($folder)){ $folder = $this->getFolderItemFromGuid($folder); if(!$folder instanceof FolderItem){ return $this->reportError('Error on folder'); } } if(!$this->fmps->canDelete($file)) return $this->reportError('Operation denied : missing permissions on file'); if(!$this->fmps->canEditFolder($folder)) return $this->reportError('Operation denied : missing permissions on folder'); $folder->addFile($file); $this->quickUpdateFolder($folder); $this->quickUpdate($file); return $file; } /** * create a zip from guid's * return FALSE if zip failed, otherwise it return the zip's path * * @param $guidArray * @return bool|string */ public function zipItemsRecursively($guidArray){ $za = new ZipArchive; $path = $this->getPath().'tmp/'; if(!is_dir($path)) @mkdir($path,0777); $filename = time().$this->tbs->generateOutputName().'.zip'; try{ $za->open($path.$filename,ZipArchive::CREATE|ZipArchive::OVERWRITE); $files = array(); $folders = array(); foreach($guidArray as $itemGuid){ if(strpos($itemGuid, '-') !== false){ //file $f = $this->getFileItemFromGuid($itemGuid); if($this->fmps->canRead($f)){ $item = array( 'path' => '/'.$this->sanitizeNameForZip($f->getName()), 'realPath' => $f->getPath() ); $files[] = $item; } } else { //folder $folder = $this->getFolderItemFromGuid($itemGuid); $arrayToMerge = $this->getItemsRecursively($folder,'/'); $files = array_merge($files,$arrayToMerge['files']); $folders = array_merge($folders,$arrayToMerge['folders']); } } foreach($folders as $fi){ $za->addEmptyDir(substr($fi['path'], 1)); } foreach($files as $fii){ //$za->addFromString(substr($fii['path'], 1),file_get_contents($fii['realPath'])); $za->addFile($fii['realPath'],substr($fii['path'], 1)); //if 2 much mmry consumption //$za->setCompressionName(substr($fii['path'], 1),ZipArchive::CM_STORE);//uncomment this line and $za->setCompressionName(substr($fii['path'], 1),ZipArchive::CM_DEFAULT);//comment this line //explanation //CM_DEFAULT take longer and have a better compression at cost of RAM and CPU //CM_STORE basically put all file in one without compression } $za->close(); } catch (Exception $e){ return false; } return $path.$filename; } /** * return a virtual structure to create a zip * * @param $guidArray * @return array */ public function createZipStructureRecursively($guidArray){ $total = array(); $files = array(); $folders = array(); foreach($guidArray as $itemGuid){ if(strpos($itemGuid, '-') !== false){ //file $f = $this->getFileItemFromGuid($itemGuid); if($this->fmps->canRead($f)){ $item = array( 'path' => '/'.$this->sanitizeNameForZip($f->getName()), 'realPath' => $f->getPath() ); $files[] = $item; } } else { //folder $folder = $this->getFolderItemFromGuid($itemGuid); $arrayToMerge = $this->getItemsRecursively($folder,'/'); $files = array_merge($files,$arrayToMerge['files']); $folders = array_merge($folders,$arrayToMerge['folders']); } } //return $total['files'] = $files; $total['folders'] = $folders; return $total; } protected function getItemsRecursively(FolderItem $folderItem, $previousPath){ $ret = array('files' => array(),'folders' => array()); if($this->fmps->canReadFolder($folderItem)){ $actualPath = $previousPath.$this->sanitizeNameForZip($folderItem->getName()).'/'; //grabbing files inside $files = $this->fmps->getFilesInFolder($folderItem); foreach($files as $file){ /** * @var $file FileItem */ $item = array( 'path' => $actualPath.$this->sanitizeNameForZip($file->getName()), 'realPath' => $file->getPath() ); $ret['files'][] = $item; } //grabbing folders $folders = $this->fmps->getFoldersInFolder($folderItem); foreach($folders as $folder){ /** * @var $folder FolderItem */ $item = array( 'path' => $actualPath.$this->sanitizeNameForZip($folder->getName()), 'realPath' => false ); $ret['folders'][] = $item; $innerRet = $this->getItemsRecursively($folder,$actualPath); $ret['files'] = array_merge($ret['files'],$innerRet['files']); $ret['folders'] = array_merge($ret['folders'],$innerRet['folders']); } } return $ret; } /** * return true if $folderItem is in a "trash" folder * * @param FolderItem $folderItem * @return bool */ public function isTrashedFolder(FolderItem $folderItem){ //for breadcrumb or tree view $loop = true; $loopFolder = $folderItem; $trashed = null; while($loop){ if($loopFolder instanceof FolderItem){ if($loopFolder->isBase() || $loopFolder->isTrash()){ if($loopFolder->isTrash()) return true; return false; } else $loopFolder = $loopFolder->getParent(); } else { $loop = false; } } return false; } /** * simple sanitize just for front usage * * /!\ don't add the dot "." in here it will delete it in the filename... * * @param $name * @return mixed */ public function sanitizeFileName($name){ $disallowed = array('"','\'','\\','/','|','[',']','(',')','{','}','=','$','%','@','>','<','?','!','?',',',';',':','*'); foreach($disallowed as $char){ $name = str_replace($char,'',$name); } return $this->str_to_noaccent($name); } public function sanitizeNameForZip($name){ $name = $this->str_to_noaccent($name); return $name; } public function str_to_noaccent($str) { $url = $str; $url = preg_replace('#Ç#', 'C', $url); $url = preg_replace('#ç#', 'c', $url); $url = preg_replace('#è|é|ê|ë#', 'e', $url); $url = preg_replace('#È|É|Ê|Ë#', 'E', $url); $url = preg_replace('#à|á|â|ã|ä|å#', 'a', $url); $url = preg_replace('#@|À|Á|Â|Ã|Ä|Å#', 'A', $url); $url = preg_replace('#ì|í|î|ï#', 'i', $url); $url = preg_replace('#Ì|Í|Î|Ï#', 'I', $url); $url = preg_replace('#ð|ò|ó|ô|õ|ö#', 'o', $url); $url = preg_replace('#Ò|Ó|Ô|Õ|Ö#', 'O', $url); $url = preg_replace('#ù|ú|û|ü#', 'u', $url); $url = preg_replace('#Ù|Ú|Û|Ü#', 'U', $url); $url = preg_replace('#ý|ÿ#', 'y', $url); $url = preg_replace('#Ý#', 'Y', $url); return ($url); } }