PageRenderTime 49ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/theme/chameleon/pix/smartpix.php

https://bitbucket.org/systime/screening2
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
  1. <?php
  2. // Outputs pictures from theme or core pix folder. Only used if $CFG->smartpix is
  3. // turned on.
  4. $matches=array(); // Reusable array variable for preg_match
  5. // This does NOT use config.php. This is because doing that makes database requests
  6. // which cause this to take longer (I benchmarked this at 16ms, 256ms with config.php)
  7. // A version using normal Moodle functions is included in comment at end in case we
  8. // want to switch to it in future.
  9. function error($text,$notfound=false) {
  10. header($notfound ? 'HTTP/1.0 404 Not Found' : 'HTTP/1.0 500 Internal Server Error');
  11. header('Content-Type: text/plain');
  12. print $text;
  13. exit;
  14. }
  15. // Nicked from moodlelib clean_param
  16. function makesafe($param) {
  17. $param = str_replace('\\\'', '\'', $param);
  18. $param = str_replace('\\"', '"', $param);
  19. $param = str_replace('\\', '/', $param);
  20. $param = ereg_replace('[[:cntrl:]]|[<>"`\|\':]', '', $param);
  21. $param = ereg_replace('\.\.+', '', $param);
  22. $param = ereg_replace('//+', '/', $param);
  23. return ereg_replace('/(\./)+', '/', $param);
  24. }
  25. // Nicked from weblib
  26. /**
  27. * Remove query string from url
  28. *
  29. * Takes in a URL and returns it without the querystring portion
  30. *
  31. * @param string $url the url which may have a query string attached
  32. * @return string
  33. */
  34. function strip_querystring($url) {
  35. if ($commapos = strpos($url, '?')) {
  36. return substr($url, 0, $commapos);
  37. } else {
  38. return $url;
  39. }
  40. }
  41. // Nicked from weblib then cutdown
  42. /**
  43. * Extracts file argument either from file parameter or PATH_INFO.
  44. * @param string $scriptname name of the calling script
  45. * @return string file path (only safe characters)
  46. */
  47. function get_file_argument_limited($scriptname) {
  48. $relativepath = FALSE;
  49. // first try normal parameter (compatible method == no relative links!)
  50. if(isset($_GET['file'])) {
  51. return makesafe($_GET['file']);
  52. }
  53. // then try extract file from PATH_INFO (slasharguments method)
  54. if (!empty($_SERVER['PATH_INFO'])) {
  55. $path_info = $_SERVER['PATH_INFO'];
  56. // check that PATH_INFO works == must not contain the script name
  57. if (!strpos($path_info, $scriptname)) {
  58. return makesafe(rawurldecode($path_info));
  59. }
  60. }
  61. // now if both fail try the old way
  62. // (for compatibility with misconfigured or older buggy php implementations)
  63. $arr = explode($scriptname, me());
  64. if (!empty($arr[1])) {
  65. return makesafe(rawurldecode(strip_querystring($arr[1])));
  66. }
  67. error('Unexpected PHP set up. Turn off the smartpix config option.');
  68. }
  69. // We do need to get dirroot from config.php
  70. if(!$config=@file_get_contents(dirname(__FILE__).'/../config.php')) {
  71. error("Can't open config.php");
  72. }
  73. $configlines=preg_split('/[\r\n]+/',$config);
  74. foreach($configlines as $configline) {
  75. if(preg_match('/^\s?\$CFG->dirroot\s*=\s*[\'"](.*?)[\'"]\s*;/',$configline,$matches)) {
  76. $dirroot=$matches[1];
  77. }
  78. if(preg_match('/^\s?\$CFG->dataroot\s*=\s*[\'"](.*?)[\'"]\s*;/',$configline,$matches)) {
  79. $dataroot=$matches[1];
  80. }
  81. if(isset($dirroot) && isset($dataroot)) {
  82. break;
  83. }
  84. }
  85. if(!(isset($dirroot) && isset($dataroot))) {
  86. error('No line in config.php like $CFG->dirroot=\'/somewhere/whatever\';');
  87. }
  88. // Split path - starts with theme name, then actual image path inside pix
  89. $path=get_file_argument_limited('smartpix.php');
  90. $match=array();
  91. if(!preg_match('|^/([a-z0-9_\-.]+)/([a-z0-9/_\-.]+)$|',$path,$match)) {
  92. error('Unexpected request format');
  93. }
  94. list($junk,$theme,$path)=$match;
  95. // Check file type
  96. if(preg_match('/\.png$/',$path)) {
  97. $mimetype='image/png';
  98. } else if(preg_match('/\.gif$/',$path)) {
  99. $mimetype='image/gif';
  100. } else if(preg_match('/\.jpe?g$/',$path)) {
  101. $mimetype='image/jpeg';
  102. } else {
  103. // Note that this is a security feature as well as a lack of mime type
  104. // support :) Means this can't accidentally serve files from places it
  105. // shouldn't. Without it, you can actually access any file inside the
  106. // module code directory.
  107. error('Request for non-image file');
  108. }
  109. // Find actual location of image as $file
  110. $file=false;
  111. if(file_exists($possibility="$dirroot/theme/$theme/pix/$path")) {
  112. // Found the file in theme, stop looking
  113. $file=$possibility;
  114. } else {
  115. // Is there a parent theme?
  116. while(true) {
  117. require("$dirroot/theme/$theme/config.php"); // Sets up $THEME
  118. if(!$THEME->parent) {
  119. break;
  120. }
  121. $theme=$THEME->parent;
  122. if(file_exists($possibility="$dirroot/theme/$theme/pix/$path")) {
  123. $file=$possibility;
  124. // Found in parent theme
  125. break;
  126. }
  127. }
  128. if(!$file) {
  129. if(preg_match('|^mod/|',$path)) {
  130. if(!file_exists($possibility="$dirroot/$path")) {
  131. error('Requested image not found.',true);
  132. }
  133. } else {
  134. if(!file_exists($possibility="$dirroot/pix/$path")) {
  135. error('Requested image not found.',true);
  136. }
  137. }
  138. $file=$possibility;
  139. }
  140. }
  141. // Now we have a file that exists. Not using send_file since it requires
  142. // proper $CFG etc.
  143. // Handle If-Modified-Since
  144. $filedate=filemtime($file);
  145. $ifmodifiedsince=isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? $_SERVER['HTTP_IF_MODIFIED_SINCE'] : false;
  146. if($ifmodifiedsince && strtotime($ifmodifiedsince)>=$filedate) {
  147. header('HTTP/1.0 304 Not Modified');
  148. exit;
  149. }
  150. header('Last-Modified: '.gmdate('D, d M Y H:i:s',$filedate).' GMT');
  151. // As I'm not loading config table from DB, this is hardcoded here; expiry
  152. // 4 hours, unless the hacky file reduceimagecache.dat exists in dataroot
  153. if(file_exists($reducefile=$dataroot.'/reduceimagecache.dat')) {
  154. $lifetime=file_read_contents($reducefile);
  155. } else {
  156. $lifetime=4*60*60;
  157. }
  158. // Send expire headers
  159. header('Cache-Control: max-age='.$lifetime);
  160. header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
  161. // Type
  162. header('Content-Type: '.$mimetype);
  163. header('Content-Length: '.filesize($file));
  164. // Output file
  165. $handle=fopen($file,'r');
  166. fpassthru($handle);
  167. fclose($handle);
  168. // Slower Moodle-style version follows:
  169. //// Outputs pictures from theme or core pix folder. Only used if $CFG->smartpix is
  170. //// turned on.
  171. //
  172. //$nomoodlecookie = true; // Stops it making a session
  173. //require_once('../config.php');
  174. //require_once('../lib/filelib.php');
  175. //global $CFG;
  176. //
  177. //$matches=array(); // Reusable array variable for preg_match
  178. //
  179. //// Split path - starts with theme name, then actual image path inside pix
  180. //$path=get_file_argument('smartpix.php');
  181. //$match=array();
  182. //if(!preg_match('|^/([a-z0-9_\-.]+)/([a-z0-9/_\-.]+)$|',$path,$match)) {
  183. // error('Unexpected request format');
  184. //}
  185. //list($junk,$theme,$path)=$match;
  186. //
  187. //// Check file type - this is not needed for the MIME types as we could
  188. //// get those by the existing function, but it provides an extra layer of security
  189. //// as otherwise this script could be used to view all files within dirroot/mod
  190. //if(preg_match('/\.png$/',$path)) {
  191. // $mimetype='image/png';
  192. //} else if(preg_match('/\.gif$/',$path)) {
  193. // $mimetype='image/gif';
  194. //} else if(preg_match('/\.jpe?g$/',$path)) {
  195. // $mimetype='image/jpeg';
  196. //} else {
  197. // error('Request for non-image file');
  198. //}
  199. //
  200. //// Find actual location of image as $file
  201. //$file=false;
  202. //if(file_exists($possibility="$CFG->dirroot/theme/$theme/pix/$path")) {
  203. // // Found the file in theme, stop looking
  204. // $file=$possibility;
  205. //} else {
  206. // // Is there a parent theme?
  207. // while(true) {
  208. // require("$CFG->dirroot/theme/$theme/config.php"); // Sets up $THEME
  209. // if(!$THEME->parent) {
  210. // break;
  211. // }
  212. // $theme=$THEME->parent;
  213. // if(file_exists($possibility="$CFG->dirroot/theme/$theme/pix/$path")) {
  214. // $file=$possibility;
  215. // // Found in parent theme
  216. // break;
  217. // }
  218. // }
  219. // if(!$file) {
  220. // if(preg_match('|^mod/|',$path)) {
  221. // if(!file_exists($possibility="$CFG->dirroot/$path")) {
  222. // error('Requested image not found.');
  223. // }
  224. // } else {
  225. // if(!file_exists($possibility="$CFG->dirroot/pix/$path")) {
  226. // error('Requested image not found.');
  227. // }
  228. // }
  229. // $file=$possibility;
  230. // }
  231. //}
  232. //
  233. //// Handle If-Modified-Since because send_file doesn't
  234. //$filedate=filemtime($file);
  235. //$ifmodifiedsince=isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? $_SERVER['HTTP_IF_MODIFIED_SINCE'] : false;
  236. //if($ifmodifiedsince && strtotime($ifmodifiedsince)>=$filedate) {
  237. // header('HTTP/1.0 304 Not Modified');
  238. // exit;
  239. //}
  240. //// Don't need to set last-modified, send_file does that
  241. //
  242. //if (empty($CFG->filelifetime)) {
  243. // $lifetime = 86400; // Seconds for files to remain in caches
  244. //} else {
  245. // $lifetime = $CFG->filelifetime;
  246. //}
  247. //send_file($file,preg_replace('|^.*/|','',$file),$lifetime);
  248. ?>