/theme/chameleon/pix/smartpix.php
PHP | 271 lines | 128 code | 21 blank | 122 comment | 20 complexity | d8a40fd54723dd26deb7622013580b84 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, GPL-3.0, BSD-3-Clause, LGPL-2.0
- <?php
- // Outputs pictures from theme or core pix folder. Only used if $CFG->smartpix is
- // turned on.
- $matches=array(); // Reusable array variable for preg_match
-
- // This does NOT use config.php. This is because doing that makes database requests
- // which cause this to take longer (I benchmarked this at 16ms, 256ms with config.php)
- // A version using normal Moodle functions is included in comment at end in case we
- // want to switch to it in future.
- function error($text,$notfound=false) {
- header($notfound ? 'HTTP/1.0 404 Not Found' : 'HTTP/1.0 500 Internal Server Error');
- header('Content-Type: text/plain');
- print $text;
- exit;
- }
- // Nicked from moodlelib clean_param
- function makesafe($param) {
- $param = str_replace('\\\'', '\'', $param);
- $param = str_replace('\\"', '"', $param);
- $param = str_replace('\\', '/', $param);
- $param = ereg_replace('[[:cntrl:]]|[<>"`\|\':]', '', $param);
- $param = ereg_replace('\.\.+', '', $param);
- $param = ereg_replace('//+', '/', $param);
- return ereg_replace('/(\./)+', '/', $param);
- }
- // Nicked from weblib
- /**
- * Remove query string from url
- *
- * Takes in a URL and returns it without the querystring portion
- *
- * @param string $url the url which may have a query string attached
- * @return string
- */
- function strip_querystring($url) {
- if ($commapos = strpos($url, '?')) {
- return substr($url, 0, $commapos);
- } else {
- return $url;
- }
- }
-
- // Nicked from weblib then cutdown
- /**
- * Extracts file argument either from file parameter or PATH_INFO.
- * @param string $scriptname name of the calling script
- * @return string file path (only safe characters)
- */
- function get_file_argument_limited($scriptname) {
- $relativepath = FALSE;
- // first try normal parameter (compatible method == no relative links!)
- if(isset($_GET['file'])) {
- return makesafe($_GET['file']);
- }
- // then try extract file from PATH_INFO (slasharguments method)
- if (!empty($_SERVER['PATH_INFO'])) {
- $path_info = $_SERVER['PATH_INFO'];
- // check that PATH_INFO works == must not contain the script name
- if (!strpos($path_info, $scriptname)) {
- return makesafe(rawurldecode($path_info));
- }
- }
- // now if both fail try the old way
- // (for compatibility with misconfigured or older buggy php implementations)
- $arr = explode($scriptname, me());
- if (!empty($arr[1])) {
- return makesafe(rawurldecode(strip_querystring($arr[1])));
- }
-
- error('Unexpected PHP set up. Turn off the smartpix config option.');
- }
-
- // We do need to get dirroot from config.php
- if(!$config=@file_get_contents(dirname(__FILE__).'/../config.php')) {
- error("Can't open config.php");
- }
- $configlines=preg_split('/[\r\n]+/',$config);
- foreach($configlines as $configline) {
- if(preg_match('/^\s?\$CFG->dirroot\s*=\s*[\'"](.*?)[\'"]\s*;/',$configline,$matches)) {
- $dirroot=$matches[1];
- }
- if(preg_match('/^\s?\$CFG->dataroot\s*=\s*[\'"](.*?)[\'"]\s*;/',$configline,$matches)) {
- $dataroot=$matches[1];
- }
- if(isset($dirroot) && isset($dataroot)) {
- break;
- }
- }
- if(!(isset($dirroot) && isset($dataroot))) {
- error('No line in config.php like $CFG->dirroot=\'/somewhere/whatever\';');
- }
- // Split path - starts with theme name, then actual image path inside pix
- $path=get_file_argument_limited('smartpix.php');
- $match=array();
- if(!preg_match('|^/([a-z0-9_\-.]+)/([a-z0-9/_\-.]+)$|',$path,$match)) {
- error('Unexpected request format');
- }
- list($junk,$theme,$path)=$match;
- // Check file type
- if(preg_match('/\.png$/',$path)) {
- $mimetype='image/png';
- } else if(preg_match('/\.gif$/',$path)) {
- $mimetype='image/gif';
- } else if(preg_match('/\.jpe?g$/',$path)) {
- $mimetype='image/jpeg';
- } else {
- // Note that this is a security feature as well as a lack of mime type
- // support :) Means this can't accidentally serve files from places it
- // shouldn't. Without it, you can actually access any file inside the
- // module code directory.
- error('Request for non-image file');
- }
- // Find actual location of image as $file
- $file=false;
- if(file_exists($possibility="$dirroot/theme/$theme/pix/$path")) {
- // Found the file in theme, stop looking
- $file=$possibility;
- } else {
- // Is there a parent theme?
- while(true) {
- require("$dirroot/theme/$theme/config.php"); // Sets up $THEME
- if(!$THEME->parent) {
- break;
- }
- $theme=$THEME->parent;
- if(file_exists($possibility="$dirroot/theme/$theme/pix/$path")) {
- $file=$possibility;
- // Found in parent theme
- break;
- }
- }
- if(!$file) {
- if(preg_match('|^mod/|',$path)) {
- if(!file_exists($possibility="$dirroot/$path")) {
- error('Requested image not found.',true);
- }
- } else {
- if(!file_exists($possibility="$dirroot/pix/$path")) {
- error('Requested image not found.',true);
- }
- }
- $file=$possibility;
- }
- }
- // Now we have a file that exists. Not using send_file since it requires
- // proper $CFG etc.
- // Handle If-Modified-Since
- $filedate=filemtime($file);
- $ifmodifiedsince=isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? $_SERVER['HTTP_IF_MODIFIED_SINCE'] : false;
- if($ifmodifiedsince && strtotime($ifmodifiedsince)>=$filedate) {
- header('HTTP/1.0 304 Not Modified');
- exit;
- }
- header('Last-Modified: '.gmdate('D, d M Y H:i:s',$filedate).' GMT');
- // As I'm not loading config table from DB, this is hardcoded here; expiry
- // 4 hours, unless the hacky file reduceimagecache.dat exists in dataroot
- if(file_exists($reducefile=$dataroot.'/reduceimagecache.dat')) {
- $lifetime=file_read_contents($reducefile);
- } else {
- $lifetime=4*60*60;
- }
- // Send expire headers
- header('Cache-Control: max-age='.$lifetime);
- header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
- // Type
- header('Content-Type: '.$mimetype);
- header('Content-Length: '.filesize($file));
- // Output file
- $handle=fopen($file,'r');
- fpassthru($handle);
- fclose($handle);
- // Slower Moodle-style version follows:
-
- //// Outputs pictures from theme or core pix folder. Only used if $CFG->smartpix is
- //// turned on.
- //
- //$nomoodlecookie = true; // Stops it making a session
- //require_once('../config.php');
- //require_once('../lib/filelib.php');
- //global $CFG;
- //
- //$matches=array(); // Reusable array variable for preg_match
- //
- //// Split path - starts with theme name, then actual image path inside pix
- //$path=get_file_argument('smartpix.php');
- //$match=array();
- //if(!preg_match('|^/([a-z0-9_\-.]+)/([a-z0-9/_\-.]+)$|',$path,$match)) {
- // error('Unexpected request format');
- //}
- //list($junk,$theme,$path)=$match;
- //
- //// Check file type - this is not needed for the MIME types as we could
- //// get those by the existing function, but it provides an extra layer of security
- //// as otherwise this script could be used to view all files within dirroot/mod
- //if(preg_match('/\.png$/',$path)) {
- // $mimetype='image/png';
- //} else if(preg_match('/\.gif$/',$path)) {
- // $mimetype='image/gif';
- //} else if(preg_match('/\.jpe?g$/',$path)) {
- // $mimetype='image/jpeg';
- //} else {
- // error('Request for non-image file');
- //}
- //
- //// Find actual location of image as $file
- //$file=false;
- //if(file_exists($possibility="$CFG->dirroot/theme/$theme/pix/$path")) {
- // // Found the file in theme, stop looking
- // $file=$possibility;
- //} else {
- // // Is there a parent theme?
- // while(true) {
- // require("$CFG->dirroot/theme/$theme/config.php"); // Sets up $THEME
- // if(!$THEME->parent) {
- // break;
- // }
- // $theme=$THEME->parent;
- // if(file_exists($possibility="$CFG->dirroot/theme/$theme/pix/$path")) {
- // $file=$possibility;
- // // Found in parent theme
- // break;
- // }
- // }
- // if(!$file) {
- // if(preg_match('|^mod/|',$path)) {
- // if(!file_exists($possibility="$CFG->dirroot/$path")) {
- // error('Requested image not found.');
- // }
- // } else {
- // if(!file_exists($possibility="$CFG->dirroot/pix/$path")) {
- // error('Requested image not found.');
- // }
- // }
- // $file=$possibility;
- // }
- //}
- //
- //// Handle If-Modified-Since because send_file doesn't
- //$filedate=filemtime($file);
- //$ifmodifiedsince=isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? $_SERVER['HTTP_IF_MODIFIED_SINCE'] : false;
- //if($ifmodifiedsince && strtotime($ifmodifiedsince)>=$filedate) {
- // header('HTTP/1.0 304 Not Modified');
- // exit;
- //}
- //// Don't need to set last-modified, send_file does that
- //
- //if (empty($CFG->filelifetime)) {
- // $lifetime = 86400; // Seconds for files to remain in caches
- //} else {
- // $lifetime = $CFG->filelifetime;
- //}
- //send_file($file,preg_replace('|^.*/|','',$file),$lifetime);
- ?>