123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593 |
- <?php
- /**
- * Define a fileor directory element.
- * @author Valentin CARRUESCO
- * @category Plugin
- * @license MIT
- */
- class Element extends Entity{
- public $id,$path,$label,$type,$extension,$size,$creatorSite,$icon,$thumbnail,$childNumber,$link;
- protected $TABLE_NAME = 'document_element';
- public $fields =
- array(
- 'id' => 'key',
- 'path' => 'longstring',
- 'label' => 'string',
- 'type' => 'string',
- 'extension' => 'string',
- 'size' => 'string',
- 'creatorSite' => 'int'
- );
- //Récupération de la racine de la GED
- public static function root(){
- return File::dir().'documents'.SLASH;
- }
- public function save(){
- $this->path = str_replace('\\','/',$this->path);
- parent::save();
- }
- //Récuperation du chemin ou du flux de thumbnail associé à l'élement
- public function thumbnail(){
- if(!in_array($this->extension, array('jpg','png','jpeg','gif','bmp','jfif'))) return $this->icon();
- if(!file_exists(self::root().'.thumbnails')) mkdir(self::root().'.thumbnails',755,true);
- $thumbname = str_replace(array('\\','./'),array('/',''),$this->path);
- $thumbnail = self::root().'.thumbnails'.SLASH.base64_encode($thumbname).'.'.$this->extension;
- if(!file_exists($thumbnail)){
- $osPath = File::convert_decoding($this->path);
- copy(self::root().$osPath,$thumbnail);
- Image::resize($thumbnail,200,200);
- }
- $path ='data:image/'.$this->extension.';base64,'.base64_encode(file_get_contents($thumbnail));
- return $path;
- }
- //Récuperation du chemin di'one à l'élement
- public function icon(){
- $path = 'plugin/document/img/file-types/';
- $icon = $this->type == 'directory' ? 'folder.svg' : 'document.svg';
- switch($this->extension){
- case 'docx':
- case 'doc':
- case 'dot':
- case 'dotx':
- $icon = 'word.svg';
- break;
- case 'xls':
- case 'xlsx':
- case 'csv':
- $icon = 'excel.svg';
- break;
- case 'ppt':
- case 'pptx':
- $icon = 'powerpoint.svg';
- break;
- case 'pdf':
- $icon = 'pdf.svg';
- break;
- case 'mp3':
- case 'wav':
- case 'mp4':
- case 'flac':
- $icon = 'music.svg';
- break;
- case 'html':
- case 'htm':
- $icon = 'url.svg';
- break;
- case 'msg':
- $icon = 'mail.svg';
- break;
- case 'psd':
- $icon = 'photoshop.svg';
- break;
- case 'rss':
- $icon = 'feed.svg';
- break;
- case 'mdb':
- $icon = 'access.svg';
- break;
- case 'bat':
- case 'sh':
- case 'cmd':
- $icon = 'gear.svg';
- break;
- case 'php':
- case 'js':
- case 'java':
- case 'class':
- case 'css':
- case 'c':
- case 'cpp':
- case 'py':
- $icon = 'code.svg';
- break;
- case 'jpg':
- case 'jpeg':
- case 'png':
- case 'bmp':
- case 'gif':
- case 'svg':
- case 'jfif':
- $icon = 'image.svg';
- break;
- }
- $path .= $icon;
- return $path;
- }
- //Récuperation d'un element base depuis un chemin physique, ou d'un objet element rensiegné a partir du path si non existant en base (prend du utf8 en entré)
- public static function fromPath($path){
- $element = new self();
- //convertion utf8 ISO-8859-1
- $osPath = File::convert_decoding($path);
- $infos = pathinfo($path);
- //Gestion label
- $element->label = mt_basename($path);
- $element->path = str_replace(array(self::root(),'\\'),array('','/'),$path);
- $element->type = is_dir($osPath) ? 'directory' : 'file';
- $element->link = is_link($osPath);
- $exists = file_exists($osPath);
- if($element->type == 'directory'){
- $path .= SLASH;
- $fi = new FilesystemIterator($osPath, FilesystemIterator::SKIP_DOTS);
- $element->childNumber = iterator_count($fi);
- $element->size = 0;
- } else {
- if(isset($infos['extension'])) $element->extension = $infos['extension'];
- $element->size = !$exists ? 0 : filesize($osPath);
- }
- $element->updated = !$exists ? 0 : filemtime($osPath);
- $element->created = !$exists ? 0 : filectime($osPath);
- $relativePath = trim(str_replace(Element::root(),'',$path),SLASH);
- if ($baseElement = Element::load(array('path'=>str_replace('\\','/',$relativePath) ))) {
- $element->creator = $baseElement->creator;
- $element->id = $baseElement->id;
- }
- $element->path = trim($element->path,'/');
- return $element;
- }
- //Récuperation de la liste des élements d'un repertoire (tiens compte des droits utilisateur) (attends de l'utf8)
- public static function browse($scanned,$folderOnly = false){
- global $myUser,$myFirm;
- require_once(__DIR__.SLASH.'ElementRight.class.php');
- $osScanned = File::convert_decoding($scanned);
- $elements = array();
- User::check_access('document','read');
- //Récuperation du tableau des rang utilisateur sous forme d'id.
- $ranks = array();
- if(!$myUser->superadmin){
- foreach($myUser->ranks[$myFirm->id] as $rank)
- $ranks[] = $rank->id;
- }
- $existingPathes = array();
- //Fix glob et utilisation d'un dossier avec des [] (glob utilise ce char pour de la regex, on doit escape)
- $osScanned = str_replace(array('[',']'),array('\[','\]'), $osScanned);
- $osScanned = str_replace(array('\[','\]'), array('[[]','[]]'), $osScanned);
- //Pour chaque fichier physique existant
- foreach(glob($osScanned) as $osPath){
- $osPath = str_replace(SLASH.'.'.SLASH, SLASH, $osPath);
- $basePath = File::convert_encoding($osPath);
- if((substr(mt_basename($osPath), 0,1)=='.') || ($folderOnly && !is_dir($osPath))) continue;
- //Récuperation/création de l'element objet correspondant (frompath n'accepte que l'utf8, on lui donne le basepath)
- $line = Element::fromPath($basePath);
- $existingPathes[] = $line->path;
- //Si l'element correspondant n'existe pas en base, on le créé
- if($line->id == ''){
- $line->creator = 'anonymous';
- $line->save();
- }
- //Si l'utilisateur n'est pas le créateur, pas un super admin et n'a pas le droit configure sur les documents on check les partages de droits
- if($myUser->login != $line->creator && !$myUser->can('document','configure') && !$myUser->superadmin){
- $can = false;
- $pathes = array();
- $path = '';
- //Récuperation des chemins dont on doit récuperer les droits :
- // ex : pour le fichier a/b/c les chemins sont a, a/b, et a/b/c
- foreach(explode('/',$line->path) as $i=>$pathCrumb){
- if($i!=0) $path.= '/';
- $path.= $pathCrumb;
- $pathes[] = $path;
- }
- //On récupere les droits pour chaques chemin
- foreach(ElementRight::staticQuery('SELECT er.*,el.path as '.Element::tableName().'_join_path
- FROM {{table}} er
- LEFT JOIN '.Element::tableName().' el ON el.id=er.element
- WHERE (er.entity=? OR (er.entity=? AND er.uid=?) OR (er.entity=? AND er.uid IN ('.str_repeat('?,',count($ranks)-1).'?)))
- AND element IN(SELECT id from '.Element::tableName().' WHERE path IN ('.str_repeat('?,',count($pathes)-1).'?)) ',array_merge(array("all","user",$myUser->login,"rank"),$ranks,$pathes),true,1) as $right){
- $element = $right->join('element');
- //Si les droits sont sur un dossier parent et sont recursifs OU si les droits sont sur le fichier concerné on continue la verification
- if($right->element == $line->id || ($right->recursive && strpos($line->path, $element->path)!==false ) )
- $can = true;
- }
- if(!$can) continue;
- }
- $elements[] = $line;
- }
- return $elements;
- }
- //Téléchargement d'un fichier ou d'un repertoire (prends de l'utf 8 en entrée)
- public static function download($path){
- $osPath = File::convert_decoding($path);
- if(!file_exists($osPath)) return '';
- $element = Element::fromPath($path);
- if(!self::hasRight($element,'read')) throw new Exception("Permissions insuffisantes",403);
- if(is_dir($osPath)){
- $filename = rand().'-'.time().'.zip';
- $filepath = sys_get_temp_dir().SLASH.$filename;
- $zip = new ZipArchive;
- $res = $zip->open($filepath, ZipArchive::CREATE);
- if ($res === TRUE) {
- //Fix glob et utilisation d'un dossier avec des [] (glob utilise ce char pour de la regex, on doit escape)
- $osPath = str_replace(array('[',']'),array('\[','\]'), $osPath);
- $osPath = str_replace(array('\[','\]'), array('[[]','[]]'), $osPath);
- $ressources = glob_recursive($osPath.SLASH.'*') ;
- foreach($ressources as $resource){
- if(is_dir($resource)) continue;
- $filename = $resource;
- $filename = File::convert_encoding($filename);
- $filename = str_replace($path,mt_basename($path),$filename);
- $filename=iconv("UTF-8", "IBM850", $filename);
- if(!$zip->addFromString($filename, file_get_contents($resource))) throw new Exception("Impossible de compresser le fichier ".$path);
- }
- if(count($ressources)==0)
- $zip->addEmptyDir('.');
- $zip->close();
- }
- $stream = file_get_contents($filepath);
- unlink($filepath);
- }else{
- $stream = file_get_contents($osPath);
- }
- return $stream;
- }
- //Creation d'un raccourcis (prends de l'utf 8 en entrée)
- public static function shortcut($path,$destination,$readonly = false){
- $osDestination = File::convert_decoding($destination);
- if(file_exists($osDestination)) return false;
- $element = Element::fromPath($destination);
- if($readonly){
- require_once(__DIR__.SLASH.'ElementRight.class.php');
- $right = new ElementRight();
- $right->element = $element->id;
- $right->read = true;
- $right->edit = false;
- $right->delete = false;
- $right->recursive = false;
- $right->save();
- }
- return symlink($path,$osDestination);
- }
- //Supression d'un répértoire ou d'un fichier en base et en physique (prends de l'utf 8 en entrée)
- public static function remove($path){
- require_once(__DIR__.SLASH.'ElementRight.class.php');
- $osPath = File::convert_decoding($path);
- if(!file_exists($osPath)) return;
- $element = Element::fromPath($path);
- $dbPath = str_replace('\\','/',$element->path);
- if(!self::hasRight($element,'edit')) throw new Exception("Permissions insuffisantes",403);
- if(is_dir($osPath) && !is_link($osPath)) {
- self::remove_dir_recursive($osPath);
- Element::staticQuery('DELETE FROM {{table}} WHERE `path` = ? OR `path` LIKE ?',array($dbPath,$dbPath.'/%'));
- } else {
- unlink($osPath);
- Element::delete(array('path'=>$dbPath));
- }
- ElementRight::delete(array('element'=>$element->id));
- }
- //Copie d'un répértoire ou d'un fichier en base et en physique (prends de l'utf 8 en entrée)
- public static function copy($path,$to, $checkExist = true){
- $osPath = File::convert_decoding($path);
- $osTo = File::convert_decoding($to);
- if(!file_exists($osPath)) return;
- $element = Element::fromPath($path);
- if($checkExist && file_exists($osTo)) return false;
- $parentPathTo = dirname($to);
- $parentOsPathTo = dirname($osTo);
- if(!file_exists($parentOsPathTo)) throw new Exception("Dossier de destination inexistant",404);
- $parentTo = Element::fromPath($parentPathTo);
- if(!self::hasRight($parentTo,'read')) throw new Exception("Permissions insuffisantes",403);
- if(!self::hasRight($element,'read')) throw new Exception("Permissions insuffisantes",403);
- $dbPath = str_replace('\\','/',$element->path);
- if($element->type == 'directory'){
- //Si c'est un dossier, on récupere tous les élements commendant par ce nom afin de gerer leurs chemins
- $baseElement = Element::staticQuery('SELECT * FROM {{table}} WHERE `path` = ? OR `path` LIKE ?',array($dbPath,$dbPath.'/%'), true);
- } else {
- $baseElement = Element::load(array('path'=>$dbPath));
- if(is_object($baseElement) && $baseElement->id != 0) $element->id = $baseElement->id;
- }
- if(!File::copy($osPath,$osTo)) throw new Exception('Erreur lors de la copie...');
- $newelement = Element::fromPath($to);
- if(is_array($baseElement)){
- foreach ($baseElement as $elem) {
- if($elem->path == $dbPath) $elem->label = $element->label;
- $elem->path = str_replace($dbPath, $newelement->path, $elem->path);
- $elem->id = 0;
- $elem->save();
- }
- } else {
- $baseElement->path = $newelement->path;
- $baseElement->label = $newelement->label;
- $baseElement->id = 0;
- $baseElement->save();
- }
- }
- //Déplacement d'un répertoire ou d'un fichier en base et en physique
- public static function move($path,$to, $label=''){
- $osPath = File::convert_decoding($path);
- $osTo = File::convert_decoding($to);
- if(!file_exists($osPath)) return;
- $element = Element::fromPath($path);
- //Si le dossier se termine par un ., on supprime ce . (non pris en charge par l'os)
- if($element->type=="directory" && substr($to, -1,1) =='.')
- $to = substr($to, 0,strlen($to)-1);
- if($to == $path) return $element;
- if(!self::hasRight($element,'edit')) throw new Exception("Permissions insuffisantes",403);
- $parentPathTo = dirname($to);
- $parentPathOsTo = dirname($osTo);
- if(!file_exists($parentPathOsTo)) throw new Exception("Dossier de destination inexistant",404);
- $parentTo = Element::fromPath($parentPathTo);
- if(!self::hasRight($parentTo,'edit')) throw new Exception("Permissions insuffisantes",403);
- $dbPath = str_replace('\\','/',$element->path);
- if(file_exists($osTo)) return false;
- if($element->type == 'directory'){
- $element->path = $oldPath = $element->path;
- //Si c'est un dossier, on récupere tous les élements commencant par ce nom afin de modifier leurs chemins
- $baseElement = Element::staticQuery('SELECT * FROM {{table}} WHERE `path` = ? OR `path` LIKE ?',array($dbPath,$dbPath.'/%'), true);
- } else {
- $baseElement = Element::load(array('path'=>$dbPath));
- if(is_object($baseElement) && $baseElement->id != 0) $element->id = $baseElement->id;
- }
- try {
- if(!rename($osPath,$osTo))
- throw new Exception('Un élément du même nom existe déjà.');
- } catch (Exception $e) {
- return false;
- }
- $toElement = Element::fromPath($to);
- //Si type est image, on supprime l'ancienne miniature
- if(in_array($element->extension, array('jpg','png','jpeg','gif','bmp')) && file_exists(self::root().'.thumbnails'.SLASH.base64_encode($element->path).'.'.$element->extension))
- unlink(self::root().'.thumbnails'.SLASH.base64_encode($element->path).'.'.$element->extension);
- if(is_array($baseElement)){
- foreach ($baseElement as $elem) {
- if($elem->path == $oldPath)
- $elem->label = $toElement->label;
- $elem->path = str_replace($dbPath, $toElement->path, $elem->path);
- $elem->save();
- }
- } else {
- $baseElement->path = $toElement->path;
- $baseElement->label = $toElement->label;
- $baseElement->save();
- }
- return $toElement;
- }
- //Supprime les caractères interdits ou non utf8 (ex le "’" de word )
- public static function convertName($name){
- $name = iconv("UTF-8","UTF-8//IGNORE",$name);
- $name = str_replace(array('’','»','«'), array("'",'"','"'), $name);
- return $name;
- }
- //Ajout d'un fichier en base et en physique (prend de l'utf8 en entré pour le path)
- public static function addFile($path,$stream){
- //on filtre les noms non utf8 ou interdits
- $path = dirname($path).SLASH.self::convertName(basename($path));
- //on enregistre le fichier dans l'encodage du système
- $osPath = File::convert_decoding($path);
- $parentPath = dirname($path);
- $parentOsPath = File::convert_decoding($parentPath);
- if(!file_exists($parentOsPath)) throw new Exception("Dossier de destination inexistant",404);
- $parent = Element::fromPath($parentPath);
- if(!self::hasRight($parent,'edit')) throw new Exception("Permissions insuffisantes",403);
- file_put_contents($osPath, $stream);
- $element = Element::fromPath($path, array('preview'=>false));
- if(!self::hasRight($element,'edit')) throw new Exception("Permissions insuffisantes",403);
- $element->save();
- return $element;
- }
- //Ajout d'un dossier en base et en physique (prend de l'utf8 en entré pour le path)
- public static function addFolder($path, $recursive = false, $checkRight=true, $creator = null){
- //on filtre les noms non utf8 ou interdits
- $path = dirname($path).SLASH.self::convertName(basename($path));
- $osPath = File::convert_decoding($path);
- $parentPath = dirname($path);
- $osParentPath = dirname($osPath);
- if(!file_exists($osParentPath)) {
- if(!$recursive){
- throw new Exception("Dossier parent ".$parentPath." inexistant",404);
- } else {
- self::addFolder($parentPath, $recursive, $checkRight, $creator);
- }
- }
- $parent = Element::fromPath($parentPath);
- if($checkRight && !self::hasRight($parent,'edit')) throw new Exception("Permissions insuffisantes",403);
- if(file_exists($osPath)) return;
- mkdir($osPath,0755,$recursive);
- $element = Element::fromPath($path);
- if(isset($creator)) $element->creator = $creator;
- $element->save();
- return $element;
- }
- public static function hasRight($element,$type){
- global $myUser,$myFirm;
- require_once(__DIR__.SLASH.'ElementRight.class.php');
- $documentRight = '';
- switch($type){
- case 'read':
- $documentRight = 'read';
- break;
- case 'delete':
- case 'edit':
- $documentRight = 'edit';
- break;
- }
- if(!$myUser->can('document',$type)) return false;
- if($myUser->login == $element->creator || $myUser->can('document','configure') || $myUser->superadmin == 1) return true;
- $allPathes = array();
- $rootPath = '';
- foreach (explode('/',$element->path) as $i=>$crumb) {
- $rootPath .= ($i==0?'':'/').$crumb;
- $allPathes[] = $rootPath;
- }
- $userRanks = array();
- foreach ($myUser->ranks[$myFirm->id] as $rank)
- $userRanks[] = $rank->id;
- $data = array();
- $query = 'SELECT dr.recursive,dr.edit,dr.read,de.path
- FROM {{table}} dr
- LEFT JOIN '.Element::tableName().' de ON de.id = dr.element
- WHERE dr.element IN(
- SELECT id
- FROM '.Element::tableName().'
- WHERE path IN ('.str_repeat('?,',count($allPathes)-1).'?)
- ) AND (dr.entity=? OR (dr.entity=? AND dr.uid=?) ';
- $data = array_merge($allPathes, array("all","user",$myUser->login));
- if(count($userRanks)!=0){
- $query .= ' OR (dr.entity=? AND dr.uid IN ('.str_repeat('?,',count($userRanks)-1).'?)) ';
- $data = array_merge($data,array("rank"),$userRanks);
- }
- $query .= ') ORDER BY CHAR_LENGTH(de.path)';
- $result = ElementRight::staticQuery($query,$data);
- $rights = array(
- 'edit'=> false,
- 'read'=> false
- );
- foreach($result->fetchAll() as $line){
- //si le droit n'est pas récursif et que le chemin associé n'est pas exactement cleui ciblé on ignore ce droit
- if($line['recursive'] != 1 && $line['path']!=$element->path) continue;
- if($line['edit'] == 1) $rights['edit'] = true;
- if($line['read'] == 1) $rights['read'] = true;
- }
- if(!$rights[$type]) return false;
- return true;
- }
- public static function remove_dir_recursive($path) {
- //Fix glob et utilisation d'un dossier avec des [] (glob utilise ce char pour de la regex, on doit escape)
- $globPath = $path.SLASH.'{,.}*';
- $globPath = str_replace(array('[',']'),array('\[','\]'), $globPath);
- $globPath = str_replace(array('\[','\]'), array('[[]','[]]'), $globPath);
- foreach(glob($globPath,GLOB_BRACE) as $element){
- if(mt_basename($element) == '.' || mt_basename($element) == '..') continue;
- if(is_dir($element)) {
- self::remove_dir_recursive($element);
- } else {
- unlink($element);
- }
- }
- rmdir($path);
- }
- }
- ?>
|