$ei) $mime = $stream[$i][$key]; }else $mime = $stream[$i]; break; default: $mime = 'application/octet-stream'; break; } } $filename = $row['path'] . "/". $row['title'] . "." . $row['type']; //проверка на существование и воспроизведение нужного файла if (!file_exists($filename) && !is_readable($filename)) exit('File does not exist or don`t readable'); //сервер сообщает клиенту, что непротив обслуживать байт-диапазонные запросы header('Accept-Ranges: bytes'); $f = fopen($filename, 'rb'); //проверка, открылся ли файл if(!$f){ header ("HTTP/1.0 505 Internal server error"); exit(); } flock($f, LOCK_EX); fseek($f, 0, SEEK_END); //указатель - в конец файла, получаем позицию указателя $size = ftell($f); //метка объекта, хеш всего файла $etag_server = md5_file($filename); //время последней модификации файла $last_mod = filemtime($filename); //клиент запросил докачку if (isset($_SERVER['HTTP_RANGE'])) { //проверяем, что лежит в $_SERVER['HTTP_RANGE']: bytes=20-50/длина файла if (!preg_match('/^bytes=(?:\d+-\d+|-\d+|\d+-)(?:,(?:\d+-\d+|-\d+|\d+-))*//\d+$/', $_SERVER['HTTP_RANGE'])) return false; // условные запросы if(isset($_SERVER['HTTP_IF_RANGE']) && $_SERVER['HTTP_IF_RANGE'] == $etag_server || strtotime($_SERVER['HTTP_IF_RANGE']) >= $last_mod){ //определяем, чем являются первые символы - меткой или датой if(!preg_match('/^\d{2}\s\d{2}\s\d{4}\s\d{2}:\d{2}:\d{2}\sGMT/', $_SERVER['HTTP_IF_RANGE'])){ //если это метка, проверяем, совпадает ли метка объекта с текущей if(isset($_SERVER['HTTP_IF_MATCH']) && $_SERVER['HTTP_IF_MATCH'] != "*"){ $etag_client = $_SERVER['HTTP_IF_MATCH']; //метка не совпала if($etag_client !== $etag_server){ //надо присвоить новую метку header("ETag: \"". $etag_server ."\""); // зафиксировать последнее изменение (сейчас) header ("Last-Modified: " . gmdate("d M Y H:i:s \G\M\T", time())); //страница не будет меняться 10 минут header("Expires: " . gmdate("d M Y H:i:s \G\M\T", time()+60*10)); } }else{ header("HTTP/1.1 412 Precondition Failed"); exit(); } }else{ //если это дата, проверяем время модификации if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_mod){ header ("Date: " . gmdate ("D, d M Y H:i:s \G\M\T")); header("HTTP/1.1 304 Not Modified"); //файл не поменялся }else{ if(strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) > $last_mod){ //файл изменился, присваиваем новую метку header("ETag: \"". $etag_server ."\""); // последнее изменение - сейчас header ("Last-Modified: " . gmdate("d M Y H:i:s \G\M\T", time())); //страница не будет меняться 10 минут header("Expires: " . gmdate("d M Y H:i:s \G\M\T", time()+60*10)); } } } //определяем диапазон $range=substr($_SERVER['HTTP_RANGE'], strpos($_SERVER['HTTP_RANGE'], '=')+1); $range = substr($range, strpos($range,0,"/")); $range = explode("-", $range); $from = $range[0]; $to = $range[1]; //если первая позиция не задана, берем ее с нуля if($from < 0) $from = 0; if($to) $to = ++ $to; //если не задана позиция конца else $to = $size; //первые байты, диапазон типа 521000- if($range[1]==''){ $from = 0; $to = $range[0]; } //последние байты, диапазон типа -300000 if($range[0]==''){ $from = $range[1]; $to = $size; } //узнаем, запросил клиент полный файл либо кусок if ($from > 0 || $to < $size) { //первый и последний байт куска $start = $from; $end = $to - 1; header('HTTP/1.1 206 Partial Content'); //метка header("ETag: \"". $etag_client ."\""); //длина диапазона, который считывается $part = $to - $from; header('Content-Length:' . $part); header('Content-Range: bytes ' . $start . "'-'" . $end . "'/'" . $size); }else{ // если клиент не запросил докачку или byte-range-spec некорректна header("HTTP/1.1 200 OK"); header('Content-Length:' . $size); } }else header("HTTP/1.1 416 Requested Range Not Satisfiable"); }else{ //клиент запросил весь файл $range = array(0,$size); $from = $range[0]; $to = $range[1]; $start = $from; } //отправляем заголовки и для целого файла, и для частичной загрузки header('Content-Type: '. $mime); header('Content-Disposition: attachment; filename=' . basename($filename)); //ставим указатель на начальную позицию, которую задал клиент fseek($f, $start, SEEK_SET); //выдача файла while(!feof($f)) { if($to == $size){ //выводим остаток до конца файла fpassthru($f); }else{ //выводим начало и середину $read = fread($f, 256000); echo $read; flush(); } } flock($f, LOCK_UN); fclose($f); }//while($row = //счетчик скачиваний $sql_update = "UPDATE books SET count_download = count_download + 1 WHERE id =" . $_GET['id_book']; mysql_query($sql_update); }//if(isset($_GET ?>