2007-02-02 12:19:58 +00:00
|
|
|
<?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);
|
2009-06-22 01:22:37 +00:00
|
|
|
$param = preg_replace('/[[:cntrl:]]|[<>"`\|\':]/', '', $param);
|
|
|
|
$param = preg_replace('/\.\.+/', '', $param);
|
|
|
|
$param = preg_replace('~//+~', '/', $param);
|
|
|
|
return preg_replace('~/(\./)+~', '/', $param);
|
2007-02-02 12:19:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
*/
|
2008-07-17 03:14:20 +00:00
|
|
|
function strip_querystring($url) {
|
2007-02-02 12:19:58 +00:00
|
|
|
|
|
|
|
if ($commapos = strpos($url, '?')) {
|
|
|
|
return substr($url, 0, $commapos);
|
|
|
|
} else {
|
|
|
|
return $url;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-17 03:14:20 +00:00
|
|
|
// get query string
|
|
|
|
function get_query($name) {
|
|
|
|
if (!empty($_SERVER['REQUEST_URI'])) {
|
|
|
|
return explode($name, $_SERVER['REQUEST_URI']);
|
|
|
|
} else if (!empty($_SERVER['QUERY_STRING'])) {
|
|
|
|
return array('', '?'. $_SERVER['QUERY_STRING']);
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2007-02-02 12:19:58 +00:00
|
|
|
// 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)
|
2008-07-17 03:14:20 +00:00
|
|
|
$arr = get_query($scriptname);
|
2007-02-02 12:19:58 +00:00
|
|
|
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();
|
2009-03-04 11:55:08 +00:00
|
|
|
if(!preg_match('|^/([a-zA-Z0-9_\-.]+)/([a-zA-Z0-9/_\-.]+)$|',$path,$match)) {
|
2007-02-02 12:19:58 +00:00
|
|
|
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.
|
|
|
|
//
|
2008-06-25 17:31:23 +00:00
|
|
|
//define('NO_MOODLE_COOKIES', true); // session not used here
|
2007-02-02 12:19:58 +00:00
|
|
|
//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);
|
|
|
|
?>
|