45 foreach ( $headers as $name => $header ) {
46 $nameLower = strtolower( $name );
47 if ( in_array( $nameLower, [
'range',
'if-modified-since' ],
true ) ) {
48 $optHeaders[$nameLower] = $header;
50 $rawHeaders[] =
"$name: $header";
53 return [ $rawHeaders, $optHeaders ];
82 $headers = [], $sendErrors =
true, $optHeaders = [], $flags = 0
87 if ( $headers && headers_sent() ) {
88 echo
"Headers already sent, terminating.\n";
93 ?
static function ( $header ) {
96 : $this->header( ... );
99 $info = @stat( $this->path );
101 if ( !is_array( $info ) ) {
109 $mtimeCT =
new ConvertibleTimestamp( $info[
'mtime'] );
110 $headerFunc(
'Last-Modified: ' . $mtimeCT->getTimestamp( TS::RFC2822 ) );
112 if ( ( $flags & self::STREAM_ALLOW_OB ) == 0 ) {
117 if ( $type && $type !=
'unknown/unknown' ) {
128 if ( isset( $optHeaders[
'if-modified-since'] ) ) {
129 $modsince = preg_replace(
'/;.*$/',
'', $optHeaders[
'if-modified-since'] );
130 if ( $mtimeCT->getTimestamp( TS::UNIX ) <= strtotime( $modsince ) ) {
131 ini_set(
'zlib.output_compression', 0 );
138 foreach ( $headers as $header ) {
142 if ( isset( $optHeaders[
'range'] ) ) {
144 if ( is_array( $range ) ) {
147 $headerFunc(
"Content-Range: bytes {$range[0]}-{$range[1]}/{$info['size']}" );
148 } elseif ( $range ===
'invalid' ) {
152 $headerFunc(
'Content-Type: text/html; charset=utf-8' );
153 $headerFunc(
'Content-Range: bytes */' . $info[
'size'] );
165 if ( is_array( $range ) ) {
166 $handle = fopen( $this->path,
'rb' );
169 fseek( $handle, $range[0] );
170 $remaining = $range[2];
171 while ( $remaining > 0 && $ok ) {
172 $bytes = min( $remaining, 8 * 1024 );
173 $data = fread( $handle, $bytes );
174 $remaining -= $bytes;
175 $ok = ( $data !== false );
182 return readfile( $this->path ) !==
false;
221 if ( preg_match(
'#^bytes=(\d*)-(\d*)$#', $range, $m ) ) {
222 [ , $start, $end ] = $m;
223 if ( $start ===
'' && $end ===
'' ) {
224 $absRange = [ 0, $size - 1 ];
225 } elseif ( $start ===
'' ) {
226 $absRange = [ $size - (int)$end, $size - 1 ];
227 } elseif ( $end ===
'' ) {
228 $absRange = [ (int)$start, $size - 1 ];
230 $absRange = [ (int)$start, (
int)$end ];
232 if ( $absRange[0] >= 0 && $absRange[1] >= $absRange[0] ) {
233 if ( $absRange[0] < $size ) {
234 $absRange[1] = min( $absRange[1], $size - 1 );
235 $absRange[2] = $absRange[1] - $absRange[0] + 1;
237 } elseif ( $absRange[0] == 0 && $size == 0 ) {
238 return 'unrecognized';
243 return 'unrecognized';