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

/ci_2.2.6_application/libraries/File_lib.php

https://github.com/dmcb/dmcb-cms
PHP | 441 lines | 287 code | 27 blank | 127 comment | 80 complexity | 2d225d4453cc8723b7e1835c4e36d5a3 MD5 | raw file
  1. <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
  2. /**
  3. * dmcb file library
  4. *
  5. * Initalizes a file and runs checks and operations on that file
  6. *
  7. * @package dmcb-cms
  8. * @author Derek McBurney
  9. * @copyright Copyright (c) 2011, Derek McBurney, derek@dmcbdesign.com
  10. * This code may not be used commercially without the expressed
  11. * written consent of Derek McBurney. Non-commercial use requires
  12. * attribution.
  13. * @link http://dmcbdesign.com
  14. */
  15. class File_lib {
  16. public $file = array();
  17. public $new_file = array();
  18. private $path;
  19. private $rootpath;
  20. private $folder;
  21. private $rootfolder;
  22. private $managed;
  23. /**
  24. * Constructor
  25. *
  26. * Grab CI
  27. *
  28. * @access public
  29. */
  30. function File_lib($params = NULL)
  31. {
  32. $this->CI =& get_instance();
  33. $this->CI->load->model('files_model');
  34. if (isset($params['id']))
  35. {
  36. $this->new_file = $this->CI->files_model->get($params['id']);
  37. $this->file = $this->new_file;
  38. $this->_initialize_paths();
  39. if (file_exists($this->path))
  40. {
  41. $this->_initialize_info();
  42. }
  43. }
  44. }
  45. // --------------------------------------------------------------------
  46. /**
  47. * Initialize info
  48. *
  49. * Set the date modified and file size properties
  50. *
  51. * @access private
  52. * @return void
  53. */
  54. function _initialize_info()
  55. {
  56. $this->CI->load->helper('file');
  57. $this->file['filesize'] = filesize($this->path);
  58. $this->file['filemodified'] = filemtime($this->path);
  59. $this->file['mimetype'] = get_mime_by_extension($this->path);
  60. }
  61. // --------------------------------------------------------------------
  62. /**
  63. * Initialize paths
  64. *
  65. * Set all the file path information
  66. *
  67. * @access private
  68. * @return void
  69. */
  70. function _initialize_paths()
  71. {
  72. $this->rootfolder = $this->file['attachedto'].'/';
  73. if ($this->new_file['attachedto'] == "page")
  74. {
  75. $object = instantiate_library('page', $this->new_file['attachedid']);
  76. // Convert nested file path of page to a flat folder structure internally
  77. $this->rootfolder .= str_replace('/', '+', $object->page['urlname']).'/';
  78. }
  79. else if ($this->new_file['attachedto'] == "post")
  80. {
  81. $object = instantiate_library('post', $this->new_file['attachedid']);
  82. // Convert nested file path of post to a flat folder structure internally
  83. $this->rootfolder .= str_replace('/', '+', $object->post['urlname']).'/';
  84. }
  85. else if ($this->new_file['attachedto'] == "user")
  86. {
  87. $object = instantiate_library('user', $this->new_file['attachedid']);
  88. $this->rootfolder .= $object->user['urlname'].'/';
  89. }
  90. $this->file['fullfilename'] = $this->new_file['filename'].'.'.$this->new_file['extension'];
  91. $this->rootpath = $this->rootfolder.$this->file['fullfilename'];
  92. // Ensure external URL given for the file is not a flat file path
  93. $this->file['urlpath'] = 'file/'.str_replace('+', '/', $this->rootpath);
  94. $this->managed;
  95. if (file_exists('files/'.$this->rootpath))
  96. {
  97. $this->path = 'files/'.$this->rootpath;
  98. $this->folder = 'files/'.$this->rootfolder;
  99. $this->managed = FALSE;
  100. }
  101. else if (file_exists('files_managed/'.$this->rootpath))
  102. {
  103. $this->path = 'files_managed/'.$this->rootpath;
  104. $this->folder = 'files_managed/'.$this->rootfolder;
  105. $this->managed = TRUE;
  106. }
  107. else // File doesn't exist, delete faulty database reference to it
  108. {
  109. $this->delete();
  110. }
  111. }
  112. // --------------------------------------------------------------------
  113. /**
  114. * Build search metadata
  115. *
  116. * Build text data file from non text file to use against searching
  117. *
  118. * @access private
  119. * @return void
  120. */
  121. function _build_search_metadata()
  122. {
  123. if ($this->file['extension'] == "pdf" && in_array('files', $this->CI->config->item('dmcb_search_types'))) //add more file type support in the future (i.e. office documents)
  124. {
  125. shell_exec('bin/pdftotext '.$this->path.' '.$this->path.'.searchmetadata');
  126. }
  127. }
  128. // --------------------------------------------------------------------
  129. /**
  130. * Clear cache
  131. *
  132. * Clear cached image resizes, search meta data, and possibly the whole folder if empty
  133. *
  134. * @access private
  135. * @return void
  136. */
  137. function _clear_cache()
  138. {
  139. if ($handle = opendir($this->folder))
  140. {
  141. while (false !== ($dirfile = readdir($handle)))
  142. {
  143. //if there is a file that has additional naming after filename.fileextension, delete it
  144. if (isset($this->file['fullfilename']) && strpos($dirfile, $this->file['fullfilename'].'.') === 0)
  145. {
  146. unlink($this->folder.$dirfile);
  147. }
  148. }
  149. closedir($handle);
  150. }
  151. //check if folder is empty, and if so, delete it
  152. $empty = TRUE;
  153. if ($handle = opendir($this->folder))
  154. {
  155. while (false !== ($dirfile = readdir($handle)))
  156. {
  157. if ($dirfile != "." && $dirfile != ".." )
  158. {
  159. $empty = FALSE;
  160. }
  161. }
  162. closedir($handle);
  163. }
  164. if ($empty)
  165. {
  166. rmdir($this->folder);
  167. }
  168. }
  169. // --------------------------------------------------------------------
  170. /**
  171. * Delete
  172. *
  173. * Delete a file and clears out references
  174. *
  175. * @access public
  176. * @return void
  177. */
  178. function delete()
  179. {
  180. if (file_exists($this->path))
  181. {
  182. unlink($this->path);
  183. $this->_clear_cache();
  184. }
  185. $this->CI->files_model->delete($this->file['fileid']);
  186. }
  187. // --------------------------------------------------------------------
  188. /**
  189. * Manage
  190. *
  191. * Moves a file to it's respective managed or unmanaged location
  192. *
  193. * @access public
  194. * @return void
  195. */
  196. function manage()
  197. {
  198. $this->_initialize_paths();
  199. $should_be_managed = $this->_manage_check();
  200. if ($should_be_managed != $this->managed)
  201. {
  202. $newpath = 'files/'.$this->rootpath;
  203. $newfolder = 'files/'.$this->rootfolder;
  204. if ($should_be_managed)
  205. {
  206. $newpath = 'files_managed/'.$this->rootpath;
  207. $newfolder = 'files_managed/'.$this->rootfolder;
  208. }
  209. if (!file_exists($newfolder))
  210. {
  211. mkdir($newfolder);
  212. }
  213. rename($this->path, $newpath);
  214. $this->_clear_cache();
  215. $this->_initialize_paths();
  216. $this->_build_search_metadata();
  217. }
  218. }
  219. // --------------------------------------------------------------------
  220. /**
  221. * Manage check
  222. *
  223. * Determine if a file needs to be managed
  224. *
  225. * @access private
  226. * @return void
  227. */
  228. function _manage_check()
  229. {
  230. $attachedid = $this->new_file['attachedid'];
  231. //if ($this->new_file['listed']) Why should a listed file be protected by default? Commented out
  232. //{
  233. // return TRUE;
  234. //}
  235. if ($this->new_file['attachedto'] == "post")
  236. {
  237. $object = instantiate_library('post', $attachedid);
  238. if (isset($object->new_post['postid']))
  239. {
  240. if ($object->new_post['published'] == 0 || $object->new_post['featured'] == -1 || $object->new_post['needsubscription'] == 1)
  241. {
  242. return TRUE;
  243. }
  244. $attachedid = $object->new_post['pageid']; // If it's attached to a post, we also need to check it's parent's properties
  245. }
  246. }
  247. if ($this->new_file['attachedto'] == "post" || $this->new_file['attachedto'] == "page") // Check page, or if it was a post, check post's parent
  248. {
  249. $object = instantiate_library('page', $attachedid);
  250. if (isset($object->new_page['pageid']))
  251. {
  252. if ($object->new_page['published'] == 0 || $object->new_page['needsubscription'] == 1 || sizeof($object->new_page['protection']))
  253. {
  254. return TRUE;
  255. }
  256. }
  257. }
  258. return FALSE;
  259. }
  260. // --------------------------------------------------------------------
  261. /**
  262. * Overwrite
  263. *
  264. * Given a temporary file path, overwrite the existing file with that temporary file and remove it
  265. *
  266. * @access public
  267. * @param string temp file
  268. * @return void
  269. */
  270. function overwrite($tempfilepath)
  271. {
  272. if (file_exists($tempfilepath))
  273. {
  274. copy($tempfilepath, $this->path);
  275. if ($this->path != $tempfilepath)
  276. {
  277. unlink($tempfilepath);
  278. }
  279. $this->new_file['datemodified'] = date('YmdHis');
  280. $this->save();
  281. $this->_clear_cache();
  282. $this->_build_search_metadata();
  283. $this->_initialize_info();
  284. }
  285. }
  286. // --------------------------------------------------------------------
  287. /**
  288. * Save
  289. *
  290. * Save file properties
  291. *
  292. * @access public
  293. * @return int new fileid from file creation
  294. */
  295. function save()
  296. {
  297. // Check if the file wasn't initialized from an existing one
  298. if (!isset($this->file['fileid'])) // If it wasn't, create a new file
  299. {
  300. if (!isset($this->new_file['listed']))
  301. {
  302. $this->new_file['listed'] = 0;
  303. }
  304. if (!isset($this->new_file['downloadcount']))
  305. {
  306. $this->new_file['downloadcount'] = 0;
  307. }
  308. $this->new_file['fileid'] = $this->CI->files_model->add($this->new_file['userid'], $this->new_file['filename'], $this->new_file['extension'], $this->new_file['isimage'], $this->new_file['attachedto'], $this->new_file['attachedid'], $this->new_file['filetypeid']);
  309. $this->file = $this->new_file;
  310. // Create search meta data for first time
  311. $this->_initialize_paths();
  312. $this->_build_search_metadata();
  313. // All new files upload to managed directory, sort out if it needs to be there
  314. $this->manage();
  315. return $this->file['fileid'];
  316. }
  317. else // If it was, update the existing file
  318. {
  319. // If a file is being renamed, copy it over, and update any references to it in pages and posts
  320. if (($this->new_file['filename'] != $this->file['filename']) || ($this->new_file['extension'] != $this->file['extension']))
  321. {
  322. if (file_exists($this->path))
  323. {
  324. $this->suggest(); // Make sure we are renaming to the file to something that doesn't exist
  325. copy($this->path, $this->folder.$this->new_file['filename'].".".$this->new_file['extension']);
  326. if ($this->path != $this->folder.$this->new_file['filename'].".".$this->new_file['extension'])
  327. {
  328. if ($this->new_file['attachedto'] == "page")
  329. {
  330. $object = instantiate_library('page', $this->new_file['attachedid']);
  331. $object->new_page['content'] = str_replace(
  332. "/file/page/".$object->page['urlname']."/".$this->file['filename'],
  333. "/file/page/".$object->page['urlname']."/".$this->new_file['filename'],
  334. $object->page['content']);
  335. $object->save();
  336. }
  337. else if ($this->new_file['attachedto'] == "post")
  338. {
  339. $object = instantiate_library('post', $this->new_file['attachedid']);
  340. $object->new_post['content'] = str_replace(
  341. "/file/post/".$object->post['urlname']."/".$this->file['filename'],
  342. "/file/post/".$object->post['urlname']."/".$this->new_file['filename'],
  343. $object->post['content']);
  344. $object->new_post['css'] = str_replace(
  345. "/file/post/".$object->post['urlname']."/".$this->file['filename'],
  346. "/file/post/".$object->post['urlname']."/".$this->new_file['filename'],
  347. $object->post['css']);
  348. $object->new_post['javascript'] = str_replace(
  349. "/file/post/".$object->post['urlname']."/".$this->file['filename'],
  350. "/file/post/".$object->post['urlname']."/".$this->new_file['filename'],
  351. $object->post['javascript']);
  352. $object->save();
  353. }
  354. unlink($this->path);
  355. $this->_clear_cache();
  356. $this->_initialize_paths();
  357. $this->_build_search_metadata();
  358. }
  359. }
  360. }
  361. if ($this->new_file['listed'] != $this->file['listed'])
  362. {
  363. $this->manage();
  364. }
  365. $this->CI->files_model->update($this->file['fileid'], $this->new_file);
  366. $this->file = $this->new_file;
  367. }
  368. }
  369. // --------------------------------------------------------------------
  370. /**
  371. * Suggest
  372. *
  373. * Check to see if the propsed file name and extension already exists and if it does, suggest a new name
  374. *
  375. * @access public
  376. */
  377. function suggest()
  378. {
  379. // Get and clean up name
  380. $proposed_filename = to_urlname($this->new_file['filename']);
  381. $proposed_extension = to_urlname($this->new_file['extension']);
  382. $root_filename = $proposed_filename;
  383. $i=0;
  384. if (preg_match("/^(\w+)(\d+)$/", $proposed_filename, $matches)) // If name already has a numeric ending, use it to increment
  385. {
  386. $root_filename = $matches[1];
  387. $i = $matches[2];
  388. }
  389. // Making sure that the new uploaded file gets a unique name by checking filenames of other files attached to the same place
  390. // This way if there's a file in /files and you are uploading to /files_managed, there won't be a name collision
  391. $object = instantiate_library('file', array($proposed_filename, $proposed_extension, $this->new_file['attachedto'], $this->new_file['attachedid']), 'details');
  392. // If this isn't a new file, make sure we allow the name if it's the name of the file we are editing
  393. if (isset($this->file['fileid']))
  394. {
  395. while (isset($object->file['fileid']) && $object->file['fileid'] != $this->file['fileid'])
  396. {
  397. $i++;
  398. $proposed_filename = $root_filename.$i;
  399. $object = instantiate_library('file', array($proposed_filename, $proposed_extension, $this->new_file['attachedto'], $this->new_file['attachedid']), 'details');
  400. }
  401. }
  402. else
  403. {
  404. while (isset($object->file['fileid']))
  405. {
  406. $i++;
  407. $proposed_filename = $root_filename.$i;
  408. $object = instantiate_library('file', array($proposed_filename, $proposed_extension, $this->new_file['attachedto'], $this->new_file['attachedid']), 'details');
  409. }
  410. }
  411. $this->new_file['filename'] = $proposed_filename;
  412. $this->new_file['extension'] = $proposed_extension;
  413. }
  414. }