Class FileManager

Description

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)


	
			
Variable Summary
 null|array $areas
 bool|array $ext_allow_browse
 bool|array $ext_allow_upload
 string $job
 object|null $output
 int $sort
 null|array $usergroups
 array $vpaths
Method Summary
 void FileManager (object &$output, [string $job = JOB_FILEMANAGER])
 bool|array allowed_extensions (string $allowed_extensions_list)
 int cmp_entries_bydate_asc (array $a, array $b)
 int cmp_entries_bydate_desc (array $a, array $b)
 int cmp_entries_byfile_asc (array $a, array $b)
 int cmp_entries_byfile_desc (array $a, array $b)
 int cmp_entries_bysize_asc (array $a, array $b)
 int cmp_entries_bysize_desc (array $a, array $b)
 int cmp_groups (array $a, array $b)
 bool delete_directory (string $path,  $directories, array $entries)
 bool delete_files (string $path, array $entries)
 array explode_path (string $path)
 string file_url (string $path)
 array get_dialogdef_add_files ([int $num_files = 1])
 array get_dialogdef_confirm_delete_files (array $entries_to_delete)
 array get_entries (string $path)
 array get_entries_root ()
 bool has_allowed_extension (string $filename, bool|array &$extensions)
 string human_readable_size (int $size)
 string sanitise_filetype (string $path, string $name, string $type, string $mimetype)
 bool save_uploaded_file (string $full_source_path, string $target_directory, string $target_name, bool $resize)
 void show_breadcrumbs (string $path)
 void show_dialog_add_files (array $dialogdef, string $href, string $path)
 dialog show_dialog_confirm_delete_directory (array $dialogdef, string $path, array $entries_to_delete)
 dialog show_dialog_confirm_delete_files (array $dialogdef, string $path, array $entries_to_delete)
 void show_directories (array &$entries, bool|string $parent)
 void show_directories_and_files (string $path, [bool $show_thumbnails = TRUE])
 output show_file_as_thumbnail (string $directory, array $entry, bool $delete_file, int $index, [string $m = ''])
 void show_list (string $path)
 void show_menu ([string $current_path = ''])
 void sort_entries (array &$entries,  $sort, int $sortorder)
 void task_add_file ()
 string unique_filename (string $directory, string $name)
 string|bool valid_path (string $path)
 int virusscan (string $path, [string $name = ''])
 string vname (string $path)
 string vpath (string $path)
Variables
null|array $areas = NULL (line 75)
  • var: $areas holds all area records (for future reference) or NULL if not yet set
string $current_directory (line 84)
  • var: $current_directory links to the session-variable that holds the current working directory
bool|array $ext_allow_browse = FALSE (line 93)
  • var: $ext_allow_browse holds brwosable filename extensions (lowercase), FALSE (none) or TRUE (all)
bool|array $ext_allow_upload = FALSE (line 90)
  • var: $ext_allow_upload holds uploadable filename extensions (lowercase), FALSE (none) or TRUE (all)
string $job (line 72)
  • var: $job indicates how we are called (eg. as 'filemanager' or as 'filebrowser' or 'imagebrowser')
object|null $output = NULL (line 69)
  • var: $output collects the html output
bool $show_thumbnails = FALSE (line 96)
  • var: $show_thumbnails if TRUE we display files graphically (as a thumbnail), otherwise in table format
int $sort = SORTBY_FILE_ASC (line 87)
  • var: $sort holds the current sort order in directory listings (default SORTBY_FILE_ASC)
null|array $usergroups = NULL (line 78)
  • var: $usergroups holds all $USER's group records (for future reference) or NULL if not yet set
array $vpaths = array() (line 81)
  • var: $vpaths is a cache of virtual paths (see vpath())
Methods
Constructor FileManager (line 112)

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.

  • return: results are returned as output in $this->output
  • todo: a nice filter for JOB_IMAGEBROWSER and also an alternative user interface for browsing/selecting images
void FileManager (object &$output, [string $job = JOB_FILEMANAGER])
  • object &$output: collects the html output
  • string $job: indicates the mode: filemanager, filebrowser (FCKEditor) or imagebrowser (FCKEditor)
allowed_extensions (line 3062)

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.

  • return: array with acceptable extensions or FALSE if none are acceptable
bool|array allowed_extensions (string $allowed_extensions_list)
  • string $allowed_extensions_list: comma-delimited string with allowable extensions (or empty string)
cmp_entries_bydate_asc (line 2257)

callback for comparing two directory entries by mtime

Comparison between a file and a directory always shows directories first.

  • return:
    1. if equal, negative if $a comes before $b, positive otherwise
int cmp_entries_bydate_asc (array $a, array $b)
  • array $a: first entry
  • array $b: second entry
cmp_entries_bydate_desc (line 2283)

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.

  • return:
    1. if equal, negative if $a comes before $b, positive otherwise
int cmp_entries_bydate_desc (array $a, array $b)
  • array $a: first entry
  • array $b: second entry
cmp_entries_byfile_asc (line 2165)

callback for comparing two directory entries by filename

Comparison between a file and a directory always shows directories first.

  • return:
    1. if equal, negative if $a comes before $b, positive otherwise
int cmp_entries_byfile_asc (array $a, array $b)
  • array $a: first entry
  • array $b: second entry
cmp_entries_byfile_desc (line 2186)

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.

  • return:
    1. if equal, negative if $a comes before $b, positive otherwise
int cmp_entries_byfile_desc (array $a, array $b)
  • array $a: first entry
  • array $b: second entry
cmp_entries_bysize_asc (line 2206)

callback for comparing two directory entries by size

Comparison between a file and a directory always shows directories first.

  • return:
    1. if equal, negative if $a comes before $b, positive otherwise
int cmp_entries_bysize_asc (array $a, array $b)
  • array $a: first entry
  • array $b: second entry
cmp_entries_bysize_desc (line 2232)

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.

  • return:
    1. if equal, negative if $a comes before $b, positive otherwise
int cmp_entries_bysize_desc (array $a, array $b)
  • array $a: first entry
  • array $b: second entry
cmp_groups (line 2122)

callback for comparing two group records

This routine is used to order a list of groups by full_name, groupname.

  • return:
    1. if equal, negative if $a < $b, positive if $a > $b
int cmp_groups (array $a, array $b)
  • array $a: first array with groupdata (straight copy from database record)
  • array $b: second array with groupdata (straight copy from database record)
delete_directory (line 1593)

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).

  • return: TRUE on success, FALSE on error (+ messages written to log)
  • uses: $CFG
bool delete_directory (string $path,  $directories, array $entries)
  • string $path: the directory containing the directories to delete
  • array $entries: list of subdirectories to delete, keyed by subdirectory name
  • $directories
delete_files (line 1544)

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.

  • return: TRUE on success, FALSE on error (+ messages written to log)
  • uses: $CFG
bool delete_files (string $path, array $entries)
  • string $path: the directory containing the files to delete
  • array $entries: list of files to delete
explode_path (line 1735)

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.

  • return: broken down path
array explode_path (string $path)
  • string $path: the path to split
file_url (line 2704)

construct a url that links to a file via /file.php

This constructs a URL that links to a file, either

    /file.php/path/to/file.txt
or
    /file.php?file=/path/to/file.txt
depending on the global setting for proxy-friendly urls. Note that we try to make the link as short as possible, eg. by omitting the http:// part if possible (see $CFG->www_short).

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.

  • return: ready to use URL
string file_url (string $path)
  • string $path: the name of the file including path
get_dialogdef_add_directory (line 2384)

construct a dialog definition for adding a subdirectory

this constructs an array which defines the dialog

  • return: with dialog definition keyed on field name
array get_dialogdef_add_directory ()
get_dialogdef_add_files (line 2324)

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)

  • return: with dialog definition keyed on field name
  • uses: $CFG
array get_dialogdef_add_files ([int $num_files = 1])
  • int $num_files: the maximum number of file upload fields to add to the dialog (default 1)
get_dialogdef_confirm_delete_directory (line 2448)

construct a dialog definition for removing/deleting a subdirectory

this constructs an array which defines the confirmation dialog

  • return: with dialog definition keyed on field name
array get_dialogdef_confirm_delete_directory ()
get_dialogdef_confirm_delete_files (line 2412)

construct a dialog definition for removing/deleting files

this constructs an array which defines the confirmation dialog

  • return: with dialog definition keyed on field name
array get_dialogdef_confirm_delete_files (array $entries_to_delete)
  • array $entries_to_delete: contains information about the files to delete
get_entries (line 1967)

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:

  • current directory '.'
  • parent directory '..'
  • index.html if it has size 0 (used to 'protect' directory against prying eyes)
  • THUMBNAIL_PREFIX* the thumbnails of images
  • symbolic links

  • return: list of available files and subdirectories
  • uses: $CFG;
array get_entries (string $path)
  • string $path: the directory to list, e.g. '/areas/exemplum' or '/groups/faculty'
get_entries_areas (line 1824)

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).

  • return: list of available areas for this user
  • uses: $USER;
  • uses: $CFG;
array get_entries_areas ()
get_entries_groups (line 1860)

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.

  • return: list of available group directories for this user
  • uses: $USER;
  • uses: $CFG;
array get_entries_groups ()
get_entries_root (line 1752)

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.

  • return: list of directories at the root level
  • uses: $USER
  • uses: $CFG
array get_entries_root ()
get_entries_users (line 1908)

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.

  • return: list of available user directories for this user
  • uses: $USER;
  • uses: $CFG;
array get_entries_users ()
get_max_file_uploads (line 3079)

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...

  • return: maximum number of file uploads
int get_max_file_uploads ()
has_allowed_extension (line 3033)

see if the filename extension is allowed

Note that an 'empty' extension could be acceptable.

  • return: TRUE if allowed, FALSE otherwise
bool has_allowed_extension (string $filename, bool|array &$extensions)
  • string $filename: the filename to examine
  • bool|array &$extensions: array with allowable extensions or FALSE for none or TRUE for all
human_readable_size (line 2099)

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.

  • return: readable form of $size
string human_readable_size (int $size)
  • int $size: value to convert
sanitise_filetype (line 2599)

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.

  • return: the sanitised name and extension based on the file type
string sanitise_filetype (string $path, string $name, string $type, string $mimetype)
  • string $path: full path to the actual file (from $_FILES[$i]['tmp_name'])
  • string $name: the requested name of the file to examine (from $_FILES[$i]['name'])
  • string $type: the suggested filetype of the file (from $_FILES[$i]['type'])
  • string $mimetype: actual mimetype based on $path
save_uploaded_file (line 2781)

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:

  • we use square boxex (of $thumb_dimension or $resize_dimension) to fit the images
  • we do not create thumbnails for images smaller than that square box
  • we do not create resized images if they are already smaller than $resize_dimension
  • the aspect ratio is preserved
  • we use default quality settings for write jpeg and png thumbnails
  • all errors are logged, successes are logged to WLOG_DEBUG
  • this routine relies on GD
  • we try to extend our stay with set_time_limit() every time a thumbnail is created because image processing is quite time-consuming
Note that we only use GD to create thumbnails. I did consider Imagick, but eventually I decided against it because it appears that support for that extension requires PHP 5.1.3. Perhaps we can add support in a later version of the FileManager.

  • return: FALSE on failure, TRUE on success
bool save_uploaded_file (string $full_source_path, string $target_directory, string $target_name, bool $resize)
  • string $full_source_path: absolute path of the uploaded file
  • string $target_directory: the working directory (relative to $CFG->datadir)
  • string $target_name: the name of the image file (including extension if any)
  • bool $resize: if TRUE, resize image files on the fly, move uploaded file otherwise
show_breadcrumbs (line 1375)

display a clickable path to the directory $path

  • return: output stored via $this->output
void show_breadcrumbs (string $path)
  • string $path: the directory path to show
show_dialog_add_files (line 1453)

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).

  • return: output sent to browser
  • todo: should we take the locale into account formatting numbers (thousands separator)?
void show_dialog_add_files (array $dialogdef, string $href, string $path)
  • array $dialogdef: defines the upload dialog
  • string $href: the target for POSTing data
  • string $path: is the target directory
show_dialog_confirm_delete_directory (line 1514)

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.

  • return: is displayed via $this->output
dialog show_dialog_confirm_delete_directory (array $dialogdef, string $path, array $entries_to_delete)
  • array $dialogdef: defines the confirmation dialog
  • string $path: the working directory
  • array $entries_to_delete: an array with directory entries identifying the files to delete
show_dialog_confirm_delete_files (line 1480)

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.

dialog show_dialog_confirm_delete_files (array $dialogdef, string $path, array $entries_to_delete)
  • array $dialogdef: defines the confirmation dialog
  • string $path: the working directory
  • array $entries_to_delete: an array with directory entries identifying the files to delete
show_directories (line 1333)

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')

void show_directories (array &$entries, bool|string $parent)
  • array &$entries: ready to use data describing all subdirectories to show
  • bool|string $parent: suppress link to parent if FALSE otherwise path of parent
show_directories_and_files (line 971)

display a list of subdirectories and files in directory $path

This long routine displays the following items to the user

  • (optional) navigation link to add (upload) a file
  • (optional) navigation link to add (create) a directory
  • a 4, 5 or 6 column table with . navigation link to the parent directory . 0, 1 or more rows with delete and navigation links to subdirectories (if any) . 0, 1 or more rows with a checkbox and delete and preview links to files (if any) . (optional) a 'select all' checkbox
  • (optional) Delete-button to mass-delete files
The table can be ordered in various ways: by name, by size and by date, either ascending or descending. Clicking the relevant column header yields another sort order. This toggles between ascending and descending. Default sort order is by name ascending.

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.

  • return: output generated via $this->output
  • todo: This routine is way too long, it should be split up into smaller subroutines
  • usedby: FileManager::show_list()
  • uses: $WAS_SCRIPT_NAME
  • uses: $USER
  • uses: $CFG
void show_directories_and_files (string $path, [bool $show_thumbnails = TRUE])
  • string $path: the directory to display
  • bool $show_thumbnails: if TRUE files are displayed as thumbnails, table rows otherwise
show_file_as_thumbnail (line 2920)

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.

  • return: generated via $this->output
  • uses: $WAS_SCRIPT_NAME
  • uses: $CFG
output show_file_as_thumbnail (string $directory, array $entry, bool $delete_file, int $index, [string $m = ''])
  • string $directory: the current working directory (necessary to construct (full) paths)
  • array $entry: information about the file to show, see get_entries() for the format
  • bool $delete_file: if TRUE, user is allowed to delete the file (used for creating delete icon)
  • int $index: a counter used to generate a unique field name for the checkbox
  • string $m: optional margin for better code readability
show_list (line 906)

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.

void show_list (string $path)
  • string $path: the (virtual) path to the directory to list
show_menu (line 1418)

show a menu that is equivalent with the root directory

  • return: menu is displayed via $this->output
void show_menu ([string $current_path = ''])
  • string $current_path: indicator for highlighting the current directory subtree
sort_entries (line 2142)

sort directory entries

  • return: entries array sorted
  • todo: it is a pity I cannot reference $this->sort from within the 6 cmp-functions...
void sort_entries (array &$entries,  $sort, int $sortorder)
  • array &$entries: array with directory entries
  • int $sortorder
  • $sort
task_add_directory (line 677)

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.

  • return: output returned via $this->output
void task_add_directory ()
task_add_file (line 472)

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.

  • return: output returned via $this->output
void task_add_file ()
task_change_directory (line 221)

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().

  • return: current directory changed and directory listing sent to browser via $this->output
void task_change_directory ()
task_list_directory (line 195)

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']).

  • return: current directory listing sent to browser via $this->output
void task_list_directory ()
task_preview_file (line 240)

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.

  • return: user is redirected to file.php
void task_preview_file ()
task_remove_directory (line 387)

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.

  • return: confirmation dialog sent to browser via $this->output
void task_remove_directory ()
task_remove_file (line 344)

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().

void task_remove_file ()
task_remove_multiple_files (line 261)

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()}).

void task_remove_multiple_files ()
unique_filename (line 2654)

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.

  • return: a filename that is not yet existing in $directory
  • todo: Should we take care of the race condition in this routine? Should we already create an empty file or is that clutter?
  • uses: $CFG
string unique_filename (string $directory, string $name)
  • string $directory: the target directory for the file upload
  • string $name: the (sanitised) name of the file
valid_path (line 811)

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:

  • areas: $USER must have the admin_pagemanager permissions for that area.
  • groups: $USER must be a member of that group OR $USER must have access to the Account Manager.
  • users: $USER must be that user OR $USER must have access to the Account Manager.

  • return: a clean version of $path starting with a slash, FALSE otherwise
  • todo: the check on '/../' is inconclusive if the $path is encoded in UTF-8: the overlong sequence 2F C0 AE 2E 2F eventually yields 2F 2E 2E 2F or '/../'. Reference: RFC3629 section 10.
  • uses: $USER
  • uses: $CFG
string|bool valid_path (string $path)
  • string $path: the path (file or directory) to check, relative to $CFG->datadir
virusscan (line 2487)

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.

  • return: return 0 if clean, 1 if infected, 2 if other error
  • todo: This routine is quite *nix-centric. I'm not sure how this would work other server platforms. Should we do something about that?
  • todo: maybe use MIME for sending alert if not 7bit message?
  • uses: $USER
  • uses: $CFG
int virusscan (string $path, [string $name = ''])
  • string $path: the path of the file to scan
  • string $name: the name of the file as provided by the uploader (from $_FILES)
vname (line 1664)

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:

  • the empty string indicates the root directory
  • /users/<userpath> maps to a (translated) string t('filemanager_personal')
  • /areas maps to a (translated) string t('filemanager_areas')
  • /groups maps to a (translated) string t('filemanager_groups')
  • /users maps to a (translated) string t('filemanager_users')
All other variations yield the last component in the list of components.

  • return: the (possibly translated) name of the last directory component
string vname (string $path)
  • string $path: the path to examine
vpath (line 2032)

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.

  • return: the translated path
string vpath (string $path)
  • string $path: the path to translate

Documentation generated on Tue, 28 Jun 2016 19:09:22 +0200 by phpDocumentor 1.4.0