File/program/main_file.php

Description

/program/main_file.php - workhorse for serving files

This file deals with serving files It is included and called from /file.php.

The work is done in main_file().

Functions
download_source (line 346)

construct a zipfile with the current source and stream it to the visitor

this routine streams a ZIP-archive to the visitor with either the current websiteatschool program code or the selected manual. This routine is necessary to comply with the provisions of the program license which basically says that the source code of the running program must be made available.

Note that it is not strictly necessary to also provide the manual, but this routine can do that nevertheless.

Note that we take special care not to download the (private) data directory $CFG->datadir. Of course the datadirectory should live outside the document root and certainly outside the /program directory tree, but accidents will happen and we don't want to create a gaping security hole.

If there are severe errors (e.g. no manual is available for download or an invalid component was specified) the program exist immediately with a 404 not found error. Otherwise the ZIP-archive is streamed to the user. If all goes well, we return TRUE, if there were errors we immediately return TRUE (without finishing the task at hand other than a perhasp futile attempt to properly close the ZIP-archive). The last error message from the Zip is logged.

  • return: Exit with 404 not found, OR TRUE and generated ZIP-file sent to user OR FALSE on error
  • uses: download_source_tree()
void|bool download_source (string $component)
  • string $component: either 'program' or 'manual' or 'languages'
download_source_tree (line 478)

workhorse function to recursively add most of a tree to a ZIP-archive

this routine recursively adds the tree starting at $path to the opened archive $zip. If a directory is in the list of excluded directories in $excludes it is skipped.

bool download_source_tree (object &$zip, string $path, string $vpath, array &$excludes)
  • object &$zip: Zip-archive
  • string $path: physical directory to add to archive
  • string $vpath: virtual pathname for this physical directory
  • array &$excludes: array with 'forbidden' subdirectories
error_exit404 (line 313)

exit with a 404 not found error

  • return: this routine never returns
void error_exit404 ([string $filename = ''])
  • string $filename: the file we were looking for and could not find
main_file (line 99)

main program for serving files

this routine is called from /file.php.

This routine is responsible for serving files to the visitor. These files are stored in a (virtual) file hierarchy that looks like this.

/areas/areaname
      /another
      /stillmore
      ...
/users/username
      /another
      /stillmore
      ...
/groups/groupname
       /another
       /stillmore
       ...
/websiteatschool/program
                /manual
                /languages

This structure maps to the real file system as follows. The (virtual) directories /areas, /users and /groups correspond to the fysical directories {$CFG->datadir}/areas, {$CFG->datadir}/users and {$CFG->datadir}/groups respectively. The subdirectories correspond to a (unique) area, user or group and serve as a file repository for that area, user or group.

The (virtual) top-level directory /websiteatschool is a special case. It is used to serve the currently running website program code and the user-defined translations of active languages.

Before any file is transmitted to the visitor the access privileges are checked. The following rules apply.

Access control for the /areas subdirectory

  • an area must be active before any files are served
  • the visitor must have access to the private area if files are to be served
  • non-existing files yield a 404 Not Found error
  • non-existing areas also yield a 404 Not Found error
  • if the visitor has no access to the private area, also a 404 Not Found error is returned
Access control for /users and /groups

  • a user/group must be active before any files are served
  • non-existing users/groups yield 404 Not Found
  • non-existing files in existing directories also yield 404 Not Found
Access control for /websiteatschool

  • there is no limit on downloading the currently active program code or user-defined translations of active languages
Note: The check on '..' in the requested filename would be inconclusive if the $path is encoded in invalid UTF-8: the overlong sequence 2F C0 AE 2E 2F eventually yields 2F 2E 2E 2F or '/../'. Reference: RFC3629 section 10. However, we use the filename processed with get_requested_filename() which already checks for utf8 validity, which rules out the trick with overlong sequences.

  • return: file sent to the browser OR 404 not found on error
void main_file ()
readfile_chunked (line 518)

send a file to the visitor's browser in chunks

This sends the file $path to the browser in manageable chunks.

  • return: FALSE on error, otherwise the number of bytes transmitted
bool|int readfile_chunked (string $path)
  • string $path: fully qualified path of the file to send
rfc1123date (line 202)

generate an RFC1123-compliant date/time stamp

This constructs a date/time stamp that is a fixed-length subset of RFC1123. This is the preferred format in HTTP (see RFC2616 section 3.3).

The format is as follows:

rfc1123-date = wkday "," SP date SP time SP "GMT"
date         = 2DIGIT SP month SP 4DIGIT             ; day month year (e.g., 02 Jun 1982)
time         = 2DIGIT ":" 2DIGIT ":" 2DIGIT          ; 00:00:00 - 23:59:59
wkday        = "Mon" | "Tue" | "Wed" | "Thu" | "Fri" | "Sat" | "Sun"
month        = "Jan" | "Feb" | "Mar" | "Apr" | "May" | "Jun" |
               "Jul" | "Aug" | "Sep" | "Oct" | "Nov" | "Dec"

If $timevalue is less or equal to zero, the current time is used, otherwies $timevalue is interpreted as a standard unix timestamp.

  • return: date/time stamp formatted according to RFC1123 (fixed length = 29)
string rfc1123date ([int $t = 0])
  • int $t: the date/time value to use, or 0 for current time
send_file_from_datadir (line 251)

the designated file is sent to the visitor

This transmits the file {$CFG->datadir}$file from the data directory to the visitor's browser, suggesting the name $name. The file is transmitted in chunks (see readfile_chunked()).

Several different variations are possible.

  • by specifying a Time To Live of 0 seconds, this routine tries hard to defeat any caching by proxies
  • if the download flag is TRUE, this routine tries to prevent the visitor's browser to render the file in-line suggesting downloading instead
Quirks

  • There appears to be a problem with Internet Explorer and https:// and caching which requires a specific workaround. We simply check for 'https:' or 'http'.
  • Adobe Acrobat Reader has a bad track record of infecting user's computers with malware when PDF's are rendered in-line. Therefore we force download for that kind of files by checking for extension 'pdf' or mediatype 'application/pdf' or 'application/x-pdf'.
  • It is not easy to determine the exact mime type of files without resorting to a complex shadow-filesystem or a metadata table in the database. Therefore we rely on the information provided via finfo, mime_content_type() or file(1). See get_mimetype()for details.

bool|int send_file_from_datadir (string $file, string $name, [string $mimetype = ''], [int $ttl = 86400], [bool $download = FALSE])
  • string $file: name of the file to send relative to $CFG->datadir
  • string $name: filename to suggest to the visitor/visitor's browser
  • string $mimetype: the mime type of the file; if not specified we look it up
  • int $ttl: time to live (aka maximum age) in seconds, 0 implies file is not cacheable
  • bool $download: if TRUE we try to force a download

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