xref: /dokuwiki/lib/exe/fetch.php (revision 91438e0b7e3f078823c9b702e87263c1a9dd5f00)
1<?php
2/**
3 * DokuWiki media passthrough file
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Andreas Gohr <andi@splitbrain.org>
7 */
8
9  if(!defined('DOKU_INC')) define('DOKU_INC',dirname(__FILE__).'/../../');
10  define('DOKU_DISABLE_GZIP_OUTPUT', 1);
11  require_once(DOKU_INC.'inc/init.php');
12  require_once(DOKU_INC.'inc/common.php');
13  require_once(DOKU_INC.'inc/media.php');
14  require_once(DOKU_INC.'inc/pageutils.php');
15  require_once(DOKU_INC.'inc/httputils.php');
16  require_once(DOKU_INC.'inc/confutils.php');
17  require_once(DOKU_INC.'inc/auth.php');
18
19  //close sesseion
20  session_write_close();
21
22  $mimetypes = getMimeTypes();
23
24  //get input
25  $MEDIA  = stripctl(getID('media',false)); // no cleaning except control chars - maybe external
26  $CACHE  = calc_cache($_REQUEST['cache']);
27  $WIDTH  = (int) $_REQUEST['w'];
28  $HEIGHT = (int) $_REQUEST['h'];
29  list($EXT,$MIME,$DL) = mimetype($MEDIA);
30  if($EXT === false){
31    $EXT  = 'unknown';
32    $MIME = 'application/octet-stream';
33    $DL   = true;
34  }
35
36  //media to local file
37  if(preg_match('#^(https?)://#i',$MEDIA)){
38    //handle external images
39    if(strncmp($MIME,'image/',6) == 0) $FILE = media_get_from_URL($MEDIA,$EXT,$CACHE);
40    if(!$FILE){
41      //download failed - redirect to original URL
42      header('Location: '.$MEDIA);
43      exit;
44    }
45  }else{
46    $MEDIA = cleanID($MEDIA);
47    if(empty($MEDIA)){
48      header("HTTP/1.0 400 Bad Request");
49      print 'Bad request';
50      exit;
51    }
52
53    //check permissions (namespace only)
54    if(auth_quickaclcheck(getNS($MEDIA).':X') < AUTH_READ){
55      header("HTTP/1.0 401 Unauthorized");
56      //fixme add some image for imagefiles
57      print 'Unauthorized';
58      exit;
59    }
60    $FILE  = mediaFN($MEDIA);
61  }
62
63  //check file existance
64  if(!@file_exists($FILE)){
65    header("HTTP/1.0 404 Not Found");
66    //FIXME add some default broken image
67    print 'Not Found';
68    exit;
69  }
70
71  $ORIG = $FILE;
72
73  //handle image resizing/cropping
74  if((substr($MIME,0,5) == 'image') && $WIDTH){
75    if($HEIGHT){
76        $FILE = media_crop_image($FILE,$EXT,$WIDTH,$HEIGHT);
77    }else{
78        $FILE = media_resize_image($FILE,$EXT,$WIDTH,$HEIGHT);
79    }
80  }
81
82  // finally send the file to the client
83  $data = array('file'     => $FILE,
84                'mime'     => $MIME,
85                'download' => $DL,
86                'cache'    => $CACHE,
87                'orig'     => $ORIG,
88                'ext'      => $EXT,
89                'width'    => $WIDTH,
90                'height'   => $HEIGHT);
91
92  $evt = new Doku_Event('MEDIA_SENDFILE', $data);
93  if ($evt->advise_before()) {
94    sendFile($data['file'],$data['mime'],$data['download'],$data['cache']);
95  }
96
97/* ------------------------------------------------------------------------ */
98
99/**
100 * Set headers and send the file to the client
101 *
102 * @author Andreas Gohr <andi@splitbrain.org>
103 * @author Ben Coburn <btcoburn@silicodon.net>
104 */
105function sendFile($file,$mime,$dl,$cache){
106  global $conf;
107  $fmtime = @filemtime($file);
108  // send headers
109  header("Content-Type: $mime");
110  // smart http caching headers
111  if ($cache==-1) {
112    // cache
113    // cachetime or one hour
114    header('Expires: '.gmdate("D, d M Y H:i:s", time()+max($conf['cachetime'], 3600)).' GMT');
115    header('Cache-Control: public, proxy-revalidate, no-transform, max-age='.max($conf['cachetime'], 3600));
116    header('Pragma: public');
117  } else if ($cache>0) {
118    // recache
119    // remaining cachetime + 10 seconds so the newly recached media is used
120    header('Expires: '.gmdate("D, d M Y H:i:s", $fmtime+$conf['cachetime']+10).' GMT');
121    header('Cache-Control: public, proxy-revalidate, no-transform, max-age='.max($fmtime-time()+$conf['cachetime']+10, 0));
122    header('Pragma: public');
123  } else if ($cache==0) {
124    // nocache
125    header('Cache-Control: must-revalidate, no-transform, post-check=0, pre-check=0');
126    header('Pragma: public');
127  }
128  //send important headers first, script stops here if '304 Not Modified' response
129  http_conditionalRequest($fmtime);
130
131
132  //download or display?
133  if($dl){
134    header('Content-Disposition: attachment; filename="'.basename($file).'";');
135  }else{
136    header('Content-Disposition: inline; filename="'.basename($file).'";');
137  }
138
139  //use x-sendfile header to pass the delivery to compatible webservers
140  if (http_sendfile($file)) exit;
141
142  // send file contents
143  $fp = @fopen($file,"rb");
144  if($fp){
145    http_rangeRequest($fp,filesize($file),$mime);
146  }else{
147    header("HTTP/1.0 500 Internal Server Error");
148    print "Could not read $file - bad permissions?";
149  }
150}
151
152/**
153 * Returns the wanted cachetime in seconds
154 *
155 * Resolves named constants
156 *
157 * @author  Andreas Gohr <andi@splitbrain.org>
158 */
159function calc_cache($cache){
160  global $conf;
161
162  if(strtolower($cache) == 'nocache') return 0; //never cache
163  if(strtolower($cache) == 'recache') return $conf['cachetime']; //use standard cache
164  return -1; //cache endless
165}
166
167//Setup VIM: ex: et ts=2 enc=utf-8 :
168?>
169