YaWK  24.1
Yet another WebKit
filemanager.php
Go to the documentation of this file.
1 <?php
2 namespace YAWK {
3  /**
4  * @details <b>Basic File Manager (Backend)</b>
5  *
6  * This basic file manager class provides simple view, delete and upload methods.
7  * <p><i>Class covers backend functionality.
8  * See Methods Summary for details!</i></p>
9  *
10  * @author Daniel Retzl <[email protected]>
11  * @copyright 2009-2015 Daniel Retzl yawk.goodconnect.net
12  * @license https://opensource.org/licenses/MIT
13  * @since File available since Release 1.0.0
14  * @brief Basic File Manager (Backend)
15  */
17  {
18 
19  /**
20  * @brief filemanager constructor.
21  * check if all media subfolder exists, if not, try to create them
22  */
23  function __construct()
24  {
25  $folders = array('../media/images',
26  '../media/audio',
27  '../media/backup',
28  '../media/documents',
29  '../media/downloads',
30  '../media/mailbox',
31  '../media/uploads',
32  '../media/video');
33 
34  foreach ($folders as $folder)
35  {
36  if (!is_dir($folder))
37  {
38  if (!mkdir($folder))
39  {
40  // todo: syslog: unable to create $folder
41  return false;
42  }
43  }
44  }
45  return true;
46  }
47 
48  /**
49  * @brief draw the table header with labeling
50  * @param array $lang language array
51  * @param integer $i
52  */
53  static function drawTableHeader($lang, $i)
54  {
55 
56  if (isset($_GET['path']) && (!empty($_GET['path'])))
57  {
58  $backBtn = "<a class=\"btn btn-success pull-right\" href=\"index.php?page=filemanager\" onclick=\"window.history.back();\"><i class=\"fa fa-level-up\"></i> &nbsp;$lang[BACK]</a>";
59  }
60  else
61  {
62  $backBtn = '';
63  }
64 
65  print $backBtn;
66  print "<table style=\"width:100%;\" class=\"table table-responsive table-hover\" id=\"table-sort$i\">
67  <thead>
68  <tr>
69  <td style=\"width:10%;\" class=\"text-right\"><b>$lang[FILEMAN_SIZE]</b></td>
70  <td style=\"width:70%;\" class=\"text-left\"><b>$lang[FILEMAN_FILENAME]</b></td>
71  <td style=\"width:10%;\" class=\"text-center\"><b>$lang[FILEMAN_RIGHTS]</b></td>
72  <td style=\"width:10%;\" class=\"text-center\"><b>$lang[ACTIONS]</b></td>
73  </tr>
74  </thead>
75  <tbody>";
76  }
77 
78  /**
79  * @brief draw: output html end table body, end table
80  */
81  static function drawTableFooter()
82  {
83  print "</tbody></table><br><br>";
84  }
85 
86 
87  /**
88  * @brief all folders in $path as select <option>...</option>
89  * @param string $path rootpath that should be scanned and returned
90  */
91  static function subdirToOptions($path)
92  {
93  if (isset($path) && (!empty($path) && (is_dir($path))))
94  {
95  // init new iterator object
96  $iter = new \RecursiveIteratorIterator(
97  new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS),
98  \RecursiveIteratorIterator::SELF_FIRST,
99  \RecursiveIteratorIterator::CATCH_GET_CHILD // Ignore "Permission denied"
100  );
101 
102  // if you wish to return an array, uncomment following line:
103  // $paths = array($root);
104  echo "<optgroup label=\"Subfolder\">";
105  foreach ($iter as $path => $dir)
106  {
107  if($dir->getFilename() === "audio") continue;
108  if($dir->getFilename() === "backup") continue;
109  if($dir->getFilename() === "documents") continue;
110  if($dir->getFilename() === "downloads") continue;
111  if($dir->getFilename() === "images") continue;
112  if($dir->getFilename() === "mailbox") continue;
113  if($dir->getFilename() === "uploads") continue;
114  if($dir->getFilename() === "video") continue;
115  if ($dir->isDir())
116  {
117  // if you wish to return an array, uncomment following line:
118  // $paths[] = $path;
119  // you need subdir only in a var?- uncomment following line:
120  // $subdir = $dir->getFilename();
121 
122  // adjust path
123  $subpath = ltrim($path, ".."); // remove dots
124  $subpath = ltrim($subpath, "/"); // remove pre slash
125  $subpath = ltrim($subpath, "media"); // remove not needed path
126  $subpath = ltrim($subpath, "/"); // remove trailing slash
127  $subpath = strtr($subpath,"\\","/"); // if run on win: backslashes2slashes
128  $label = ltrim($subpath, "/"); // remove trailing slash
129  $label = ucfirst($label); // uppercase first char of label
130  echo "<option value=\"$subpath\">&nbsp;$label</option>";
131  }
132  }
133 
134  // if you wish to return an array, uncomment following code block:
135  /*
136  if (isset($paths) && (is_array($paths)))
137  {
138  return $paths;
139  }
140  else
141  {
142  return null;
143  }
144  */
145  }
146  }
147 
148  /**
149  * @brief returns a list of all files in given folder. expect $folder as string
150  * @author Daniel Retzl <[email protected]>
151  * @copyright 2009-2015 Daniel Retzl yawk.goodconnect.net
152  * @license https://opensource.org/licenses/MIT
153  * @param string $folder folder to look for files
154  * @param string $path path to workout
155  * @param array $lang current language array
156  */
157  static function getFilesFromFolder($folder, $lang)
158  {
159  global $file_value;
160 
161  // check if a path is requested via GET variable
162  if (isset($_GET['path']) && (!empty($_GET['path'])))
163  { // set folder to given value
164  $folder = $_GET['path'];
165  }
166 
167  // if no folder is set
168  if (!isset($folder)) {
169  // show up any default folder
170  $folder = "../media/images";
171  }
172 
173  // if requested folder not exists, folder structure may be corrupt.
174  // this can cause a crash if a system-needed folder was deleted.
175  if (!is_dir($folder))
176  { // try to catch this - create missing folder
177  if (!mkdir($folder))
178  { // could not create missing folder - bad exit, bad warning.
179  die ("$lang[FILEMAN_FOLDER_MISSING]");
180  }
181  // in any other case, everything is ok - go on...
182  }
183  // set path variable
184  $path = "$folder";
185  // walk through file structure...
186  foreach (new \DirectoryIterator($path) as $file) {
187  // fill files array
188  if ($file->isFile()) {
189  // create files array
190  $files[] = htmlentities($file);
191  // get permissions
192  $file_perms[] = substr(sprintf('%o', fileperms($path . "/" . $file)), -4);
193  // get filesize
194  $file_size[] = filesize($path . "/" . $file);
195  }
196  // fill folders array
197  if ($file->isDir() AND (!$file->isDot())) {
198  $folders[] = htmlentities($file);
199  $dir_perms[] = substr(sprintf('%o', fileperms($path . "/" . $file)), -4);
200  }
201  }
202  // sort files asc/desc
203  if (!empty($files)) {
204  // insert sort here - if needed
205  }
206  // sort folders asc/desc
207  if (!empty($folders)) {
208  // sort($folders);
209  }
210 
211  // if no files or folder was found
212  if (empty($files) && (empty($folders)))
213  { // this directory is empty, show msg and draw back btn
214  $errorMsg = "$lang[FILEMAN_THIS_EMPTY_DIR]<br>
215  <a href=\"index.php?page=filemanager\" onclick=\"window.history.back();\"> $lang[BACK]</a>";
216  }
217  else
218  { // no error message
219  $errorMsg = '';
220  }
221 
222  /* OUTPUT:
223  * list folders + files
224  */
225  // first of all, draw folders from array
226  if (isset($folders))
227  { // print folders
228  $i = 0;
229  $deleteIcon = "<i class=\"fa fa-trash-o\"></i>";
230  foreach ($folders as $dir_value)
231  {
232  // avoid warnings if no files or directories are found
233  if (!isset($file_perms[$i])){ $file_perms[$i] = ''; }
234  if (!isset($dir_perms[$i])){ $dir_perms[$i] = ''; }
235 
236  // LIST FOLDERS
237  // print "<strong>$dir_perms $dir_value</strong><br>";
238  echo "<tr>
239  <td class=\"text-right\"><a href=\"?page=filemanager&path=$path" . "/$dir_value\"><div style=\"width:100%\"><i class=\"fa fa-folder\"></i></div></a></td>
240  <td class=\"text-left\"><a href=\"?page=filemanager&path=$path" . "/$dir_value\"><div style=\"width:100%\">$dir_value</div></a></td>
241  <td class=\"text-center\">$dir_perms[$i] <small><a class=\"fa fa-edit\" onclick=\"setChmodCode('$path/$file_value', '$file_perms[$i]');\" data-toggle=\"modal\" data-target=\"#chmodModal\" data-foldername=\"$file_perms[$i]\" title=\"$lang[FILEMAN_CHMOD]\" href=\"#myModal\"></a></small> </td>
242  <td class=\"text-center\">
243  <a class=\"fa fa-trash-o\" data-title=\"$lang[FILEMAN_REMOVE_FOLDER]\" data-itemtype=\"$lang[FOLDER]\" role=\"dialog\" data-confirm=\"$lang[FILEMAN_DELETE] &laquo;$dir_value&raquo;\"
244  title=\"$lang[FILEMAN_REMOVE_FOLDER]\" data-target=\"#deleteModal\" data-toggle=\"modal\" href=\"index.php?page=filemanager&delete=1&path=$path&item=$dir_value&folder=$folder\"></a>
245  &nbsp;
246  <a class=\"fa fa-pencil\" id=\"renameToggle\" onclick=\"setRenameFieldState('$path', '$dir_value', '$lang[FILEMAN_RENAME_FOLDER]');\" data-toggle=\"modal\" data-target=\"#renameModal\" data-foldername=\"$dir_value\" title=\"$lang[RENAME]\" href=\"#myModal\"></a>
247  </td>
248  </tr>";
249  $i++;
250  }
251  }
252  else
253  { // if directory is empty, display this info instead of data
254  echo "<tr>
255  <td></td>
256  <td>$errorMsg</td>
257  <td></td>
258  <td></td>
259  </tr>";
260  }
261 
262  // secondly draw files from array
263  if (isset($files))
264  { // print files
265  $i = 0;
266  foreach ($files as $file_value) {
267 
268  $fsize = \YAWK\filemanager::sizeFilter($file_size[$i], 1);
269  echo "<tr>
270  <td class=\"text-right\">$fsize</td>
271  <td class=\"text-left\"><a href='$path" . "/$file_value'><div style=\"width:100%\">$file_value</div></a></td>
272  <td class=\"text-center\">$file_perms[$i] <small><a class=\"fa fa-edit\" onclick=\"setChmodCode('$path/$file_value', '$file_perms[$i]');\" data-toggle=\"modal\" data-target=\"#chmodModal\" data-foldername=\"$file_perms[$i]\" title=\"$lang[FILEMAN_CHMOD]\" href=\"#myModal\"></a></small></td>
273  <td class=\"text-center\">
274 
275  <a class=\"fa fa-trash-o\" role=\"dialog\" data-confirm=\"$lang[FILEMAN_DELETE] &laquo;$file_value&raquo;\"
276  title=\"$lang[FILEMAN_REMOVE_FILE]\" data-target=\"#moveModal\" data-toggle=\"modal\" href='index.php?page=filemanager&delete=1&path=$path&item=$file_value&folder=$folder'></a>
277  &nbsp;
278  <a class=\"fa fa-pencil\" onclick=\"setRenameFieldState('$path', '$file_value', '$lang[FILEMAN_RENAME_FILE]');\" data-toggle=\"modal\" data-target=\"#renameModal\" data-foldername=\"$file_value\" title=\"$lang[RENAME]\" href=\"#myModal\"></a>
279  </td>
280  </tr>";
281  $i++;
282  }
283  } else {
284  // print "<br><h4>There are no files in $folder.</h4>";
285 
286  }
287  }
288 
289  /**
290  * @brief Delete a directory recursive
291  * @author Daniel Retzl <[email protected]>
292  * @copyright 2009-2017 Daniel Retzl
293  * @license https://opensource.org/licenses/MIT
294  * @param string $directory folder to delete
295  */
296  static function recursiveRemoveDirectory($directory)
297  { // walk through directory
298  foreach(glob("{$directory}/*") as $file)
299  { // if it's a directory
300  if(is_dir($file))
301  { // call ourself
303  }
304  else
305  { // delete folder
306  unlink($file);
307  }
308  }
309  // directory removed
310  if (rmdir($directory))
311  { // successful
312  return true;
313  }
314  else
315  { // remove folder failed
316  return false;
317  }
318  }
319 
320  /**
321  * @brief delete file from folder
322  * @author Daniel Retzl <[email protected]>
323  * @copyright 2009-2015 Daniel Retzl
324  * @license https://opensource.org/licenses/MIT
325  * @param string $file file to delete
326  * @param string $folder folder containing the file
327  */
328  static function deleteItem($file)
329  {
330  // check if it is a directory or a file and set relevant actions
331 
332  // FOLDER
333  if (is_dir($file))
334  { // lets run recursive directory removal function...
335  if (self::recursiveRemoveDirectory($file))
336  { // folder + its content deleted
337  return true;
338  }
339  else
340  { // could not recursive delete folder
341  // die ("recursiveRemoveDirectory failed");
342  return false;
343  }
344  }
345 
346  // FILE
347  else if (is_file($file))
348  { // check if unlink worked
349  if (@unlink($file))
350  { // all good
351  return true;
352  }
353  else
354  { // on error
355  return false;
356  }
357  }
358  else
359  { // item is not a file nor a directory
360  // die ("item not found.");
361  return false;
362  }
363  }
364 
365  /**
366  * @brief get and return post_max_size value from phpinfo()
367  * @author Daniel Retzl <[email protected]>
368  * @copyright 2009-2016 Daniel Retzl
369  * @license https://opensource.org/licenses/MIT
370  * @return string|false
371  */
372  static function getPostMaxSize()
373  {
374 
375  if ($postMaxSize = ini_get('post_max_size'))
376  { // return post max filesize
377  return $postMaxSize;
378  }
379  else
380  { // ini_get failed
381  if (!isset($db)) { $db = new \YAWK\db(); }
382  \YAWK\sys::setSyslog($db, 27, 1, "failed to ini_get post_max_size", 0, 0, 0, 0);
383  echo "Unable to get post_max_size";
384  return false;
385  }
386  }
387 
388  /**
389  * @brief get and return upload max filesize value from phpinfo()
390  * @author Daniel Retzl <[email protected]>
391  * @copyright 2009-2016 Daniel Retzl
392  * @license https://opensource.org/licenses/MIT
393  * @return string|false
394  */
395  static function getUploadMaxFilesize()
396  {
397 
398  if ($upload_max_filesize = ini_get('upload_max_filesize'))
399  { // upload_max_filesize
400  return $upload_max_filesize;
401  }
402  else
403  { // ini_get failed
404  if (!isset($db)) { $db = new \YAWK\db(); }
405  \YAWK\sys::setSyslog($db, 27, 1, "failed to ini_get upload_max_filesize", 0, 0, 0, 0);
406  return false;
407  }
408  }
409 
410  /**
411  * @brief get and return PHP max file size setting
412  * @author Daniel Retzl <[email protected]>
413  * @copyright 2009-2016 Daniel Retzl
414  * @license https://opensource.org/licenses/MIT
415  * @return bool|string
416  */
417  static function getPhpMaxUploadSize()
418  {
419  $returnValue = '';
420 
421  if ($postMaxSize = ini_get('post_max_size'))
422  { // return post max filesize
423  $returnValue = $postMaxSize;
424  }
425  if ($upload_max_filesize = ini_get('upload_max_filesize'))
426  { // upload_max_filesize
427  $returnValue .= " (".$upload_max_filesize.")";
428  }
429  else
430  { // ini_get failed
431  if (!isset($db)) { $db = new \YAWK\db(); }
432  \YAWK\sys::setSyslog($db, 27, 1, "failed to ini_get post_max_size", 0, 0, 0, 0);
433  return false;
434  }
435 
436  return $returnValue;
437  }
438 
439 
440  /**
441  * @brief count files from folder
442  * @author Daniel Retzl <[email protected]>
443  * @copyright 2009-2016 Daniel Retzl
444  * @license https://opensource.org/licenses/MIT
445  * @param string $folder to search for files
446  * @return int number of files in folder
447  */
448  static function countFilesFromFolder($folder)
449  {
450  $i = 0;
451  foreach (new \DirectoryIterator($folder) as $fileInfo) {
452  if($fileInfo->isDot()) continue;
453  if($fileInfo->isDir()) continue;
454  $i++;
455  }
456  return $i;
457  }
458 
459  /**
460  * @brief output a list showing only files from folder (no subfolders)
461  * @author Daniel Retzl <[email protected]>
462  * @copyright 2009-2016 Daniel Retzl
463  * @license https://opensource.org/licenses/MIT
464  * @param string $folder to get files from
465  */
467  {
468  foreach (new \DirectoryIterator($folder) as $fileInfo) {
469  if($fileInfo->isDot()) continue;
470  if($fileInfo->isDir()) continue;
471  echo $fileInfo->getFilename() . "<br>\n";
472  }
473  }
474 
475  /**
476  * @brief remove special chars as well as leading and trailing slashes from string
477  * @author Daniel Retzl <[email protected]>
478  * @copyright 2017 Daniel Retzl
479  * @license https://opensource.org/licenses/MIT
480  * @param string $string the affected string
481  */
482  static function removeSpecialChars($string)
483  {
484  if (isset($string) && (!empty($string)))
485  {
486  // $string = 'V!e§r$s%c&h/i(e)d=e?n`e² S³o{n[d]e]r}z\e´i+c*h~e#n';
487  // remove special chars
488  $string = preg_replace ('/[^a-z0-9-. ]/i', '', $string);
489  // trim any whitespaces left or right
490  $string = trim($string);
491  // change any backslashes to regular slashes
492  $string = strtr($string,"\\","/");
493  // remove all leading slashes
494  $string = ltrim($string, "/");
495  // remove all trailing slashes
496  $string = rtrim($string, "/");
497  return $string;
498  }
499  else
500  {
501  return null;
502  }
503  }
504 
505  /**
506  * @brief returns an array containing only files from folder (no subfolders)
507  * @author Daniel Retzl <[email protected]>
508  * @copyright 2009-2016 Daniel Retzl
509  * @license https://opensource.org/licenses/MIT
510  * @param string $folder to get files from
511  */
513  {
514  $files = array();
515  foreach (new \DirectoryIterator($folder) as $fileInfo) {
516  if($fileInfo->isDot()) continue;
517  if($fileInfo->isDir()) continue;
518  $files[] = $fileInfo->getFilename();
519  }
520  return $files;
521  }
522 
523  /**
524  * @brief returns an array containing only files from folder (no subfolders)
525  * @author Daniel Retzl <[email protected]>
526  * @copyright 2009-2016 Daniel Retzl
527  * @license https://opensource.org/licenses/MIT
528  * @param string $folder to get files from
529  */
530  static function getSubfoldersToArray($folder)
531  {
532  $subFolders = array();
533  foreach (new \DirectoryIterator($folder) as $fileInfo) {
534  if($fileInfo->isDot()) continue;
535  if($fileInfo->isFile()) continue;
536  if($fileInfo->isDir())
537  $subFolders[] = $fileInfo->getFilename();
538  }
539  return $subFolders;
540  }
541 
542  /**
543  * @brief returns an multidimensional array containing subfolders + files of given folder
544  * @param string $folder to get files from
545  * @return array|null
546  */
547  static function ritit($folder)
548  {
549  if (isset($folder) && (!empty($folder) && (is_string($folder))))
550  {
551  $ritit = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($folder, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::CHILD_FIRST);
552  $r = array();
553  foreach ($ritit as $splFileInfo) {
554 
555  $path = $splFileInfo->isDir()
556  ? array($splFileInfo->getFilename() => array())
557  : array($splFileInfo->getFilename());
558 
559  for ($depth = $ritit->getDepth() - 1; $depth >= 0; $depth--) {
560  $path = array($ritit->getSubIterator($depth)->current()->getFilename() => $path);
561 
562  }
563  $r = array_merge_recursive($r, $path);
564  }
565  if (is_array($r))
566  {
567  return $r;
568  }
569  else
570  {
571  return null;
572  }
573  }
574  else
575  {
576  return null;
577  }
578  }
579 
580  /**
581  * @brief calculate filesize from bytes
582  * @author Daniel Retzl <[email protected]>
583  * @copyright 2009-2016 Daniel Retzl
584  * @license https://opensource.org/licenses/MIT
585  * @param int|string $bytes
586  * @param int|string $precision how many decimal places?
587  * @return string rounded, human-readable bytes
588  */
589  static function sizeFilter($bytes, $precision)
590  {
591  // if no precision is set
592  if (!isset($precision) || (empty($precision)))
593  { // set default: no decimal place
594  $precision = 0;
595  }
596  // different sizes
597  $label = array('B', 'KB', 'MB', 'GB', 'TB', 'PB');
598  // calculate filesize
599  for ($i = 0; $bytes >= 1024 && $i < (count($label) - 1); $bytes /= 1024, $i++) ;
600  // return calculated filesize
601  return (round($bytes, $precision) . " " . $label[$i]);
602  } // end class filter
603 
604 
605  /**
606  * @brief Fast generation of a complete uptodate mime types list
607  * @return bool|string
608  */
609  static function getCurrentMimeTypes()
610  {
611  $url = "http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types";
612  $s=array();
613  foreach(@explode("\n",@file_get_contents($url))as $x)
614  if(isset($x[0])&&$x[0]!=='#'&&preg_match_all('#([^\s]+)#',$x,$out)&&isset($out[1])&&($c=count($out[1]))>1)
615  for($i=1;$i<$c;$i++)
616  $s[]='&nbsp;&nbsp;&nbsp;\''.$out[1][$i].'\' => \''.$out[1][0].'\'';
617  return @sort($s)?'$mime_types = array(<br />'.implode($s,',<br />').'<br />);':false;
618  }
619  }
620 }
$folder
Definition: actions.php:9
print $lang['FILEMAN_UPLOAD']
die
Definition: block-user.php:27
Basic File Manager (Backend)
Definition: filemanager.php:17
static subdirToOptions($path)
all folders in $path as select <option>...</option>
Definition: filemanager.php:91
static countFilesFromFolder($folder)
count files from folder
static getUploadMaxFilesize()
get and return upload max filesize value from phpinfo()
static getFilesFromFolderToArray($folder)
returns an array containing only files from folder (no subfolders)
static ritit($folder)
returns an multidimensional array containing subfolders + files of given folder
__construct()
filemanager constructor. check if all media subfolder exists, if not, try to create them
Definition: filemanager.php:23
static recursiveRemoveDirectory($directory)
Delete a directory recursive.
static getPhpMaxUploadSize()
get and return PHP max file size setting
static deleteItem($file)
delete file from folder
static getFilesFromFolder($folder, $lang)
returns a list of all files in given folder. expect $folder as string
static removeSpecialChars($string)
remove special chars as well as leading and trailing slashes from string
static getPostMaxSize()
get and return post_max_size value from phpinfo()
static getFilesOnlyFromFolder($folder)
output a list showing only files from folder (no subfolders)
static drawTableFooter()
draw: output html end table body, end table
Definition: filemanager.php:81
static sizeFilter($bytes, $precision)
calculate filesize from bytes
static getSubfoldersToArray($folder)
returns an array containing only files from folder (no subfolders)
static getCurrentMimeTypes()
Fast generation of a complete uptodate mime types list.
static drawTableHeader($lang, $i)
draw the table header with labeling
Definition: filemanager.php:53
This class serves methods to create backup from files.
Definition: AdminLTE.php:2
print $_GET['id']
Definition: page-edit.php:357
$url
Definition: user-new.php:101
$i