ILIAS  release_7 Revision v7.30-3-g800a261c036
PHPChunked.php
Go to the documentation of this file.
1 <?php
2 
20 
24 
25 require_once('./Services/FileDelivery/interfaces/int.ilFileDeliveryType.php');
26 
34 final class PHPChunked implements ilFileDeliveryType
35 {
36 
40  private $httpService;
41 
42 
48  public function __construct(GlobalHttpState $httpState)
49  {
50  $this->httpService = $httpState;
51  }
52 
53 
57  public function doesFileExists($path_to_file)
58  {
59  return is_readable($path_to_file);
60  }
61 
62 
66  public function prepare($path_to_file)
67  {
68  return true;
69  }
70 
71 
75  public function deliver($path_to_file, $file_marked_to_delete)
76  {
77  $file = $path_to_file;
78  $fp = @fopen($file, 'rb');
79  // see https://mantis.ilias.de/view.php?id=36970
80  if ($fp === false) {
81  $response = $this->httpService->response()->withStatus(404);
82  $this->httpService->saveResponse($response);
83  $this->close();
84  }
85 
86  $size = filesize($file); // File size
87  $length = $size; // Content length
88  $start = 0; // Start byte
89  $end = $size - 1; // End byte
90  // Now that we've gotten so far without errors we send the accept range header
91  /* At the moment we only support single ranges.
92  * Multiple ranges requires some more work to ensure it works correctly
93  * and comply with the spesifications: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2
94  *
95  * Multirange support annouces itself with:
96  * header('Accept-Ranges: bytes');
97  *
98  * Multirange content must be sent with multipart/byteranges mediatype,
99  * (mediatype = mimetype)
100  * as well as a boundry header to indicate the various chunks of data.
101  */
102  $response = $this->httpService->response()->withHeader("Accept-Ranges", "0-$length");
103  $this->httpService->saveResponse($response);
104  $server = $this->httpService->request()->getServerParams();
105  // header('Accept-Ranges: bytes');
106  // multipart/byteranges
107  // http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2
108  if (isset($server['HTTP_RANGE'])) {
109  $c_start = $start;
110  $c_end = $end;
111 
112  // Extract the range string
113  list(, $range) = explode('=', $server['HTTP_RANGE'], 2);
114  // Make sure the client hasn't sent us a multibyte range
115  if (strpos($range, ',') !== false) {
116  // (?) Shoud this be issued here, or should the first
117  // range be used? Or should the header be ignored and
118  // we output the whole content?
119  $response = $this->httpService->response()->withStatus(416)->withHeader(ResponseHeader::CONTENT_RANGE, "bytes $start-$end/$size");
120  $this->httpService->saveResponse($response);
121 
122  //header("Content-Range: bytes $start-$end/$size");
123  // (?) Echo some info to the client?
124  $this->close();
125  } // fim do if
126  // If the range starts with an '-' we start from the beginning
127  // If not, we forward the file pointer
128  // And make sure to get the end byte if spesified
129  if ($range[0] == '-') {
130  // The n-number of the last bytes is requested
131  $c_start = $size - substr($range, 1);
132  } else {
133  $range = explode('-', $range);
134  $c_start = $range[0];
135  $c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size;
136  } // fim do if
137  /* Check the range and make sure it's treated according to the specs.
138  * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
139  */
140  // End bytes can not be larger than $end.
141  $c_end = ($c_end > $end) ? $end : $c_end;
142  // Validate the requested range and return an error if it's not correct.
143  if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) {
144  $response = $this->httpService->response()->withStatus(416)->withHeader(ResponseHeader::CONTENT_RANGE, "bytes $start-$end/$size");
145 
146  $this->httpService->saveResponse($response);
147  // (?) Echo some info to the client?
148  $this->close();
149  } // fim do if
150 
151  $start = $c_start;
152  $end = $c_end;
153  $length = $end - $start + 1; // Calculate new content length
154  fseek($fp, $start);
155 
156  $response = $this->httpService->response()->withStatus(206);
157 
158  $this->httpService->saveResponse($response);
159  } // fim do if
160 
161  // Notify the client the byte range we'll be outputting
162  $response = $this->httpService->response()->withHeader(ResponseHeader::CONTENT_RANGE, "bytes $start-$end/$size")->withHeader(ResponseHeader::CONTENT_LENGTH, $length);
163 
164  $this->httpService->saveResponse($response);
165 
166  //render response and start buffered download
167  $this->httpService->sendResponse();
168 
169  // Start buffered download
170  $buffer = 1024 * 8;
171  while (!feof($fp) && ($p = ftell($fp)) <= $end) {
172  if ($p + $buffer > $end) {
173  // In case we're only outputtin a chunk, make sure we don't
174  // read past the length
175  $buffer = $end - $p + 1;
176  } // fim do if
177 
178  set_time_limit(0); // Reset time limit for big files
179  echo fread($fp, $buffer);
180  flush(); // Free up memory. Otherwise large files will trigger PHP's memory limit.
181  } // fim do while
182 
183  fclose($fp);
184 
185  return true;
186  }
187 
188 
192  public function supportsInlineDelivery()
193  {
194  return true;
195  }
196 
197 
201  public function supportsAttachmentDelivery()
202  {
203  return true;
204  }
205 
206 
210  public function supportsStreaming()
211  {
212  return true;
213  }
214 
215 
216  private function close()
217  {
218  //render response
219  $this->httpService->sendResponse();
220  exit;
221  }
222 
223 
227  public function handleFileDeletion($path_to_file)
228  {
229  return unlink($path_to_file);
230  }
231 }
Interface GlobalHttpState.
$size
Definition: RandomTest.php:84
exit
Definition: login.php:29
__construct(GlobalHttpState $httpState)
PHP constructor.
Definition: PHPChunked.php:48
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$server
deliver($path_to_file, $file_marked_to_delete)
absolute path to fileThis is needed at this point for header-based delivery methodsbool ...
Definition: PHPChunked.php:75
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$response