PageRenderTime 26ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/secured/fetch.php

http://oregon-caspages.googlecode.com/
PHP | 305 lines | 162 code | 47 blank | 96 comment | 47 complexity | ed11b3578a2001fb4c22a09922425a4e MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, AGPL-3.0
  1. <?php
  2. include 'editor_conf.php';
  3. include 'intranet_check_cookie.php';
  4. if($is_admin){
  5. /**
  6. * DokuWiki media passthrough file
  7. *
  8. * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
  9. * @author Andreas Gohr <andi@splitbrain.org>
  10. */
  11. //echo 'is admin = ' . $is_admin;
  12. if(!defined('CHUNK_SIZE')) define('CHUNK_SIZE',16*1024);
  13. //get input
  14. $FILE = $basepath.$_GET['media']; // no cleaning except control chars - maybe external
  15. $CACHE = calc_cache($_REQUEST['cache']);
  16. //check file existance
  17. if(!@file_exists($FILE)){
  18. header("HTTP/1.0 404 Not Found");
  19. //FIXME add some default broken image
  20. print 'Not Found';
  21. exit;
  22. }
  23. // finally send the file to the client
  24. sendFile($FILE,$CACHE);
  25. }
  26. /* ------------------------------------------------------------------------ */
  27. /**
  28. * Set headers and send the file to the client
  29. *
  30. * @author Andreas Gohr <andi@splitbrain.org>
  31. * @author Ben Coburn <btcoburn@silicodon.net>
  32. */
  33. function sendFile($file,$cache){
  34. /*
  35. echo 'Start Send File <br>';
  36. echo 'Current path = ' . getcwd() . '<br>';
  37. echo 'File name = '.$file . '<br>';
  38. echo 'cache = '.$cache . '<br>';
  39. */
  40. global $conf;
  41. $fmtime = filemtime($file);
  42. // send headers
  43. header("Content-Type: application/octet-stream");
  44. if ($cache==-1) {
  45. // cache
  46. // cachetime or one hour
  47. header('Expires: '.gmdate("D, d M Y H:i:s", time()+max($conf['cachetime'], 3600)).' GMT');
  48. header('Cache-Control: public, proxy-revalidate, no-transform, max-age='.max($conf['cachetime'], 3600));
  49. header('Pragma: public');
  50. } else if ($cache>0) {
  51. // recache
  52. // remaining cachetime + 10 seconds so the newly recached media is used
  53. header('Expires: '.gmdate("D, d M Y H:i:s", $fmtime+$conf['cachetime']+10).' GMT');
  54. header('Cache-Control: public, proxy-revalidate, no-transform, max-age='.max($fmtime-time()+$conf['cachetime']+10, 0));
  55. header('Pragma: public');
  56. } else if ($cache==0) {
  57. // nocache
  58. header('Cache-Control: must-revalidate, no-transform, post-check=0, pre-check=0');
  59. header('Pragma: public');
  60. }
  61. header('Content-Disposition: attachment; filename="'.basename($file).'";');
  62. //send important headers first, script stops here if '304 Not Modified' response
  63. http_conditionalRequest($fmtime);
  64. //support download continueing
  65. header('Accept-Ranges: bytes');
  66. list($start,$len) = http_rangeRequest(filesize($file));
  67. // send file contents
  68. $fp = @fopen($file,"rb");
  69. if($fp){
  70. fseek($fp,$start); //seek to start of range
  71. $chunk = ($len > CHUNK_SIZE) ? CHUNK_SIZE : $len;
  72. while (!feof($fp) && $chunk > 0) {
  73. @set_time_limit(30); // large files can take a lot of time
  74. print fread($fp, $chunk);
  75. flush();
  76. $len -= $chunk;
  77. $chunk = ($len > CHUNK_SIZE) ? CHUNK_SIZE : $len;
  78. }
  79. fclose($fp);
  80. }else{
  81. header("HTTP/1.0 500 Internal Server Error");
  82. print "Could not read $file - bad permissions?";
  83. }
  84. }
  85. /**
  86. * Checks and sets HTTP headers for conditional HTTP requests
  87. *
  88. * @author Simon Willison <swillison@gmail.com>
  89. * @link http://simon.incutio.com/archive/2003/04/23/conditionalGet
  90. * @param timestamp $timestamp lastmodified time of the cache file
  91. * @returns void or void with previously header() commands executed
  92. */
  93. function http_conditionalRequest($timestamp){
  94. // A PHP implementation of conditional get, see
  95. // http://fishbowl.pastiche.org/archives/001132.html
  96. $last_modified = substr(gmdate('r', $timestamp), 0, -5).'GMT';
  97. $etag = '"'.md5($last_modified).'"';
  98. // Send the headers
  99. header("Last-Modified: $last_modified");
  100. header("ETag: $etag");
  101. // See if the client has provided the required headers
  102. if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])){
  103. $if_modified_since = stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE']);
  104. }else{
  105. $if_modified_since = false;
  106. }
  107. if (isset($_SERVER['HTTP_IF_NONE_MATCH'])){
  108. $if_none_match = stripslashes($_SERVER['HTTP_IF_NONE_MATCH']);
  109. }else{
  110. $if_none_match = false;
  111. }
  112. if (!$if_modified_since && !$if_none_match){
  113. return;
  114. }
  115. // At least one of the headers is there - check them
  116. if ($if_none_match && $if_none_match != $etag) {
  117. return; // etag is there but doesn't match
  118. }
  119. if ($if_modified_since && $if_modified_since != $last_modified) {
  120. return; // if-modified-since is there but doesn't match
  121. }
  122. // Nothing has changed since their last request - serve a 304 and exit
  123. header('HTTP/1.0 304 Not Modified');
  124. // don't produce output, even if compression is on
  125. ob_end_clean();
  126. exit;
  127. }
  128. /**
  129. * Checks and sets headers to handle range requets
  130. *
  131. * @author Andreas Gohr <andi@splitbrain.org>
  132. * @returns array The start byte and the amount of bytes to send
  133. */
  134. function http_rangeRequest($size){
  135. if(!isset($_SERVER['HTTP_RANGE'])){
  136. // no range requested - send the whole file
  137. header("Content-Length: $size");
  138. return array(0,$size);
  139. }
  140. $t = explode('=', $_SERVER['HTTP_RANGE']);
  141. if (!$t[0]=='bytes') {
  142. // we only understand byte ranges - send the whole file
  143. header("Content-Length: $size");
  144. return array(0,$size);
  145. }
  146. $r = explode('-', $t[1]);
  147. $start = (int)$r[0];
  148. $end = (int)$r[1];
  149. if (!$end) $end = $size - 1;
  150. if ($start > $end || $start > $size || $end > $size){
  151. header('HTTP/1.1 416 Requested Range Not Satisfiable');
  152. print 'Bad Range Request!';
  153. exit;
  154. }
  155. $tot = $end - $start + 1;
  156. header('HTTP/1.1 206 Partial Content');
  157. header("Content-Range: bytes {$start}-{$end}/{$size}");
  158. header("Content-Length: $tot");
  159. return array($start,$tot);
  160. }
  161. /**
  162. * Returns the wanted cachetime in seconds
  163. *
  164. * Resolves named constants
  165. *
  166. * @author Andreas Gohr <andi@splitbrain.org>
  167. */
  168. function calc_cache($cache){
  169. global $conf;
  170. if(strtolower($cache) == 'nocache') return 0; //never cache
  171. if(strtolower($cache) == 'recache') return $conf['cachetime']; //use standard cache
  172. return -1; //cache endless
  173. }
  174. /**
  175. * Download a remote file and return local filename
  176. *
  177. * returns false if download fails. Uses cached file if available and
  178. * wanted
  179. *
  180. * @author Andreas Gohr <andi@splitbrain.org>
  181. * @author Pavel Vitis <Pavel.Vitis@seznam.cz>
  182. */
  183. function get_from_URL($url,$ext,$cache){
  184. global $conf;
  185. // if no cache or fetchsize just redirect
  186. if ($cache==0) return false;
  187. if (!$conf['fetchsize']) return false;
  188. $local = getCacheName(strtolower($url),".media.$ext");
  189. $mtime = @filemtime($local); // 0 if not exists
  190. //decide if download needed:
  191. if( ($mtime == 0) || // cache does not exist
  192. ($cache != -1 && $mtime < time()-$cache) // 'recache' and cache has expired
  193. ){
  194. if(image_download($url,$local)){
  195. return $local;
  196. }else{
  197. return false;
  198. }
  199. }
  200. //if cache exists use it else
  201. if($mtime) return $local;
  202. //else return false
  203. return false;
  204. }
  205. /**
  206. * Download image files
  207. *
  208. * @author Andreas Gohr <andi@splitbrain.org>
  209. */
  210. function image_download($url,$file){
  211. global $conf;
  212. $http = new DokuHTTPClient();
  213. $http->max_bodysize = $conf['fetchsize'];
  214. $http->timeout = 25; //max. 25 sec
  215. $http->header_regexp = '!\r\nContent-Type: image/(jpe?g|gif|png)!i';
  216. $data = $http->get($url);
  217. if(!$data) return false;
  218. $fileexists = @file_exists($file);
  219. $fp = @fopen($file,"w");
  220. if(!$fp) return false;
  221. fwrite($fp,$data);
  222. fclose($fp);
  223. if(!$fileexists and $conf['fperm']) chmod($file, $conf['fperm']);
  224. // check if it is really an image
  225. $info = @getimagesize($file);
  226. if(!$info){
  227. @unlink($file);
  228. return false;
  229. }
  230. return true;
  231. }
  232. /**
  233. * Checks if the given amount of memory is available
  234. *
  235. * If the memory_get_usage() function is not available the
  236. * function just assumes $bytes of already allocated memory
  237. *
  238. * @param int $mem Size of memory you want to allocate in bytes
  239. * @param int $used already allocated memory (see above)
  240. * @author Filip Oscadal <webmaster@illusionsoftworks.cz>
  241. * @author Andreas Gohr <andi@splitbrain.org>
  242. */
  243. function is_mem_available($mem,$bytes=1048576){
  244. $limit = trim(ini_get('memory_limit'));
  245. if(empty($limit)) return true; // no limit set!
  246. // parse limit to bytes
  247. $limit = php_to_byte($limit);
  248. // get used memory if possible
  249. if(function_exists('memory_get_usage')){
  250. $used = memory_get_usage();
  251. }
  252. if($used+$mem > $limit){
  253. return false;
  254. }
  255. return true;
  256. }
  257. //Setup VIM: ex: et ts=2 enc=utf-8 :
  258. ?>