File Manager
This class implements the File Manager.
This class is also used to browse files and images from FCKEditor. Distinction is made via the $job parameter in the constructor.
All the work is directed from the constructor, so it is enough to simply instantiate a new object and let the constructor do the work. The only thing needed is an output object (see AdminOutput).
Located in /program/lib/filemanager.class.php (line 67)
construct a FileManager object (called from /program/main_admin.php)
This initialises the FileManager, checks user permissions and finally dispatches the tasks. If the specified task is not recognised, the default task TASK_LIST_DIRECTORY is executed.
Note that many commands act on the directory contained in the SESSION-variable current_directory.
convert a comma-delimited list of allowable extensions to an array (or FALSE if none are allowed)
this converts the comma-delimited list of allowable filename extensions to an array with one element per allowable extension OR to a boolean with value FALSE if no allowable extensions are specified. The input is converted to lower case and also spaces and dots are removed (in anticipation of users entering the bare extension with the dot while we use the bare extension here. Also, it appears very natural to specify a list including spaces (which we don't want), so there.
callback for comparing two directory entries by mtime
Comparison between a file and a directory always shows directories first.
callback for comparing two directory entries by date (descending)
Comparison between a file and a directory always shows directories first, nevermind that we are sorting in descending order.
callback for comparing two directory entries by filename
Comparison between a file and a directory always shows directories first.
callback for comparing two directory entries by filename (descending)
Comparison between a file and a directory always shows directories first, nevermind that we are sorting in descending order.
callback for comparing two directory entries by size
Comparison between a file and a directory always shows directories first.
callback for comparing two directory entries by size (descending)
Comparison between a file and a directory always shows directories first, nevermind that we are sorting in descending order.
callback for comparing two group records
This routine is used to order a list of groups by full_name, groupname.
workhorse function that actually removes directories
This routine first deletes the files "index.html" and "THUMBNAIL_PREFIX*" in the directory to remove and subsequently the directory itself. This is more or less the reverse of the mkdir function (see task_add_directory()) but with a twist: we consider any remaining thumbnails as trash and we will happily delete those without further ado.
If anything goes wrong, the routine returns FALSE and some details are written to the logfile. Note that if the directory somehow contains symlinks or devices or named pipes we bail out: we cannot handle those kinds of directory entries.
Note that the routine is able to delete an array of directories, even though it is currently called/used with only a single entry. We don't want to make it too easy to remove many directories at once (an attempt to protect the user against herself).
workhorse function that actually deletes files, and possibly the corresponding thumbnails
This routine deletes the files specified in the array $entries from directory $path. If a thumbnail-file exists (ie. a file with a similar name but with the THUMBNAIL_PREFIX prepended), it is deleted too.
shorthand for splitting a path into an array with path components
This routine splits $path into components. Path components are supposed to be delimited with a forward slash '/', but if somehow a backslash '\' is encountered, it is translated to a forward slash first. This means that it is impossible to have backslashes as part of a path name, even though the underlying filesystem would happily accept a component (filename or directoryname) with an embedded backslash.
construct a url that links to a file via /file.php
This constructs a URL that links to a file, either
Note: If $path contains special characters such as '%' or '#' these are encoded via rawurlencode(). However, the path delimiter '/' (ascii 0x2F) is changed back to a genuine '/' to make $path look like a path.
construct a dialog definition for adding a subdirectory
this constructs an array which defines the dialog
construct a dialog definition for adding (uploading) files
this constructs an array which defines a file(s) upload dialog. Note that we make a subtle difference between a single-file upload and a multifile upload: I think it looks stupid to start numbering a list of files to upload when there is in fact only a list of exactly 1 file(s). The cost is minimal: two extra strings in the translation file.
By using the fieldname 'filename[]', ie. a name ending in '[]' we tell PHP to store the uploaded file information in an array rather than in $num_files separate entries in the global $_FILES[] array. This has a huge advantage that any 'multiple' file uploads, ie. a comma-delimited list of filenames as supported by many browsers since Firefox 3.6 in a single file upload widget, all end up in max 5 arrays. In other words: we can work with the 0-based arrays $_FILES['filename']['name'][], $_FILES['filename']['type'][], $_FILES['filename']['tmp_name'][], $_FILES['filename']['error'][] and $_FILES['filename']['size'][]. This is independent from the actual number of file input elements in the dialog. It requires setting the property 'multiple' to TRUE though. (Multiple upload feature was added July 2014)
construct a dialog definition for removing/deleting a subdirectory
this constructs an array which defines the confirmation dialog
construct a dialog definition for removing/deleting files
this constructs an array which defines the confirmation dialog
generate a list of selected files and subdirectories in $path
This creates an array containing a (filtered) listing of the directory $path, keyed by filename. we items are suppressed:
generate a list of (virtual) directories for areas the user can access
This generates a list of (virtual) area directories for which the user has access permissions. The list is ordered based on the sort order (in the areas table).
generate a list of (virtual) directories for groups the user can access
This generates a list of (virtual) group directories for which the user has access permissions. The list is ordered by groupname.
generate a list of (virtual) directories at the root level
This generates a list of up to 4 'directories' which are equivalent to 'My Files', 'Areas', 'Groups' and 'Users'. Permissions and group memberships are taken into account, i.e. if a user has no group memberships (and is not an account manager), the 'Groups' directory is suppressed.
generate a list of (virtual) directories for users this user can access
This generates a list of (virtual) user directories for which this user has access permissions. The list is ordered by full name.
maximum number of files accepted in a single upload (since PHP 5.2.12)
This retrieves the INI-file setting for the maximum number of files that can be uploaded in a single go (PHP 5.2.12+) OR an educated guess equal to the default value in PHP 5.2.12 (which happens to be 20). In the latter case this limit isn't actually a limit but we use it to inform the user about limits. Most users will probably have upgraded to a PHP-version newer than 5.2.12 anyway making this a moot issue...
see if the filename extension is allowed
Note that an 'empty' extension could be acceptable.
convert an integer filesize to a human readable form
This routine displays a file size in bytes, kilobytes, megabytes or gigabytes or bytes with space-delimited groups of 3 digits depending on the size. No decimals are used.
try to make sure that the extension of file $name makes sense or matches the actual filetype
this checks or changes the $name of the file in line with the mimetype of the actual file (as established by get_mimetype()).
The reason to do this is to make it harder to 'smuggle in' files with deceptive filenames/extensions. Quite often the extension is used to determine the type of the file, even by browsers that should know better. By uploading a malicious .PDF using an innocuous extension like .TXT, a browser may be tricked into rendering that .PDF inline. By changing the extension from .TXT to .PDF we can mitigate that risk, at least a little bit. (People somehow trust an extension even though they should know better and file(1) says so...)
Strategy is as follows. If the mimetype that corresponds to the extension matches the actual mimetype determined via get_mimetype(), we can simply allow the name provided.
If there is a difference, we try to find an extension that maps to the same mimetype as that of the actual file. IOW: we put more trust in the mimetype of the actual file than we do in the mimetype suggested by the extension.
If no suitable extension is available (based on the calculater mimetype) we simply use 'bin'. This changes the filename and the caller will probably reject this upload anyway because of this.
move the uploaded file in place or perhaps resize it first (supported images only) + create thumb
this routine performs the actual adding/moving of the uploaded file to its final destination. If the file is NOT a supported image, the effect is the same as that of the standard function move_uploaded_file(): the file is moved from the temporary location (e.g. /tmp/phpAE45Rg) to the destination within the $CFG->datadir (e.g. /areas/exemplum/sample.txt).
If the file happens to be a supported graphical file, e.g. a .GIF, a .JPG or a .PNG-file, the story is different. In that case we attempt to create a thumbnail of the source file first. The dimensions of this thumbnail are determined by a parameter in the global $CFG, e.g. a box of 100x100 pixels. After that and depending on the flage $resize, we create another copy of the sourcefile, but with a different box (say 800x800), again based on a parameter in the global $CFG.
If somehow the scaling appears to fail, we eventually resort to moving the file anyway in order to not leave the user empty-handed after uploading the file.
If everything fails, we return FALSE, TRUE on success.
The strategy is as follows. First we determine whether this is actually a graphics file and whether GD is available. Then we decide if scaling is needed at all. If the file is of one of the currently supported image formats, we load the file, resample it and write the resulting (smaller) image to a file which name is prepended with the thumbnail prefix. We then either move to original file (depending on the existing dimensions and the $resize flag) or create a bigger smaller version.
The following cases are possible (assuming dimension=100 for thumbs, 800 for resized images)
A. source dimension <= 100: move the source file to target
B. 100 < source dimension <= 800 load the image, create a thumbnail, move the source file to target
C. 800 < source dimension && $resize == FALSE load the image, create a thumbnail, move the source file to target
D. 800 < source dimension && $resize == TRUE load the image, create a thumbnail, create resized a target (and leave source file untouched)
Design considerations:
display a clickable path to the directory $path
display the file upload dialog
this displays the file upload dialog, including the message which reminds the user of the limits that are currently in place (in bytes).
show a dialog that ask the user to confirm the removal of a directory
Show the first directory from $entries_to_delete and ask the user to confirm with [Delete] button or to cancel with [Cancel] button. The name of the directory to delete is part of the href rather than a POSTed field. We only allow a single directory to be removed at a time.
show a dialog that ask the user to confirm a mass file delete
Show a list of files from $entries_to_delete and ask the user to confirm with [Delete] button or to cancel with [Cancel] button. The names of the files to delete are communicated via hidden fields. Once the form is submitted the data is validated against the existing files in the directory $path.
output a simple list of directories (for navigation only)
This outputs a simple list of subdirectories based on information in the array $entries. The subdirectories can not be deleted and no files or subdirectories can be added. (because this is either '/', 'Areas','Groups' or 'Users')
display a list of subdirectories and files in directory $path
This long routine displays the following items to the user
The checkbox 'select all' works with Javascript in the most simple way: an ad-hoc script connected to the onclick attribute of the select all checkbox. However, the select all checkbox itself is rendered via Javascript. The effect is that this feature is only available if Javascript is enabled in the browser. If it isn't, no select all is visible so it can not distract the user. This is part of the attempt to make this CMS usable even without Javascript.
If the flag $show_thumbnails is set we display file entries as thumbnails. This is done mostly to cater for the visual interactieve selection of images from FCK Editor.
show a thumbnail of a single (image) file perhaps including clickable links for use in FCK Editor
This constructs a single clickable image with either a selection of the file (for FCK Editor, in file/image browser mode) or a link to the file preview. If a file is not an image or otherwise no suitable thumbnail is found, a large question mark is displayed (unknown.gif). Otherwise the existing thumbnail is shown, maintaining the original aspect ratio. Either way the image is scaled to the currently specified thumbail dimension so the image fits the corresponding DIV-tag.
The strategy for finding a thumbnail is as follows: - is the file to show an image at all? If not, show unknown.gif - if the file zz_thumb_{filename.ext} exists, use that, otherwise - if not AND the original file is smaller than a thumbnailm use the original file, otherwise - use 'unknown.gif' after all.
If the flag $delete_file is set, we also generate a checkbox and a delete icon. This means that even in file/image browser mode files can be deleted by the user. In fact the file/image browser is basically the same old filemanager.
display a list of directories and files in $path
This yields a list of directories (for $path is '/', '/areas', '/groups' or '/users') or a list of directories and files ($path is anything else). In the latter case, if the current user has sufficient permissions, various additional links are added such as upload a file or create directory. The actual work is done in two separate workhorses.
show a menu that is equivalent with the root directory
sort directory entries
create a new subdirectory
This routine either shows a dialog where the user can specify the name of a new directory to add OR processes the dialog.
In case of directory name too short, already exists, etc. the user is returned to the dialog to try again. If all goes well the new directory is created and at the same time the empty file 'index.html' is created to "protect" the directory from prying eyes.
add one or more new files to a directory
This routine either shows a dialog where the user can specify the names of one or more (maximum $CFG->upload_max_files) files OR processes the dialog.
Various checks are performed before the files are actually saved, e.g. checks for viruses (via ClamAV), resolve name clashes, allowed filetypes and extensions, etc. This is all done in a separate worker routine.
make another directory the current (working) directory and optionally change the sort order
This changes the current working directory to the user-supplied path (after thorough validation, naturally). The new current directory is stored in $this->current_directory and via that reference in the $_SESSION array, for future reference. If a valid directory was specified, we also take a look at the optional sort order parameter and set the sort order of the directory listing accordingly.
After (perhaps) changing the current directory, and perhaps changing the sort order, the contents of that directory is displayed via task_list_directory().
show a directory listing of the current working directory and links to add/delete files/directories etc.
This is the main routine to show a list of subdirectories and files in the current working directory ($_SESSION['current_directory']).
preview a file via file.php
After validation of the specified path, the user is redirected to file.php in order to show the selected file.
show a confirmation dialog for removing a single directory OR actually removes a directory
This shows a confirmation dialog for removing of a single directory OR actually removes a directory.
show a confirmation dialog for deleting a single file
This shows a confirmation dialog for deletion of a single file. We reuse the code for deletion of multiple files, see task_remove_multiple_files().
show confirmation dialog for multiple file delete OR perform actual file delete
this routine either shows a list of files to be deleted, asking the user for confirmation or actually deletes the specified files if the user did confirm the delete. We bail out if the user pressed the cancel button in the confirmation dialog. The real work is done in workhorse routines in order to combine the single-file-delete and the batch-delete into a single confirmation routine. For actual deletion, however, we always return here and not in the single file delete (see {$link task_remove_file()}).
construct a unique filename taking existing files into account
this constructs a filename that is unique within the target directory. If a file of the name $name already exists, a new name is constructed from the basename of $name, an integer sequence number and the extension of $name.
There is no guarantee that this name will stay uniqe between the moment we test for it and the moment the file is actually moved into place (a classical race condition). However, the chance that this will be happening is small enough I guess.
access control and validation for selected directory or file
This routine checks to see if the current user has access to the specified file or directory. If not, FALSE is returned, otherwise the valid path is returned, with a starting slash. If $path doesn't start with a slash a slash is assumed nevertheless. The path is relative to $CFG->datadir.
It is not allowed to reference parent directories in the path. This prevents tricks like '../../../etc/passwd' (leaking the system passwd file) or '/users/foo/../bar' (access to bar's userdata with permissions for just foo's files). Furthermore, symbolic links are NOT acceptable as part of the path, i.e. symlinks like '/users/foo/etc -> /etc' or '/users/foo/passwd -> /etc/passwd' are considered invalid.
Required permissions for access are:
scan a file for viruses
this scans $path for viruses, returns 0 if file considerd clean, 1 for infected file, or 2 if something else went wrong.
If the flag $CFG->clamscan_mandatory is set, we consider the file infected if we are not able to run the virus scanner (better safe than sorry). However, if no virusscanner is configured at all ($CFG->clamscan_path is empty), we indicate a 'clean' file even though we did not scan it. Rationale: it doesn't make sense to make scanning mandatory and at the same time NOT configuring a scanner at all.
If scanning succeeds and a virus is found we send an alert to the website owner address (or the reply-to-address) immediately. Furthermore everything is logged.
construct the (possibly translated) name of the last directory in the path
This examines $path and returns a string with the last directory component. There are a few special cases:
translate a path to the corresponding virtual path
This translates a path like '/users/webmaster/foo' into 'My Files/foo' and '' into 'All Files', etc. The result of the translation is cached in $this->vpaths, for future reference.
Documentation generated on Tue, 28 Jun 2016 19:09:22 +0200 by phpDocumentor 1.4.0