/secured/fetch.php
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
- <?php
- include 'editor_conf.php';
- include 'intranet_check_cookie.php';
- if($is_admin){
- /**
- * DokuWiki media passthrough file
- *
- * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * @author Andreas Gohr <andi@splitbrain.org>
- */
- //echo 'is admin = ' . $is_admin;
- if(!defined('CHUNK_SIZE')) define('CHUNK_SIZE',16*1024);
- //get input
- $FILE = $basepath.$_GET['media']; // no cleaning except control chars - maybe external
- $CACHE = calc_cache($_REQUEST['cache']);
- //check file existance
- if(!@file_exists($FILE)){
- header("HTTP/1.0 404 Not Found");
- //FIXME add some default broken image
- print 'Not Found';
- exit;
- }
- // finally send the file to the client
- sendFile($FILE,$CACHE);
- }
- /* ------------------------------------------------------------------------ */
- /**
- * Set headers and send the file to the client
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- * @author Ben Coburn <btcoburn@silicodon.net>
- */
- function sendFile($file,$cache){
- /*
- echo 'Start Send File <br>';
- echo 'Current path = ' . getcwd() . '<br>';
- echo 'File name = '.$file . '<br>';
- echo 'cache = '.$cache . '<br>';
- */
- global $conf;
- $fmtime = filemtime($file);
- // send headers
- header("Content-Type: application/octet-stream");
- if ($cache==-1) {
- // cache
- // cachetime or one hour
- header('Expires: '.gmdate("D, d M Y H:i:s", time()+max($conf['cachetime'], 3600)).' GMT');
- header('Cache-Control: public, proxy-revalidate, no-transform, max-age='.max($conf['cachetime'], 3600));
- header('Pragma: public');
- } else if ($cache>0) {
- // recache
- // remaining cachetime + 10 seconds so the newly recached media is used
- header('Expires: '.gmdate("D, d M Y H:i:s", $fmtime+$conf['cachetime']+10).' GMT');
- header('Cache-Control: public, proxy-revalidate, no-transform, max-age='.max($fmtime-time()+$conf['cachetime']+10, 0));
- header('Pragma: public');
- } else if ($cache==0) {
- // nocache
- header('Cache-Control: must-revalidate, no-transform, post-check=0, pre-check=0');
- header('Pragma: public');
- }
- header('Content-Disposition: attachment; filename="'.basename($file).'";');
- //send important headers first, script stops here if '304 Not Modified' response
- http_conditionalRequest($fmtime);
- //support download continueing
- header('Accept-Ranges: bytes');
- list($start,$len) = http_rangeRequest(filesize($file));
- // send file contents
- $fp = @fopen($file,"rb");
- if($fp){
- fseek($fp,$start); //seek to start of range
- $chunk = ($len > CHUNK_SIZE) ? CHUNK_SIZE : $len;
- while (!feof($fp) && $chunk > 0) {
- @set_time_limit(30); // large files can take a lot of time
- print fread($fp, $chunk);
- flush();
- $len -= $chunk;
- $chunk = ($len > CHUNK_SIZE) ? CHUNK_SIZE : $len;
- }
- fclose($fp);
- }else{
- header("HTTP/1.0 500 Internal Server Error");
- print "Could not read $file - bad permissions?";
- }
- }
- /**
- * Checks and sets HTTP headers for conditional HTTP requests
- *
- * @author Simon Willison <swillison@gmail.com>
- * @link http://simon.incutio.com/archive/2003/04/23/conditionalGet
- * @param timestamp $timestamp lastmodified time of the cache file
- * @returns void or void with previously header() commands executed
- */
- function http_conditionalRequest($timestamp){
- // A PHP implementation of conditional get, see
- // http://fishbowl.pastiche.org/archives/001132.html
- $last_modified = substr(gmdate('r', $timestamp), 0, -5).'GMT';
- $etag = '"'.md5($last_modified).'"';
- // Send the headers
- header("Last-Modified: $last_modified");
- header("ETag: $etag");
- // See if the client has provided the required headers
- if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])){
- $if_modified_since = stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE']);
- }else{
- $if_modified_since = false;
- }
-
- if (isset($_SERVER['HTTP_IF_NONE_MATCH'])){
- $if_none_match = stripslashes($_SERVER['HTTP_IF_NONE_MATCH']);
- }else{
- $if_none_match = false;
- }
-
- if (!$if_modified_since && !$if_none_match){
- return;
- }
- // At least one of the headers is there - check them
- if ($if_none_match && $if_none_match != $etag) {
- return; // etag is there but doesn't match
- }
-
- if ($if_modified_since && $if_modified_since != $last_modified) {
- return; // if-modified-since is there but doesn't match
- }
-
- // Nothing has changed since their last request - serve a 304 and exit
- header('HTTP/1.0 304 Not Modified');
-
- // don't produce output, even if compression is on
- ob_end_clean();
- exit;
- }
-
- /**
- * Checks and sets headers to handle range requets
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- * @returns array The start byte and the amount of bytes to send
- */
- function http_rangeRequest($size){
- if(!isset($_SERVER['HTTP_RANGE'])){
- // no range requested - send the whole file
- header("Content-Length: $size");
- return array(0,$size);
- }
- $t = explode('=', $_SERVER['HTTP_RANGE']);
- if (!$t[0]=='bytes') {
- // we only understand byte ranges - send the whole file
- header("Content-Length: $size");
- return array(0,$size);
- }
- $r = explode('-', $t[1]);
- $start = (int)$r[0];
- $end = (int)$r[1];
- if (!$end) $end = $size - 1;
- if ($start > $end || $start > $size || $end > $size){
- header('HTTP/1.1 416 Requested Range Not Satisfiable');
- print 'Bad Range Request!';
- exit;
- }
- $tot = $end - $start + 1;
- header('HTTP/1.1 206 Partial Content');
- header("Content-Range: bytes {$start}-{$end}/{$size}");
- header("Content-Length: $tot");
- return array($start,$tot);
- }
- /**
- * Returns the wanted cachetime in seconds
- *
- * Resolves named constants
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
- function calc_cache($cache){
- global $conf;
- if(strtolower($cache) == 'nocache') return 0; //never cache
- if(strtolower($cache) == 'recache') return $conf['cachetime']; //use standard cache
- return -1; //cache endless
- }
- /**
- * Download a remote file and return local filename
- *
- * returns false if download fails. Uses cached file if available and
- * wanted
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- * @author Pavel Vitis <Pavel.Vitis@seznam.cz>
- */
- function get_from_URL($url,$ext,$cache){
- global $conf;
- // if no cache or fetchsize just redirect
- if ($cache==0) return false;
- if (!$conf['fetchsize']) return false;
- $local = getCacheName(strtolower($url),".media.$ext");
- $mtime = @filemtime($local); // 0 if not exists
- //decide if download needed:
- if( ($mtime == 0) || // cache does not exist
- ($cache != -1 && $mtime < time()-$cache) // 'recache' and cache has expired
- ){
- if(image_download($url,$local)){
- return $local;
- }else{
- return false;
- }
- }
- //if cache exists use it else
- if($mtime) return $local;
- //else return false
- return false;
- }
- /**
- * Download image files
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
- function image_download($url,$file){
- global $conf;
- $http = new DokuHTTPClient();
- $http->max_bodysize = $conf['fetchsize'];
- $http->timeout = 25; //max. 25 sec
- $http->header_regexp = '!\r\nContent-Type: image/(jpe?g|gif|png)!i';
- $data = $http->get($url);
- if(!$data) return false;
- $fileexists = @file_exists($file);
- $fp = @fopen($file,"w");
- if(!$fp) return false;
- fwrite($fp,$data);
- fclose($fp);
- if(!$fileexists and $conf['fperm']) chmod($file, $conf['fperm']);
- // check if it is really an image
- $info = @getimagesize($file);
- if(!$info){
- @unlink($file);
- return false;
- }
- return true;
- }
- /**
- * Checks if the given amount of memory is available
- *
- * If the memory_get_usage() function is not available the
- * function just assumes $bytes of already allocated memory
- *
- * @param int $mem Size of memory you want to allocate in bytes
- * @param int $used already allocated memory (see above)
- * @author Filip Oscadal <webmaster@illusionsoftworks.cz>
- * @author Andreas Gohr <andi@splitbrain.org>
- */
- function is_mem_available($mem,$bytes=1048576){
- $limit = trim(ini_get('memory_limit'));
- if(empty($limit)) return true; // no limit set!
- // parse limit to bytes
- $limit = php_to_byte($limit);
- // get used memory if possible
- if(function_exists('memory_get_usage')){
- $used = memory_get_usage();
- }
- if($used+$mem > $limit){
- return false;
- }
- return true;
- }
- //Setup VIM: ex: et ts=2 enc=utf-8 :
- ?>