tagging as ATutor 1.5.4-release
[atutor.git] / include / classes / FileManager.class.php
1 <?php\r
2 exit('not yet complete');\r
3 /****************************************************************/\r
4 /* ATutor                                                                                                               */\r
5 /****************************************************************/\r
6 /* Copyright (c) 2002-2006 by Greg Gay & Joel Kronenberg        */\r
7 /* Adaptive Technology Resource Centre / University of Toronto  */\r
8 /* http://atutor.ca                                                                                             */\r
9 /*                                                              */\r
10 /* This program is free software. You can redistribute it and/or*/\r
11 /* modify it under the terms of the GNU General Public License  */\r
12 /* as published by the Free Software Foundation.                                */\r
13 /****************************************************************/\r
14 // $Id$\r
15 \r
16 /**\r
17  *\r
18  * This a class I'm writing to replace the un-cohesive operations of\r
19  * the existing file manager.\r
20  *\r
21  * The focus of these methods is security. This file manager is written\r
22  * to be much more secure and easier to maintain then the existing code.\r
23  *\r
24  **/\r
25 \r
26 /**\r
27 * Class for dealing with files/directories in the course content directory\r
28 * @access       public\r
29 * @author       Joel Kronenberg\r
30 */\r
31 class FileManager {\r
32 \r
33         /**\r
34         * string $contentDirectory - the full path to this course's content directory\r
35         * @access  private\r
36         */\r
37         var $contentDirectory; // path to content dir\r
38 \r
39 \r
40         /**\r
41         * Constructor method.  Initialises variables.\r
42         * @access       public\r
43         * @author       Joel Kronenberg\r
44         */\r
45         function FileManager( ) {\r
46                 $this->contentDirectory = AT_CONTENT_DIR . $_SESSION['course_id'];\r
47         }\r
48 \r
49         /**\r
50         * Creates a directory recursivelly.\r
51         * @access  public\r
52         * @param   string $dir      relative path and name of the directory to create.\r
53         *                           dir can be a full path of a dir structure to create.\r
54         * @return  boolean                      whether or not the directory was created\r
55         * @author  Joel Kronenberg\r
56         */\r
57         function createDirectory($dir) {\r
58                 // break $dir into the end part\r
59                 // check that the path to the new dir is safe\r
60                 // sanitise the dir name\r
61 \r
62                 // Note: would it be easier to receive the path and directory name separately?\r
63                 \r
64         }\r
65 \r
66         /**\r
67         * Copies a file or directory\r
68         * @access  public\r
69         * @param   string $src  relative path to the source directory or file\r
70         * @param   string $dst  relative path to the destination directory or file\r
71         * @return  boolean      TRUE or FALSE whether or not the action was successful\r
72         * @author  Joel Kronenberg\r
73         */\r
74         function copy($src, $dst) {\r
75 \r
76         }\r
77 \r
78         /**\r
79         * Moves a file or directory\r
80         * @access  public\r
81         * @param   string $src  relative path to the source directory or file\r
82         * @param   string $dst  relative path to the destination directory or file\r
83         * @return  boolean      TRUE or FALSE whether or not the action was successful\r
84         * @author  Joel Kronenberg\r
85         */\r
86         function move($src, $dst) {\r
87 \r
88         }\r
89 \r
90         /**\r
91         * Rename a file or directory\r
92         * @access  public\r
93         * @param   string $old_name   relative path and old name of the directory or file to rename\r
94         * @param   string $new_name   relative path and new name of the directory or file to rename\r
95         * @return  boolean            TRUE or FALSE whether or not the action was successful\r
96         * @author  Joel Kronenberg\r
97         */\r
98         function rename($old_name, $new_name) {\r
99 \r
100         }\r
101 \r
102         /**\r
103         * Delete a file or directory (recusively)\r
104         * @access  public\r
105         * @param   string $file   relative path and name of the file or directory to delete\r
106         * @return  boolean        TRUE or FALSE whether or not the action was successful\r
107         * @author  Joel Kronenberg\r
108         */\r
109         function delete($file) {\r
110                 // if it's a dir, then call the $this->_deleteDir($file) private method\r
111                 // else if it's a file call the $this->_deleteFile($file) private method\r
112         }\r
113 \r
114         /**\r
115         * Extracts a zip archive\r
116         * @access  public\r
117         * @param   string $archive  relative path and name of the zip file to extract\r
118         * @param   string $dst      relative path and name of the directory to extract the files into\r
119         * @return  boolean          TRUE or FALSE whether or not the action was successful\r
120         * @author  Joel Kronenberg\r
121         */\r
122         function extract($archive, $dst) {\r
123 \r
124         }\r
125 \r
126         /**\r
127         * Saves contents to a file\r
128         * @access  public\r
129         * @param   string $file       relative path to the file to save to\r
130         * @param   string $contents   the contents of the file to save to\r
131         * @param   boolean $overwrite whether or not to overwrite the file if it exists\r
132         * @return  boolean          TRUE or FALSE whether or not the action was successful\r
133         * @author  Joel Kronenberg\r
134         */\r
135         function saveFile($file, $contents, $overwrite = FALSE) {\r
136 \r
137         }\r
138 \r
139         /**\r
140         * Saves an uploded file\r
141         * @access  public\r
142         * @return  boolean          TRUE or FALSE whether or not the action was successful\r
143         * @author  Joel Kronenberg\r
144         */\r
145         function saveUploadFile( ) {\r
146 \r
147         }\r
148 \r
149         /**\r
150         * Returns size of a directory (recursively)\r
151         * @access  public\r
152         * @param   string $dir         relative path to the directory\r
153         * @param   boolean $recursive  whether or not to recurse down directories\r
154         * @return  int                 size of directory in Bytes, FALSE on failure\r
155         * @author  Joel Kronenberg\r
156         */\r
157         function getDirectorySize($dir, $recursive = TRUE) {\r
158                 $dir = $this->_getRealPath($dir);\r
159 \r
160                 if (($dir !== FALSE) && is_dir($dir)) {\r
161                         $dh = @opendir($dir);\r
162                 }\r
163                 if (!$dh) {\r
164                         return -1;\r
165                 }\r
166                 $size = 0;\r
167                 while (($file = readdir($dh)) !== false) {\r
168                         if (($file != '.') && ($file != '..')) {\r
169                                 $path = $dir . $file;\r
170                                 if (is_dir($path) && ($recursive === TRUE)) {\r
171                                         $size += $this->getDirectorySize($path . DIRECTORY_SEPARATOR);\r
172                                 } elseif (is_file($path)) {\r
173                                         $size += filesize($path);\r
174                                 }\r
175                         }\r
176                         \r
177                 }\r
178                 closedir($dh);\r
179                 return $size;\r
180         }\r
181 \r
182         /**\r
183         * Returns listing of files and directories\r
184         * @access  public\r
185         * @param   string $dir     relative path to the directory\r
186         * @return  array           array of files and directories in $dir\r
187         * @author  Joel Kronenberg\r
188         */\r
189         function getDirectoryListing($dir) {\r
190 \r
191         }\r
192 \r
193         /**\r
194         * Returns whether or not the $fileName is an editable type of file\r
195         * @access  public\r
196         * @param   string $fileName    name of the file to check\r
197         * @return  boolean             TRUE if the file can be edited, FALSE otherwise\r
198         * @author  Joel Kronenberg\r
199         */\r
200         function isEditable($fileName) {\r
201                 // check if $fileName is in the list of editable files\r
202 \r
203         }\r
204 \r
205         /**\r
206         * Returns whether or not the $fileName is an archive that can be extracted\r
207         * @access  public\r
208         * @param   string $fileName    name of the file to check\r
209         * @return  boolean             TRUE if the file can be extracted, FALSE otherwise\r
210         * @author  Joel Kronenberg\r
211         */\r
212         function isExtractable($fileName) {\r
213                 // check if $fileName is in the list of extractable files\r
214 \r
215                 // Note: could possibly call this isArchive() (but that doesn't directly imply extractability)\r
216         }\r
217 \r
218         // -- private methods below\r
219 \r
220         /**\r
221         * Returns a safe to use file or directory name\r
222         * @access  private\r
223         * @param   string $file         the file or directory name to sanitise\r
224         * @return  string|boolean   the sanitised file/directory name, or FALSE if the result is empty\r
225         * @author  Joel Kronenberg\r
226         */\r
227         function _getCleanName($fileName) {\r
228                 $fileName = trim($fileName);\r
229                 $fileName = str_replace(' ', '_', $fileName);\r
230                 $fileName = str_replace(array(' ', '/', '\\', ':', '*', '?', '"', '<', '>', '|', '\''), '', $fileName);\r
231 \r
232                 return $fileName;\r
233         }\r
234 \r
235         /**\r
236         * Returns canonicalized absolute pathname\r
237         * @access  private\r
238         * @param   string $file         the relative path to a file or directory\r
239         * @return  string|boolean   the canonicalized pathname, or FALSE if the file is not in the content directory\r
240         * @author  Joel Kronenberg\r
241         */\r
242         function _getRealPath($file) {\r
243                 // determine the real path of the file/directory\r
244                 $real = realpath($this->contentDirectory . DIRECTORY_SEPARATOR . $file);\r
245                 \r
246                 if (!file_exists($real)) {\r
247                         // the file or directory does not exist\r
248                         return FALSE;\r
249 \r
250                 } else if (substr($real, 0, strlen($this->contentDirectory)) != $this->contentDirectory) {\r
251                         // the file or directory is not in the content path\r
252                         return FALSE;\r
253 \r
254                 } else {\r
255                         // otherwise return the real path of the file\r
256                         return $real;\r
257                 }\r
258         }\r
259 \r
260         /**\r
261         * Delete a file\r
262         * @access  private\r
263         * @param   string $file   relative path and name of the file or directory to delete\r
264         * @return  boolean        TRUE or FALSE whether or not the action was successful\r
265         * @author  Joel Kronenberg\r
266         */\r
267         function _deleteFile($file) {\r
268 \r
269         }\r
270 \r
271         /**\r
272         * Delete this directory recursively\r
273         * @access  private\r
274         * @param   string $dir   relative path and name of the directory to delete\r
275         * @return  boolean       TRUE or FALSE whether or not the action was successful\r
276         * @author  Joel Kronenberg\r
277         */\r
278         function _deleteDirectory($dir) {\r
279 \r
280         }\r
281 }\r
282 \r
283 \r
284 /**\r
285 * FileManagerFactory\r
286 * Class for creating AbstractFileManager Objects\r
287 * @access       public\r
288 * @author       Joel Kronenberg\r
289 * @package      FileManager\r
290 */\r
291 class FileManagerFactory {\r
292 \r
293         function FileManagerFactory() { }\r
294 \r
295         function createFileManagerFile($name) {\r
296                 $obj = new FileManagerFile($name);\r
297                 if ($obj->isOkay()) {\r
298                         return $obj;\r
299                 }\r
300                 return NULL;\r
301         }\r
302         function createFileManagerDirectory($name) {\r
303                 $obj= new FileManagerDirectory($name);\r
304                 if ($obj->isOkay()) {\r
305                         return $obj;\r
306                 }\r
307                 return NULL;\r
308         }\r
309 \r
310         function open($name) {\r
311                 if (is_dir($name)) {\r
312                         $obj = new FileManagerDirectory($name);\r
313                 } else if (is_file($name)) {\r
314                         $obj = new FileManagerFile($name);\r
315                 } else {\r
316                         // file not found\r
317                         return NULL;\r
318                 }\r
319                 if ($obj->isOkay()) {\r
320                         return $obj;\r
321                 }\r
322                 return NULL;\r
323         }\r
324 }\r
325 \r
326 class AbstractFileManager {\r
327         var $_type; // private\r
328         var $_name; // private\r
329         var $_path; // private\r
330         var $_filename; // private\r
331         var $_exists; // private\r
332 \r
333         // var $_old_filename;\r
334         // var $_old_path; // maybe?\r
335 \r
336         var $_fp; // private, file/dir pointer\r
337 \r
338         function AbstractFileManager( ) {\r
339                 $this->contentDirectory = AT_CONTENT_DIR . $_SESSION['course_id'];\r
340         }\r
341 \r
342         function create() { }\r
343 \r
344         function isOkay() {\r
345                 // this is where the important authentication check is done!\r
346                 echo 'authenticating '.$this->_filename.'<br>';\r
347                 if (file_exists($this->_path . DIRECTORY_SEPARATOR . $this->_filename)) {\r
348                         $this->_exists = TRUE;\r
349                 }\r
350                 $this->_exists = FALSE;\r
351                 if ($this->isIllegalType()) {\r
352                         return FALSE;\r
353                 }\r
354                 return TRUE;\r
355         }\r
356         \r
357         function exists() {\r
358                 return $this->_exists;\r
359         }\r
360 \r
361 }\r
362 \r
363 class FileManagerFile extends AbstractFileManager {\r
364         var $_extension; // private\r
365 \r
366         function FileManagerFile($file) {\r
367                 $this->_type = 'file';\r
368 \r
369                 $pathinfo = pathinfo($file);\r
370                 $this->_extension = $pathinfo['extension'];\r
371                 $this->_path      = $pathinfo['dirname'];\r
372                 $this->_filename  = $pathinfo['basename'];\r
373 \r
374                 // set whether or not this file/dir is safe.\r
375         }\r
376 \r
377         function rename($newName) {\r
378                 $return = FALSE;\r
379 \r
380                 $fileManagerFactory = new FileManagerFactory();\r
381                 $fileObj = $fileManagerFactory->createFileManagerFile($this->_path . DIRECTORY_SEPARATOR . $newName);\r
382                 if (($fileObj !== NULL) && !$fileObj->exists()) {\r
383                         if (@rename($this->_path . DIRECTORY_SEPARATOR . $this->_filename, $this->_path . DIRECTORY_SEPARATOR . $newName)) {\r
384                                 $this->_filename = $newName;\r
385                                 $return = TRUE;\r
386                         }\r
387                 }\r
388                 return $return;\r
389         }\r
390 \r
391         function delete() {\r
392                 return unlink($this->_path . DIRECTORY_SEPARATOR . $this->_filename);\r
393         }\r
394 \r
395         function isIllegalType($name = '') {\r
396                 // get file extension\r
397                 if ($name) {\r
398                         $pathinfo = pathinfo($name);\r
399                         $ext = $pathinfo['extension'];\r
400                 } else {\r
401                         $ext = $this->_extension;\r
402                 }\r
403 \r
404                 if (in_array($ext, array('txt', 'html'))) {\r
405                         return FALSE;\r
406                 }\r
407                 return TRUE;\r
408         }\r
409 \r
410         function create($content) {\r
411                 if (!is_dir($this->_path)) {\r
412                         $fileManagerFactory = new FileManagerFactory();\r
413                         $dirObj = $fileManagerFactory->createFileManagerDirectory($this->_path);\r
414                         if ($dirObj !== NULL) {\r
415                                 $dirObj->create(0666);\r
416                         }\r
417                 }\r
418 \r
419                 // save $contents into $file\r
420                 $return = FALSE;\r
421                 if (($fp = @fopen($this->_path . DIRECTORY_SEPARATOR . $this->_filename, 'wb+')) !== FALSE) {\r
422                         $return = @fwrite($fp, $content, strlen($content));\r
423                         @fclose($fp);\r
424                 }\r
425                 return $return;\r
426         }\r
427 \r
428 }\r
429 \r
430 class FileManagerDirectory extends AbstractFileManager {\r
431 \r
432         function FileManagerDirectory($dir) {\r
433                 $this->_type = 'directory';\r
434 \r
435                 $pathinfo = pathinfo($dir);\r
436                 $this->_path     = $pathinfo['dirname'];\r
437                 $this->_filename = $pathinfo['basename'];\r
438         }\r
439 \r
440         function isIllegalType() {\r
441                 return FALSE;\r
442         }\r
443 \r
444         function getDirectoryListing() {\r
445 \r
446         }\r
447 \r
448         // creates dir\r
449         function create($mode = 0666) {\r
450                 if (is_dir($this->_path)) {\r
451                         return @mkdir($this->_path . DIRECTORY_SEPARATOR . $this->_filename, $mode);\r
452                 } else {\r
453                         $fileManagerFactory = new FileManagerFactory();\r
454                         $dirObj = $fileManagerFactory->createFileManagerDirectory($this->_path);\r
455                         if ($dirObj !== NULL) {\r
456                                 if ($dirObj->create(0666) !== FALSE) {\r
457                                         return @mkdir($this->_path . DIRECTORY_SEPARATOR . $this->_filename, $mode);\r
458                                 }\r
459                         }\r
460                 }\r
461         }\r
462 \r
463         function delete() {}\r
464 \r
465         function getDirectorySize($recursive = TRUE) {\r
466 \r
467         }\r
468 \r
469         // private\r
470         function _getDirectorySize($recursive = TRUE) {\r
471 \r
472         }\r
473 \r
474 }\r
475 \r
476 $fileManagerFactory = new FileManagerFactory();\r
477 \r
478 $fileObj = $fileManagerFactory->createFileManagerFile('/content/meow.txt');\r
479 \r
480 if ($fileObj !== NULL) {\r
481         $data = 'stuff goes in here';\r
482         if ($fileObj->create($data) !== FALSE) {\r
483                 echo 'create good: ' . $fileObj->_filename .' in '. $fileObj->_path;\r
484         }\r
485 }\r
486 echo '<hr>';\r
487 \r
488 $fileObj = $fileManagerFactory->open('/content/meow.txt');\r
489 if ($fileObj !== NULL) {\r
490         if ($fileObj->rename('cow.txt') !== FALSE) {\r
491                 echo 'rename good: ' . $fileObj->_filename .' in '. $fileObj->_path;\r
492         }\r
493 }\r
494 \r
495 echo '<hr>';\r
496 \r
497 $fileObj = $fileManagerFactory->open('/content/cow.txt');\r
498 if ($fileObj !== NULL) {\r
499         if ($fileObj->delete() !== FALSE) {\r
500                 echo 'delete good: ' . $fileObj->_filename .' in '. $fileObj->_path;\r
501         }\r
502 }\r
503 \r
504 echo '<hr>';\r
505 \r
506 $dirObj = $fileManagerFactory->createFileManagerDirectory('/content/test1/test2/test3/test4/');\r
507 if ($dirObj !== NULL) {\r
508         if ($dirObj->create(0666) !== FALSE) {\r
509                 echo 'create good: ' . $dirObj->_filename .' in '. $dirObj->_path;\r
510         } else {\r
511                 echo 'dir exists: ' . $dirObj->_filename .' in '. $dirObj->_path;\r
512         }\r
513 }\r
514 \r
515 echo '<hr>';\r
516 \r
517 \r
518 $fileObj = $fileManagerFactory->createFileManagerFile('/content/test3/test122/quack.txt');\r
519 if ($fileObj !== NULL) {\r
520         $data = 'quack file goes here';\r
521         if ($fileObj->create($data) !== FALSE) {\r
522                 echo 'create good: ' . $fileObj->_filename .' in '. $fileObj->_path;\r
523         }\r
524 }\r
525 \r
526 echo '<hr>';\r
527 \r
528 /*\r
529 - create/overwrite file\r
530 - move file\r
531 - rename file\r
532 - delete file\r
533 - copy file\r
534 \r
535 \r
536 - create dir\r
537 - move dir (and its files)\r
538 - rename dir\r
539 - delete dir\r
540 - copy dir\r
541 \r
542 \r
543 */\r
544 ?>