Element.class.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. <?php
  2. /**
  3. * Define a fileor directory element.
  4. * @author Valentin CARRUESCO
  5. * @category Plugin
  6. * @license copyright
  7. */
  8. class Element extends Entity{
  9. public $id,$path,$label,$type,$extension,$size,$creatorSite,$icon,$thumbnail,$childNumber;
  10. protected $TABLE_NAME = 'document_element';
  11. public $fields =
  12. array(
  13. 'id' => 'key',
  14. 'path' => 'longstring',
  15. 'label' => 'string',
  16. 'type' => 'string',
  17. 'extension' => 'string',
  18. 'size' => 'string',
  19. 'creatorSite' => 'int'
  20. );
  21. //Récupération de la racine de la GED
  22. public static function root(){
  23. return File::dir().'documents'.SLASH;
  24. }
  25. public function save(){
  26. $this->path = str_replace('\\','/',$this->path);
  27. parent::save();
  28. }
  29. //Récuperation du chemin ou du flux de thumbnail associé à l'élement
  30. public function thumbnail(){
  31. if(!in_array($this->extension, array('jpg','png','jpeg','gif','bmp'))) return $this->icon();
  32. if(!file_exists(self::root().'.thumbnails')) mkdir(self::root().'.thumbnails',755,true);
  33. $thumbname = str_replace(array('\\','./'),array('/',''),$this->path);
  34. $thumbnail = self::root().'.thumbnails'.SLASH.base64_encode($thumbname).'.'.$this->extension;
  35. if(!file_exists($thumbnail)){
  36. $osPath = File::convert_decoding($this->path);
  37. copy(self::root().$osPath,$thumbnail);
  38. Image::resize($thumbnail,200,200);
  39. }
  40. $path ='data:image/'.$this->extension.';base64,'.base64_encode(file_get_contents($thumbnail));
  41. return $path;
  42. }
  43. //Récuperation du chemin di'one à l'élement
  44. public function icon(){
  45. $path = 'plugin/document/img/file-types/';
  46. $icon = $this->type == 'directory' ? 'folder.svg' : 'document.svg';
  47. switch($this->extension){
  48. case 'docx':
  49. case 'doc':
  50. case 'dot':
  51. case 'dotx':
  52. $icon = 'word.svg';
  53. break;
  54. case 'xls':
  55. case 'xlsx':
  56. case 'csv':
  57. $icon = 'excel.svg';
  58. break;
  59. case 'ppt':
  60. case 'pptx':
  61. $icon = 'powerpoint.svg';
  62. break;
  63. case 'pdf':
  64. $icon = 'pdf.svg';
  65. break;
  66. case 'mp3':
  67. case 'wav':
  68. case 'mp4':
  69. case 'flac':
  70. $icon = 'music.svg';
  71. break;
  72. case 'html':
  73. case 'htm':
  74. $icon = 'url.svg';
  75. break;
  76. case 'msg':
  77. $icon = 'mail.svg';
  78. break;
  79. case 'psd':
  80. $icon = 'photoshop.svg';
  81. break;
  82. case 'rss':
  83. $icon = 'feed.svg';
  84. break;
  85. case 'mdb':
  86. $icon = 'access.svg';
  87. break;
  88. case 'bat':
  89. case 'sh':
  90. case 'cmd':
  91. $icon = 'gear.svg';
  92. break;
  93. case 'php':
  94. case 'js':
  95. case 'java':
  96. case 'class':
  97. case 'css':
  98. case 'c':
  99. case 'cpp':
  100. case 'py':
  101. $icon = 'code.svg';
  102. break;
  103. case 'jpg':
  104. case 'jpeg':
  105. case 'png':
  106. case 'bmp':
  107. case 'gif':
  108. case 'svg':
  109. $icon = 'image.svg';
  110. break;
  111. }
  112. $path .= $icon;
  113. return $path;
  114. }
  115. //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é)
  116. public static function fromPath($path){
  117. global $conf;
  118. $element = new self();
  119. //convertion utf8 ISO-8859-1
  120. $osPath = File::convert_decoding($path);
  121. $infos = pathinfo($path);
  122. //Gestion label
  123. $element->label = mt_basename($path);
  124. $element->path = str_replace(self::root(),'',$path);
  125. $element->type = is_dir($osPath) ? 'directory' : 'file';
  126. $exists = file_exists($osPath);
  127. if($element->type == 'directory'){
  128. $path .= SLASH;
  129. $fi = new FilesystemIterator($osPath, FilesystemIterator::SKIP_DOTS);
  130. $element->childNumber = iterator_count($fi);
  131. $element->size = 0;
  132. } else {
  133. if(isset($infos['extension'])) $element->extension = $infos['extension'];
  134. $element->size = !$exists ? 0 : filesize($osPath);
  135. }
  136. $element->updated = !$exists ? 0 : filemtime($osPath);
  137. $element->created = !$exists ? 0 : filectime($osPath);
  138. $relativePath = trim(str_replace(Element::root(),'',$path),SLASH);
  139. if ($baseElement = Element::load(array('path'=>str_replace('\\','/',$relativePath) ))) {
  140. $element->creator = $baseElement->creator;
  141. $element->id = $baseElement->id;
  142. }
  143. $element->path = trim($element->path,SLASH);
  144. return $element;
  145. }
  146. //Récuperation de la liste des élements d'un repertoire (tiens compte des droits utilisateur) (attends de l'utf8)
  147. public static function browse($scanned,$folderOnly = false){
  148. global $myUser,$myFirm;
  149. require_once(__DIR__.SLASH.'ElementRight.class.php');
  150. $osScanned = File::convert_decoding($scanned);
  151. $elements = array();
  152. User::check_access('document','read');
  153. $toCheck = array();
  154. //Récuperation du tableau des rang utilisateur sous forme d'id.
  155. $ranks = array();
  156. if(!$myUser->superadmin){
  157. foreach($myUser->ranks[$myFirm->id] as $rank)
  158. $ranks[] = $rank->id;
  159. }
  160. $existingPathes = array();
  161. //Pour chaque fichier physique existant
  162. foreach(glob($osScanned) as $osPath){
  163. $osPath = str_replace(SLASH.'.'.SLASH, SLASH, $osPath);
  164. $basePath = File::convert_encoding($osPath);
  165. if((substr(mt_basename($osPath), 0,1)=='.') || ($folderOnly && !is_dir($osPath))) continue;
  166. //Récuperation/création de l'element objet correspondant (frompath n'accepte que l'utf8, on lui donne le basepath)
  167. $line = Element::fromPath($basePath);
  168. $existingPathes[] = $line->path;
  169. //Si l'element correspondant n'existe pas en base, on le créé
  170. if($line->id == ''){
  171. $line->creator = 'anonymous';
  172. $line->save();
  173. }
  174. //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
  175. if($myUser->login != $line->creator && !$myUser->can('document','configure') && !$myUser->superadmin){
  176. $can = false;
  177. $pathes = array();
  178. $path = '';
  179. //Récuperation des chemins dont on doit récuperer les droits :
  180. // ex : pour le fichier a/b/c les chemins sont a, a/b, et a/b/c
  181. foreach(explode(SLASH,$line->path) as $i=>$pathCrumb){
  182. if($i!=0) $path.= SLASH;
  183. $path.= $pathCrumb;
  184. $pathes[] = str_replace("\\","\\\\",$path);
  185. }
  186. //On récupere les droits pour chaques chemin
  187. 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
  188. ( er.entity="all" OR (er.entity="user" AND er.uid=?) OR (er.entity="rank" AND er.uid IN ('.implode(',',$ranks).') ) )
  189. AND element IN(SELECT id from '.Element::tableName().' WHERE path IN ("'.implode('","',$pathes).'")) ',array($myUser->login),true,1) as $right){
  190. $element = $right->join('element');
  191. //Si les droits sont sur un dossier parent et son recursif OU si les droits sont sur le fichier concerné on continue la verification
  192. if($right->element == $line->id || ($right->recursive && strpos($line->path, $element->path)!==false ) )
  193. $can = true;
  194. }
  195. if(!$can) continue;
  196. }
  197. $elements[] = $line;
  198. }
  199. //Element::staticQuery('SELECT * FROM {{table}} WHERE `path` NOT IN ("'.implode('","',$existingPathes).'") ');
  200. return $elements;
  201. }
  202. //Téléchargement d'un fichier ou d'un repertoire (prends de l'utf 8 en entrée)
  203. public static function download($path){
  204. $osPath = File::convert_decoding($path);
  205. if(!file_exists($osPath)) return '';
  206. $element = Element::fromPath($path);
  207. if(!self::hasRight($element,'read')) throw new Exception("Permissions insuffisantes",403);
  208. if(is_dir($osPath)){
  209. $filename = rand().'-'.time().'.zip';
  210. $filepath = sys_get_temp_dir().SLASH.$filename;
  211. $zip = new ZipArchive;
  212. $res = $zip->open($filepath, ZipArchive::CREATE);
  213. if ($res === TRUE) {
  214. $ressources = glob_recursive($osPath.SLASH.'*') ;
  215. foreach($ressources as $i=>$resource){
  216. if(is_dir($resource)) continue;
  217. $filename = $resource;
  218. $filename = File::convert_encoding($filename);
  219. $filename = str_replace($path,mt_basename($path),$filename);
  220. $filename=iconv("UTF-8", "IBM850", $filename);
  221. if(!$zip->addFromString($filename, file_get_contents($resource))) throw new Exception("Impossible de compresser le fichier ".$path);
  222. }
  223. if(count($ressources)==0)
  224. $zip->addEmptyDir('.');
  225. $zip->close();
  226. }
  227. $stream = file_get_contents($filepath);
  228. unlink($filepath);
  229. }else{
  230. $stream = file_get_contents($osPath);
  231. }
  232. return $stream;
  233. }
  234. //Supression d'un répértoire ou d'un fichier en base et en physique (prends de l'utf 8 en entrée)
  235. public static function remove($path){
  236. global $myUser,$myFirm;
  237. require_once(__DIR__.SLASH.'ElementRight.class.php');
  238. $osPath = File::convert_decoding($path);
  239. if(!file_exists($osPath)) return;
  240. $element = Element::fromPath($path);
  241. $dbPath = str_replace('\\','/',$element->path);
  242. if(!self::hasRight($element,'edit')) throw new Exception("Permissions insuffisantes",403);
  243. if(is_dir($osPath)) {
  244. self::remove_dir_recursive($osPath);
  245. Element::staticQuery('DELETE FROM {{table}} WHERE `path` = ? OR `path` LIKE ?',array($dbPath,$dbPath.'/%'));
  246. } else {
  247. unlink($osPath);
  248. Element::delete(array('path'=>$dbPath));
  249. }
  250. ElementRight::delete(array('element'=>$element->id));
  251. }
  252. //Copie d'un répértoire ou d'un fichier en base et en physique (prends de l'utf 8 en entrée)
  253. public static function copy($path,$to){
  254. global $conf, $myUser;
  255. $osPath = File::convert_decoding($path);
  256. $osTo = File::convert_decoding($to);
  257. if(!file_exists($osPath)) return;
  258. $element = Element::fromPath($path);
  259. if(file_exists($osTo)) return false;
  260. $parentPathTo = dirname($to);
  261. $parentOsPathTo = dirname($osTo);
  262. if(!file_exists($parentOsPathTo)) throw new Exception("Dossier de destination inexistant",404);
  263. $parentTo = Element::fromPath($parentPathTo);
  264. if(!self::hasRight($parentTo,'read')) throw new Exception("Permissions insuffisantes",403);
  265. if(!self::hasRight($element,'read')) throw new Exception("Permissions insuffisantes",403);
  266. $dbPath = str_replace('\\','/',$element->path);
  267. if($element->type == 'directory'){
  268. $element->path = $element->path;
  269. //Si c'est un dossier, on récupere tous les élements commendant par ce nom afin de gerer leurs chemins
  270. $baseElement = Element::staticQuery('SELECT * FROM {{table}} WHERE `path` = ? OR `path` LIKE ?',array($dbPath,$dbPath.'/%'), true);
  271. } else {
  272. $baseElement = Element::load(array('path'=>$dbPath));
  273. if(is_object($baseElement) && $baseElement->id != 0) $element->id = $baseElement->id;
  274. }
  275. if(!copy($osPath,$osTo)) throw new Exception('Erreur lors de la copie...');
  276. $newelement = Element::fromPath($to);
  277. if(is_array($baseElement)){
  278. foreach ($baseElement as $elem) {
  279. if($elem->path == $dbPath) $elem->label = $element->label;
  280. $elem->path = str_replace($dbPath, $newelement->path, $elem->path);
  281. $elem->id = 0;
  282. $elem->save();
  283. }
  284. } else {
  285. $baseElement->path = $newelement->path;
  286. $baseElement->label = $newelement->label;
  287. $baseElement->id = 0;
  288. $baseElement->save();
  289. }
  290. }
  291. //Déplacement d'un répertoire ou d'un fichier en base et en physique
  292. public static function move($path,$to, $label=''){
  293. global $conf, $myUser;
  294. $osPath = File::convert_decoding($path);
  295. $osTo = File::convert_decoding($to);
  296. if(!file_exists($osPath)) return;
  297. $element = Element::fromPath($path);
  298. //Si le dossier se termine par un ., on supprime ce . (non pris en charge par l'os)
  299. if($element->type=="directory" && substr($to, -1,1) =='.')
  300. $to = substr($to, 0,strlen($to)-1);
  301. if($to == $path) return $element;
  302. if(!self::hasRight($element,'edit')) throw new Exception("Permissions insuffisantes",403);
  303. $parentPathTo = dirname($to);
  304. $parentPathOsTo = dirname($osTo);
  305. if(!file_exists($parentPathOsTo)) throw new Exception("Dossier de destination inexistant",404);
  306. $parentTo = Element::fromPath($parentPathTo);
  307. if(!self::hasRight($parentTo,'read')) throw new Exception("Permissions insuffisantes",403);
  308. $dbPath = str_replace('\\','/',$element->path);
  309. if(file_exists($osTo)) return false;
  310. if($element->type == 'directory'){
  311. $element->path = $oldPath = $element->path;
  312. //Si c'est un dossier, on récupere tous les élements commencant par ce nom afin de modifier leurs chemins
  313. $baseElement = Element::staticQuery('SELECT * FROM {{table}} WHERE `path` = ? OR `path` LIKE ?',array($dbPath,$dbPath.'/%'), true);
  314. } else {
  315. $baseElement = Element::load(array('path'=>$dbPath));
  316. if(is_object($baseElement) && $baseElement->id != 0) $element->id = $baseElement->id;
  317. }
  318. try {
  319. if(!rename($osPath,$osTo))
  320. throw new Exception('Un élément du même nom existe déjà.');
  321. } catch (Exception $e) {
  322. return false;
  323. }
  324. $toElement = Element::fromPath($to);
  325. //Si type est image, on supprime l'ancienne miniature
  326. if(in_array($element->extension, array('jpg','png','jpeg','gif','bmp')) && file_exists(self::root().'.thumbnails'.SLASH.base64_encode($element->path).'.'.$element->extension))
  327. unlink(self::root().'.thumbnails'.SLASH.base64_encode($element->path).'.'.$element->extension);
  328. if(is_array($baseElement)){
  329. foreach ($baseElement as $elem) {
  330. if($elem->path == $oldPath)
  331. $elem->label = $toElement->label;
  332. $elem->path = str_replace($dbPath, $toElement->path, $elem->path);
  333. $elem->save();
  334. }
  335. } else {
  336. $baseElement->path = $toElement->path;
  337. $baseElement->label = $toElement->label;
  338. $baseElement->save();
  339. }
  340. return $toElement;
  341. }
  342. //Ajout d'un fichier en base et en physique (prend de l'utf8 en entré pour le path)
  343. public static function addFile($path,$stream){
  344. //on enregistre le fichier dans l'encodage du système
  345. $osPath = File::convert_decoding($path);
  346. $parentPath = dirname($path);
  347. $parentOsPath = File::convert_decoding($parentPath);
  348. if(!file_exists($parentOsPath)) throw new Exception("Dossier de destination inexistant",404);
  349. $parent = Element::fromPath($parentPath);
  350. if(!self::hasRight($parent,'read')) throw new Exception("Permissions insuffisantes",403);
  351. file_put_contents($osPath, $stream);
  352. $element = Element::fromPath($path, array('preview'=>false));
  353. $element->save();
  354. return $element;
  355. }
  356. //Ajout d'un dossier en base et en physique (prend de l'utf8 en entré pour le path)
  357. public static function addFolder($path, $recursive = false, $checkRight=true, $creator = null){
  358. $osPath = File::convert_decoding($path);
  359. $parentPath = dirname($path);
  360. $osParentPath = dirname($osPath);
  361. if(!file_exists($osParentPath)) {
  362. if(!$recursive){
  363. throw new Exception("Dossier parent ".$parentPath." inexistant",404);
  364. } else {
  365. self::addFolder($parentPath, $recursive, $checkRight, $creator);
  366. }
  367. }
  368. $parent = Element::fromPath($parentPath);
  369. if($checkRight && !self::hasRight($parent,'read')) throw new Exception("Permissions insuffisantes",403);
  370. if(file_exists($osPath)) return;
  371. mkdir($osPath,0755,$recursive);
  372. $element = Element::fromPath($path);
  373. if(isset($creator)) $element->creator = $creator;
  374. $element->save();
  375. return $element;
  376. }
  377. public static function hasRight($element,$type){
  378. global $myUser,$myFirm;
  379. require_once(__DIR__.SLASH.'ElementRight.class.php');
  380. $documentRight = '';
  381. switch($type){
  382. case 'read':
  383. $documentRight = 'read';
  384. break;
  385. case 'delete':
  386. $documentRight = 'edit';
  387. break;
  388. case 'edit':
  389. $documentRight = 'edit';
  390. break;
  391. }
  392. if(!$myUser->can('document',$type)) return false;
  393. if($myUser->login == $element->creator || $myUser->can('document','configure') || $myUser->superadmin == 1) return true;
  394. $allPathes = array();
  395. $rootPath = '';
  396. foreach (explode(SLASH,$element->path) as $i=>$crumb) {
  397. $rootPath .= ($i==0?'':SLASH).$crumb;
  398. $allPathes[] = str_replace("\\","\\\\",$rootPath);
  399. }
  400. $userRanks = array();
  401. foreach ($myUser->ranks[$myFirm->id] as $rank)
  402. $userRanks[] = $rank->id;
  403. $query = 'SELECT COUNT(id) allowed FROM {{table}} WHERE (element IN(SELECT id from '.Element::tableName().' WHERE path IN("'.implode('","',$allPathes).'")) AND `'.$documentRight.'`=1) AND (entity="all" OR (entity="user" AND uid=?) ';
  404. if(count($userRanks)!=0) $query .= ' OR (entity="rank" AND uid IN('.implode(',',$userRanks).')) ';
  405. $query .= ')';
  406. $result = ElementRight::staticQuery($query,array($myUser->login));
  407. $result = $result->fetch();
  408. if(!$result || $result['allowed']<=0) return false;
  409. return true;
  410. }
  411. public static function remove_dir_recursive($path) {
  412. foreach(glob($path.SLASH.'*') as $element){
  413. if(mt_basename($element) == '.' || mt_basename($element) == '..') continue;
  414. if(is_dir($element)) {
  415. self::remove_dir_recursive($element);
  416. } else {
  417. unlink($element);
  418. }
  419. }
  420. rmdir($path);
  421. }
  422. }
  423. ?>