$value) { switch (strtolower($key)) { case "range": $rangeheader=$value; break; case "if-modified-since": if (!(($pos=strpos($value,";"))===false)) $value=substr($value,0,$pos); # IE dodaje ";length=xxx" do daty. grrrr! :-) if ($modifiedtime<=strtotime($value)) { header($HTTP_SERVER_VARS["SERVER_PROTOCOL"]." 304 Not Modified"); exit(); }; case "if-unmodified-since": if (!(($pos=strpos($value,";"))===false)) $value=substr($value,0,$pos); # jak wyżej if (($modified>strtotime($value))&&(strtotime($value)!=-1)) { header($HTTP_SERVER_VARS["SERVER_PROTOCOL"]." 412 Precondition Failed"); exit(); }; case "if-range": if ($modifiedtime>strtotime($value)) $ifrangemod=1; break; } } # analiza nagłówka "Range" $ranges=array(); if (isset($rangeheader)) { if (preg_match("/^bytes[ ]*=[ ]*([0-9, -]*?)$/i",$rangeheader,$matches)) { $rangesstr=$matches[1]; # rozbijamy string na pojedyńcze zakresy $ranges=explode(",",$rangesstr); foreach($ranges as $key=>$range) { # szukamy granic zakresu if (preg_match("/^[ ]*([0-9]*)[ ]*-[ ]*([0-9]*)[ ]*$/",$range,$matches)) { if ($matches[1]=="") { if ($matches[2]=="") { # nieprawidłowy zakres - sama kreska! $ranges=array(); break; } else { # zakres typu "-100" $ranges[$key]=array($filesize-$matches[2],$filesize-1); } } else { if ($matches[2]=="") { # zakres typu "10-" $ranges[$key]=array($matches[1],$filesize-1); } else { # zakres typu "10-100" $ranges[$key]=array($matches[1],$matches[2]); } } } else { # zakres nieprawidłowy $ranges=array(); break; } } # sprawdzenie czy granice zakresu mieszczą się w przedziale <0,filesize-1> foreach($ranges as $key=>$range) { if (($range[0]>$range[1])||($range[0]<0)||($range[1]<0)||($range[0]>=$filesize)||($range[1]>=$filesize)) { # zakres nieprawidłowy $ranges=array(); break; } } } } if ((sizeof($ranges)==0)||(isset($ifrangemod))) # nie ma zakresu lub warunek w "If-Range" niespełniony { header($HTTP_SERVER_VARS["SERVER_PROTOCOL"]." 200 OK"); header("Last-Modified: ".$modified); header("Accept-Ranges: bytes"); header("Content-Type: ".$contenttype); header("Content-Length: ".$filesize); fpassthru($fp); } else # jest conajmniej jeden zakres i "If-Range" spełnione { header($HTTP_SERVER_VARS["SERVER_PROTOCOL"]." 206 Partial Content"); if (sizeof($ranges)==1) # dokładnie jeden zakres { header("Last-Modified: ".$modified); header("Content-Type: ".$contenttype); header("Content-Range: ".$ranges[0][0]."-".$ranges[0][1]."/".$filesize); outputpart($fp,$ranges[0][0],$ranges[0][1]); } else # więcej zakresów - wysyłamy jako "multipart/byteranges" { # działanie poniższego kodu nie zostało sprawdzone w praktyce!!! # nie znam programu który z tej metody przesyłania korzysta! $boundary=md5(uniqid("")); header("Last-Modified: ".$modified); header("Content-Type: multipart/byteranges; boundary=".$boundary); foreach($ranges as $key=>$range) { echo "--".$boundary."\r\n"; echo "Content-Type: ".$contenttype."\r\n"; echo "Content-Transfer-Encoding: 8bit\r\n"; echo "Content-Range: ".$range[0]."-".$range[1]."/".$filesize."\r\n"; echo "\r\n"; outputpart($fp,$range[0],$range[1]); echo "\r\n"; } echo "--".$boundary."--\r\n"; } } fclose($fp); set_error_handler($oldhandler); error_reporting($olderrorlevel); } # wypisanie fragmentu pliku na wyjście function outputpart($fp,$from,$to) { $len=$to-$from+1; $chunklen=65536; $chunks=intval($len/$chunklen); fseek($fp,$from); for ($i=0;$i<$chunks;$i++) { echo fread($fp,$chunklen); } $rest=$len-($chunks*$chunklen); if ($rest>0) echo(fread($fp,$rest)); } function myerrhandler($errno,$errstr) { global $HTTP_HOST,$HTTP_SERVER_VARS; # jeśli jeszcze żadne dane nie poszły to error 404 ;-) # jeśli już coś poszło to nie należy nic wypisywać, bo klient może chcieć kontynuować od miejsca przerwania if (!headers_sent()) header($HTTP_SERVER_VARS["SERVER_PROTOCOL"]." 404 Not Found"); # error 404 exit(); } # zwraca typ MIME pliku w zależności od rozszerzenia # lista typów do uzupełnienia zależnie od potrzeb function ctype($filename) { preg_match("/\.(.*?)$/i",basename($filename),$matches); $ext=isset($matches[1])?$matches[1]:""; $ext=strtolower($ext); $types=array( "zip" => "application/zip", "jpg" => "image/jpeg", "jpeg" => "image/jpeg", "jpe" => "image/jpeg", "gif" => "image/gif", "png" => "image/png", "html" => "text/html", "htm" => "text/html", "txt" => "text/plain" ); $type=isset($types[$ext])?$types[$ext]:"application/octet-stream"; return($type); } ?>