PageRenderTime 42ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/j/kfm/classes/kfmDirectory.php

http://kv-webme.googlecode.com/
PHP | 363 lines | 329 code | 1 blank | 33 comment | 92 complexity | cd1db29195ee0e84ead4bd06eefa34fc MD5 | raw file
Possible License(s): LGPL-3.0, GPL-2.0, BSD-3-Clause, BSD-2-Clause, Apache-2.0, MIT, LGPL-2.1
  1. <?php
  2. class kfmDirectory extends kfmObject{
  3. static $instances=array();
  4. var $subDirs=array();
  5. private $maxWidth;
  6. private $maxHeight;
  7. public $relpath = false; // Cache for path relative to kfm root
  8. public $relpath_user = false; // Cache for path relative to user root
  9. function __construct($id=1){
  10. parent::__construct();
  11. $this->id=$id;
  12. if(!$id)return;
  13. $res=db_fetch_row("SELECT * FROM ".KFM_DB_PREFIX."directories WHERE id=".$this->id);
  14. if(!$res)return $this->id=0;
  15. $this->name=$res['name'];
  16. $this->pid=(int)$res['parent'];
  17. $this->maxWidth=(int)$res['maxwidth'];
  18. $this->maxHeight=(int)$res['maxheight'];
  19. }
  20. function addFile($file){
  21. if(!$GLOBALS['kfm']->setting('allow_file_create'))return $this->error(kfm_lang('permissionDeniedCreateFile'));
  22. if(is_numeric($file))$file=kfmFile::getInstance($file);
  23. if(!$this->isWritable())return $this->error(kfm_lang('fileNotCreatedDirUnwritable',$file->name));
  24. copy($file->path,$this->path().'/'.$file->name);
  25. $id=$file->addToDb($file->name,$this->id);
  26. if($file->isImage()){
  27. $file=kfmImage::getInstance($file->id);
  28. $newFile=kfmImage::getInstance($id);
  29. $newFile->setCaption($file->caption);
  30. if($this->maxWidth>0 && $this->maxHeight>0 && ($newFile->width>$this->maxWidth || $newFile->height>$this->maxHeight)){
  31. $newFile->resize($this->maxWidth,$this->maxHeight);
  32. }
  33. }
  34. else $newFile=kfmFile::getInstance($id);
  35. $newFile->setTags($file->getTags());
  36. return true;
  37. }
  38. function addSubdirToDb($name){
  39. $sql="INSERT INTO ".KFM_DB_PREFIX."directories (name,parent) VALUES('".sql_escape($name)."',".$this->id.")";
  40. $GLOBALS['kfm']->db->exec($sql);
  41. return $GLOBALS['kfm']->db->lastInsertId(KFM_DB_PREFIX.'directories','id');
  42. }
  43. function checkAddr($addr){
  44. return (
  45. strpos($addr,'..')===false&&
  46. strpos($addr,'.')!==0&&
  47. strpos($addr,'/.')===false);
  48. }
  49. function checkName($file=false){
  50. if($file===false)$file=$this->name;
  51. if(trim($file)==''|| trim($file)!=$file)return false;
  52. if($file=='.'||$file=='..')return false;
  53. foreach($GLOBALS['kfm']->setting('banned_folders') as $ban){
  54. if(($ban[0]=='/' || $ban[0]=='@')&&preg_match($ban,$file))return false;
  55. elseif($ban==strtolower(trim($file)))return false;
  56. }
  57. if(count($GLOBALS['kfm']->setting('allowed_folders'))){
  58. foreach($GLOBALS['kfm']->setting('allowed_folders') as $allow){
  59. if($allow[0]=='/' || $allow[0]=='@'){
  60. if(preg_match($allow, $file))return true;
  61. }else if($allow==strtolower($file)) return true;
  62. }
  63. return false;
  64. }
  65. return true;
  66. }
  67. function createSubdir($name){
  68. if(!$GLOBALS['kfm']->setting('allow_directory_create'))return $this->error(kfm_lang('permissionDeniedCreateDirectory'));
  69. $physical_address=$this->path().$name;
  70. $short_version=str_replace($GLOBALS['rootdir'],'',$physical_address);
  71. if(!$this->checkAddr($physical_address) || !$this->checkName($name)){
  72. $this->error(kfm_lang('illegalDirectoryName',$short_version));
  73. return false;
  74. }
  75. if(file_exists($physical_address)){
  76. $this->error(kfm_lang('alreadyExists',$short_version));
  77. return false;
  78. }
  79. mkdir($physical_address);
  80. if(!file_exists($physical_address)){
  81. $this->error(kfm_lang('failedCreateDirectoryCheck',$name));
  82. return false;
  83. }
  84. chmod($physical_address,octdec('0'.$GLOBALS['kfm']->setting('default_directory_permission')));
  85. return $this->addSubdirToDb($name);
  86. }
  87. function delete(){
  88. if(!$GLOBALS['kfm']->setting('allow_directory_delete'))return $this->error(kfm_lang('permissionDeniedDeleteDirectory'));
  89. $files=$this->getFiles();
  90. foreach($files as $f){
  91. if(!$f->delete())return false;
  92. }
  93. $subdirs=$this->getSubdirs();
  94. foreach($subdirs as $subdir){
  95. if(!$subdir->delete())return false;
  96. }
  97. rmdir($this->path());
  98. if(is_dir($this->path()))return $this->error('failed to delete directory '.$this->path());
  99. $GLOBALS['kfm']->db->exec("delete from ".KFM_DB_PREFIX."directories where id=".$this->id);
  100. return true;
  101. }
  102. function exists(){
  103. return (file_exists($this->path()) && is_dir($this->path()));
  104. }
  105. function getCssSprites(){
  106. $groupby=16;
  107. $thumbsize=64;
  108. $files=$this->getFiles();
  109. $images=array();
  110. $i=-1;
  111. $j=0;
  112. if(!is_dir(WORKPATH.'css_sprites'))mkdir(WORKPATH.'css_sprites');
  113. foreach($files as $file){
  114. if(!$file->isImage() || !$file->thumb_path)continue;
  115. if(!($j%$groupby)){
  116. $i++;
  117. $images[$i]=array();
  118. $j=0;
  119. }
  120. $images[$i][$j]=$file->id;
  121. $j++;
  122. }
  123. $sprites=array();
  124. foreach($images as $igroup){
  125. $md5=md5($this->id.'_'.join(',',$igroup));
  126. $sprites[]=array('sprite'=>$md5,'files'=>$igroup);
  127. if(!file_exists(WORKPATH.'css_sprites/'.$md5.'.png')){
  128. $thumbs=array();
  129. for($i=0;$i<count($igroup);++$i){
  130. $fid=$igroup[$i];
  131. $file=kfmFile::getInstance($fid);
  132. $file->setThumbnail($thumbsize,$thumbsize);
  133. $thumbs[]="'".$file->thumb_path."'";
  134. }
  135. $cli=dirname(IMAGEMAGICK_PATH)."/montage -background transparent -geometry $thumbsize".'x'."$thumbsize -tile $groupby"."x1 ".join(' ',$thumbs).' '.WORKPATH.'css_sprites/'.$md5.'.png';
  136. $arr=array();
  137. exec($cli,$arr,$retval);
  138. }
  139. }
  140. return $sprites;
  141. }
  142. function getFiles(){
  143. $filesdb=db_fetch_all("select * from ".KFM_DB_PREFIX."files where directory=".$this->id);
  144. $fileshash=array();
  145. if(is_array($filesdb))foreach($filesdb as $r)$fileshash[$r['name']]=$r['id'];
  146. // { get files from directoryIterator, then sort them
  147. $tmp=array();
  148. if(file_exists($this->path()) && is_dir($this->path())) {
  149. foreach(new directoryIterator($this->path()) as $f){
  150. if($f->isDot())continue;
  151. if(is_file($this->path().$f) && @kfmFile::checkName($f))$tmp[]=$f.'';
  152. }
  153. }
  154. natsort($tmp);
  155. // }
  156. // { load file details from database
  157. $files=array();
  158. foreach($tmp as $filename){
  159. if (!isset($fileshash[$filename])) {
  160. $fileshash[$filename]=@kfmFile::addToDb($filename,$this->id);
  161. }
  162. $file=kfmFile::getInstance($fileshash[$filename]);
  163. if(!$file)continue;
  164. if($file->isImage()){
  165. $file=kfmImage::getInstance($fileshash[$filename]);
  166. if($this->maxWidth>0 && $this->maxHeight>0 && ($file->width>$this->maxWidth || $file->height>$this->maxHeight)){
  167. $file->resize($this->maxWidth,$this->maxHeight);
  168. }
  169. }
  170. $files[]=$file;
  171. unset($fileshash[$filename]);
  172. }
  173. // }
  174. return $files;
  175. }
  176. static function getInstance($id=1){
  177. $id=(int)$id;
  178. if($id<1)return;
  179. if (!array_key_exists($id,self::$instances)) {
  180. $dir=new kfmDirectory($id);
  181. if($dir->id==0)return false;
  182. self::$instances[$id]=$dir;
  183. }
  184. return self::$instances[$id];
  185. }
  186. /**
  187. Full path of directory
  188. */
  189. function getPath(){
  190. $pathTmp=$this->name.'/';
  191. $pid=$this->pid;
  192. if(!$pid)return $GLOBALS['rootdir'];
  193. while($pid>1){
  194. $p=kfmDirectory::getInstance($pid);
  195. if($p==false)return 'non-existing-directory';
  196. $pathTmp=$p->name.'/'.$pathTmp;
  197. $pid=$p->pid;
  198. }
  199. return file_join($GLOBALS['kfm']->files_root_path, $pathTmp);
  200. }
  201. /**
  202. * At the moment the path property is loaded for every directory instance. Maybe this is not required.
  203. * A cached function should be more efficient for the future. Therefor every $dir->path call should be
  204. * replaced by $dir->path();
  205. */
  206. function path(){
  207. if(!isset($this->cached_path) || !$this->cached_path) $this->cached_path = $this->getPath();
  208. return $this->cached_path;
  209. }
  210. /**
  211. Path of directory relative to root.
  212. If $to_user_root is set to true, support for custom root folders is activated.
  213. The $to_user_root option should not be used for file retrieval but solely for display purposes.
  214. */
  215. function relativePath($to_user_root = false){
  216. // Determin root_id and check for cashed path
  217. if($to_user_root){
  218. if($this->relpath_user) return $this->relpath_user;
  219. $root_id = $GLOBALS['kfm']->setting('root_folder_id');
  220. }else{
  221. if($this->relpath) return $this->relpath;
  222. $root_id = 1;
  223. }
  224. $pathTmp=''; // Return empty if we are the root folder
  225. $pid=$this->pid;
  226. if(!$pid)return $pathTmp;
  227. if($this->id == $root_id) return $pathTmp;
  228. $pathTmp = $this->name; // If not root, we need our name
  229. while($pid != $root_id ){
  230. $p=kfmDirectory::getInstance($pid);
  231. $pathTmp=$p->name.DIRECTORY_SEPARATOR.$pathTmp;
  232. $pid=$p->pid;
  233. }
  234. if($to_user_root){
  235. $this->relpath_user = $pathTmp;
  236. }else{
  237. $this->relpath = $pathTmp;
  238. }
  239. return $pathTmp;
  240. }
  241. function getProperties(){
  242. return array(
  243. 'allowed_file_extensions' => '',
  244. 'name' => $this->name,
  245. 'path' => $this->relativePath(), #str_replace($_SERVER['DOCUMENT_ROOT'],'',$this->path()),
  246. 'parent' => $this->pid,
  247. 'writable' => $this->isWritable(),
  248. 'maxWidth' => $this->maxWidth,
  249. 'maxHeight' => $this->maxHeight
  250. );
  251. }
  252. function getSubdir($dirname, $create_unless_exists = false){
  253. $res=db_fetch_row('select id from '.KFM_DB_PREFIX.'directories where name="'.sql_escape($dirname).'" and parent='.$this->id);
  254. if($res)return kfmDirectory::getInstance($res['id']);
  255. else if(is_dir($this->path().$dirname)){
  256. $id = $this->addSubdirToDb($dirname);
  257. return kfmDirectory::getInstance($id);
  258. }elseif($create_unless_exists){
  259. $id = $this->createSubdir($dirname);
  260. return kfmDirectory::getInstance($id);
  261. }
  262. return false;
  263. }
  264. function getSubdirs(){
  265. $dir_iterator=new DirectoryIterator($this->path());
  266. $dirsdb=db_fetch_all("select id,name from ".KFM_DB_PREFIX."directories where parent=".$this->id);
  267. $dirshash=array();
  268. if(is_array($dirsdb))foreach($dirsdb as $r)$dirshash[$r['name']]=$r['id'];
  269. $directories=array();
  270. foreach($dir_iterator as $file){
  271. if($file->isDot())continue;
  272. if(!$file->isDir())continue;
  273. $filename=$file->getFilename();
  274. if(is_dir($this->path().$filename)&&$this->checkName($filename)){
  275. if(!array_key_exists($filename,$dirshash)){
  276. $this->addSubdirToDb($filename);
  277. $dirshash[$filename]=$GLOBALS['kfm']->db->lastInsertId(KFM_DB_PREFIX.'directories','id');
  278. }
  279. $directories[]=kfmDirectory::getInstance($dirshash[$filename]);
  280. unset($dirshash[$filename]);
  281. }
  282. }
  283. return $directories;
  284. }
  285. function hasSubdirs(){
  286. $dirs=new DirectoryIterator($this->path());
  287. foreach($dirs as $dir){
  288. if($dir->isDot())continue;
  289. if($dir->isDir())return true;
  290. }
  291. return false;
  292. }
  293. function isWritable(){
  294. return is_writable($this->path());
  295. }
  296. function isLink(){
  297. return is_link($this->path());
  298. }
  299. function moveTo($newParent){
  300. if(is_numeric($newParent))$newParent=kfmDirectory::getInstance($newParent);
  301. // { check for errors
  302. if($this->isLink()) return $this->error(kfm_lang('cannotMoveLink'));
  303. if(!$GLOBALS['kfm']->setting('allow_directory_move'))return $this->error(kfm_lang('permissionDeniedMoveDirectory'));
  304. if(strpos($newParent->path(),$this->path())===0) return $this->error(kfm_lang('cannotMoveIntoSelf'));
  305. if(file_exists(file_join($newParent->path(),$this->name)))return $this->error(kfm_lang('alreadyExists',$newParent->path().$this->name));
  306. if(!$newParent->isWritable())return $this->error(kfm_lang('isNotWritable',$newParent->path()));
  307. // }
  308. // { do the move and check that it was successful
  309. rename(rtrim($this->path(), ' /'),$newParent->path().'/'.$this->name);
  310. if(!file_exists($newParent->path().$this->name))return $this->error(kfm_lang('couldNotMoveDirectory',$this->path(),$newParent->path().$this->name));
  311. // }
  312. // { update database and kfmDirectory object
  313. $GLOBALS['kfm']->db->query("update ".KFM_DB_PREFIX."directories set parent=".$newParent->id." where id=".$this->id) or die('error: '.print_r($GLOBALS['kfmdb']->errorInfo(),true));
  314. $this->pid=$newParent->id;
  315. $this->cached_path=$this->getPath();
  316. $this->clearCache();
  317. // }
  318. }
  319. function rename($newname){
  320. if(!$GLOBALS['kfm']->setting('allow_directory_edit'))return $this->error(kfm_lang('permissionDeniedEditDirectory'));
  321. if($this->isLink()) return $this->error(kfm_lang('cannotRenameLink'));
  322. if(!$this->isWritable())return $this->error(kfm_lang('permissionDeniedRename',$this->name));
  323. if(!$this->checkName($newname))return $this->error(kfm_lang('cannotRenameFromTo',$this->name,$newname));
  324. $parent=kfmDirectory::getInstance($this->pid);
  325. if(file_exists($parent->path().$newname))return $this->error(kfm_lang('aDirectoryNamedAlreadyExists',$newname));
  326. rename(rtrim($this->path(),' /'),file_join($parent->path(),rtrim($newname, ' /')));
  327. if(file_exists($this->path()))return $this->error(kfm_lang('failedRenameDirectory'));
  328. $GLOBALS['kfm']->db->query("update ".KFM_DB_PREFIX."directories set name='".sql_escape($newname)."' where id=".$this->id);
  329. $this->name=$newname;
  330. $this->cached_path=$this->path();
  331. $GLOBALS['kfmDirectoryInstances'][$this->id]=$this;
  332. }
  333. function setDirectoryMaxSizeImage($width=0,$height=0){
  334. $width=(int)$width;
  335. $height=(int)$height;
  336. if($width<0)$width=0;
  337. if($height<0)$height=0;
  338. if($width==$this->maxWidth && $height==$this->maxHeight)return;
  339. $this->maxWidth=$width;
  340. $this->maxHeight=$height;
  341. $GLOBALS['kfm']->db->exec("UPDATE ".KFM_DB_PREFIX."directories SET maxwidth=$width,maxheight=$height WHERE id=".$this->id);
  342. }
  343. /*
  344. * Return the max image height for the directory if set, the default otherwise
  345. */
  346. function maxHeight(){
  347. return $this->maxHeight > 0 ? $this->maxHeight : $GLOBALS['kfm']->setting('max_image_upload_height');
  348. }
  349. /*
  350. * Return the max image width for the directory if set, the default otherwise
  351. */
  352. function maxWidth(){
  353. return $this->maxWidth > 0 ? $this->maxWidth : $GLOBALS['kfm']->setting('max_image_upload_width');
  354. }
  355. /**
  356. Clear cashed properties
  357. */
  358. function clearCache(){
  359. $this->relpath = false; # remove relative path cache
  360. $this->relpath_user = false;
  361. }
  362. }