2 /************************************************************************/
4 /************************************************************************/
5 /* Copyright (c) 2010 */
6 /* Inclusive Design Institute */
8 /* This program is free software. You can redistribute it and/or */
9 /* modify it under the terms of the GNU General Public License */
10 /* as published by the Free Software Foundation. */
11 /************************************************************************/
14 * File utility functions
19 if (!defined('TR_INCLUDE_PATH')) exit;
24 * Allows the copying of entire directories.
26 * @param string $source the source directory
27 * @param string $dest the destination directory
28 * @return boolean whether the copy was successful or not
29 * @link http://www.php.net/copy
30 * @author www at w8c dot com
32 public static function copys($source,$dest)
34 if (!is_dir($source)) {
42 while (@($entry=$h->read()) !== false) {
43 if (($entry == '.') || ($entry == '..')) {
47 if (is_dir("$source/$entry") && $dest!=="$source/$entry") {
48 copys("$source/$entry", "$dest/$entry");
50 @copy("$source/$entry", "$dest/$entry");
58 * Enables deletion of directory if not empty
60 * @param string $dir the directory to delete
61 * @return boolean whether the deletion was successful
62 * @author Joel Kronenberg
64 public static function clr_dir($dir) {
65 if(!$opendir = @opendir($dir)) {
69 while(($readdir=readdir($opendir)) !== false) {
70 if (($readdir !== '..') && ($readdir !== '.')) {
71 $readdir = trim($readdir);
73 clearstatcache(); /* especially needed for Windows machines: */
75 if (is_file($dir.'/'.$readdir)) {
76 if(!@unlink($dir.'/'.$readdir)) {
79 } else if (is_dir($dir.'/'.$readdir)) {
80 /* calls itself to clear subdirectories */
81 if(!FileUtility::clr_dir($dir.'/'.$readdir)) {
97 * Calculate the size in Bytes of a directory recursively.
99 * @param string $dir the directory to traverse
100 * @return int the total size in Bytes of the directory
101 * @author Joel Kronenberg
103 public static function dirsize($dir) {
105 $dh = @opendir($dir);
112 while (($file = readdir($dh)) !== false) {
114 if ($file != '.' && $file != '..') {
117 $size += FileUtility::dirsize($path.'/');
118 } elseif (is_file($path)) {
119 $size += filesize($path);
128 /* prints the <options> out of $cats which is an array of course categories where */
129 /* $cats[parent_cat_id][] = $row */
130 public static function print_course_cats($parent_cat_id, &$cats, $cat_row, $depth=0) {
131 $my_cats = $cats[$parent_cat_id];
132 if (!is_array($my_cats)) {
135 foreach ($my_cats as $cat) {
137 echo '<option value="'.$cat['cat_id'].'"';
138 if($cat['cat_id'] == $cat_row){
139 echo ' selected="selected"';
142 echo str_pad('', $depth, '-');
143 echo $cat['cat_name'].'</option>'."\n";
145 print_course_cats($cat['cat_id'], $cats, $cat_row, $depth+1);
149 // returns the most appropriate representation of Bytes in MB, KB, or B
150 public static function get_human_size($num_bytes) {
151 $abs_num_bytes = abs($num_bytes);
153 if ($abs_num_bytes >= TR_KBYTE_SIZE * TR_KBYTE_SIZE) {
154 return round(FileUtility::bytes_to_megabytes($num_bytes), 2) .' '. _AT('mb');
155 } else if ($abs_num_bytes >= TR_KBYTE_SIZE) {
156 return round(FileUtility::bytes_to_kilobytes($num_bytes), 2) .' '._AT('kb') ;
160 return $num_bytes . ' '._AT('bt');
164 * Returns the MB representation of inputed bytes
166 * @param int $num_bytes the input bytes to convert
167 * @return int MB representation of $num_bytes
168 * @author Heidi Hazelton
170 public static function bytes_to_megabytes($num_bytes) {
171 return $num_bytes/TR_KBYTE_SIZE/TR_KBYTE_SIZE;
175 * Returns the Byte representation of inputed MB
177 * @param int $num_bytes the input MB to convert
178 * @return int the Bytes representation of $num_bytes
179 * @author Heidi Hazelton
181 public static function megabytes_to_bytes($num_bytes) {
182 return $num_bytes*TR_KBYTE_SIZE*TR_KBYTE_SIZE;
186 * Returns the KB representation of inputed Bytes
188 * @param int $num_bytes the input Bytes to convert
189 * @return int the KB representation of $num_bytes
190 * @author Heidi Hazelton
192 public static function bytes_to_kilobytes($num_bytes) {
193 return $num_bytes/TR_KBYTE_SIZE;
197 * Returns the Bytes representation of inputed KBytes
199 * @param int $num_bytes the input KBytes to convert
200 * @return int the KBytes representation of $num_bytes
201 * @author Heidi Hazelton
203 public static function kilobytes_to_bytes($num_bytes) {
204 return $num_bytes*TR_KBYTE_SIZE;
208 * Outputs the directories associated with a course in the form of <option> elements.
210 * @param string $cur_dir the current directory to include in the options.
211 * @author Norma Thompson
213 public static function output_dirs($current_path,$cur_dir,$indent) {
215 if ($dir = opendir($current_path.$cur_dir)) {
217 // recursively call output_dirs() for all directories in this directory
218 while (false !== ($file = readdir($dir)) ) {
220 //if the name is not a directory
221 if( ($file == '.') || ($file == '..') ) {
225 // if it is a directory call function
226 if(is_dir($current_path.$cur_dir.$file)) {
227 $ldir = explode('/',$cur_dir.$file);
228 $count = count($ldir);
229 $label = $ldir[$count-1];
231 $dir_option .= '<option value="'.$cur_dir.$file.'/" >'.$indent.$label.'</option>';
233 $dir_option .= output_dirs($current_path,$cur_dir.$file.'/',$indent.'--');
243 public static function display_tree($current_path, $cur_dir, $pathext, $ignore_children = false) {
246 if (!isset($list_array)) {
247 $list_array = explode(',', $_GET['list']);
249 if ($dir = opendir($current_path . $cur_dir)) {
251 // recursively call output_dirs() for all directories in this directory
252 while (false !== ($file = readdir($dir)) ) {
254 //if the name is not a directory
255 if( ($file == '.') || ($file == '..') ) {
259 // if it is a directory call function
260 if (is_dir($current_path . $cur_dir . $file)) {
262 //$ldir = explode('/',$cur_dir.$file);
263 //$count = count($ldir);
264 //$label = $ldir[$count-1];
268 if ($cur_dir . $file == substr($pathext, 0, -1)) {
269 $check = 'checked="checked"';
270 $here = ' ' . _AT('current_location');
271 } else if (($cur_dir == $pathext) && in_array($file, $list_array)) {
272 $ignore_children = true;
275 if ($ignore_children) {
276 $check = 'disabled="disabled"';
277 $class = ' disabled';
280 $dir_option .= '<ul><li class="folders'.$class.'">';
281 $dir_option .= '<label><input type="radio" name="dir_name" value="'.$cur_dir.$file.'" '.$check. '/>'. $file . $here. '</label>';
282 $dir_option .= ''.FileUtility::display_tree($current_path,$cur_dir.$file.'/', $pathext, $ignore_children).'';
283 $dir_option .= '</li></ul>';
285 if (($cur_dir == $pathext) && in_array($file, $list_array)) {
286 $ignore_children = false;
299 public static function course_realpath($file) {
302 if (!$_course_id) return FALSE;
304 $course_path = TR_CONTENT_DIR . $_course_id;
306 $path_parts = pathinfo($file);
308 $dir_name = $path_parts['dirname'];
309 $file_name = $path_parts['basename'];
310 $ext_name = $path_parts['extension'];
312 //1. determine the real path of the file/directory
313 if (is_dir($dir_name.DIRECTORY_SEPARATOR.$file_name) && $ext_name == '') {
314 //if directory ws passed through (moving file to diff directory)
315 $real = realpath($dir_name . DIRECTORY_SEPARATOR . $file_name);
317 //if file was passed through or no existant direcotry was passed through (rename/creating dir)
318 $real = realpath($dir_name);
321 //2. and whether its in the course content directory
322 if (substr($real, 0, strlen($course_path)) != $course_path) {
326 //3. check if extensions are legal
328 //4. Otherwise return the real path of the file
333 * Returns canonicalized absolute pathname to a file/directory in the content directory
335 * @param string $file the relative path to the file or directory
336 * @return string the full path to the file or directory, FALSE if it does not exist in our content directory.
338 public static function course_realpath_NEW_VERSION($file) {
339 if (!$_SESSION['course_id']) {
343 $course_path = TR_CONTENT_DIR . $_SESSION['course_id'];
345 // determine the real path of the file/directory
346 $real = realpath($course_path . DIRECTORY_SEPARATOR . $file);
348 if (!file_exists($real)) {
349 // the file or directory does not exist
352 } else if (substr($real, 0, strlen($course_path)) != $course_path) {
353 // the file or directory is not in the content path
357 // Otherwise return the real path of the file
363 * Returns the name of the readme file in the given directory
365 * @param string $dir_name the name of the directory
366 * @return string the name of the readme file
368 public static function get_readme($dir)
370 if (!is_dir($dir)) return '';
374 while (($file = readdir($dh)) !== false) {
375 if (stristr($file, 'readme') && substr($file, -4) <> '.php')
384 * This function is mainly used to download big zip files that are created by ATutor.
385 * For example, download common cartridge, content package, backup.
386 * Note that the file is only in binary, as fopen($filename, "rb").
387 * Don't use it to read open text/html files
389 * When downloading large files exceeding 1M, instead of use readfile() to read
390 * the whole file into memory once at a time, push down 1M at a time. This way can
391 * download whatever size of the file regardless of php memory limit.
393 function readfile_in_chunks($filename) {
394 $filesize = intval(sprintf("%u", filesize($filename)));
395 $chunk_size = 1024 * 1024;
397 if ($filesize > $chunk_size) {
398 $fp = fopen($filename, "rb");
401 echo fread($fp, $chunk_size);
412 * This function handles ajax request and return an array of errors encoded in JSON
413 * @param int HTTP Status code, so far, handle 200 and 500.
415 public static function handleAjaxUpload($statusCode) {
416 if ($_POST['type'] === 'ajax') {
417 if ($statusCode === 500) {
418 // $msg->printErrors();
419 header("HTTP/1.1 500 Internal Server Error", TRUE, 500);
420 } elseif ($statusCode === 200) {
421 // $msg->printFeedbacks();
422 header("HTTP/1.1 200 Ok", TRUE, 200);