Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
Социальная инженерия и социальные хакеры. Авторы: Кузнецов М.В., Симдянов И.В. PHP на примерах (2 издание). Авторы: Кузнецов М.В., Симдянов И.В. C++. Мастер-класс в задачах и примерах. Авторы: Кузнецов М.В., Симдянов И.В. Самоучитель MySQL 5. Авторы: Кузнецов М.В., Симдянов И.В. PHP 5/6. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум PHP

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Ошибки при скачивание файла через скрипт
 
 автор: Xzed   (21.07.2009 в 21:45)   письмо автору
 
 

Здравствуйте:)

Написал файлообменник. Но так как загрузка файла из него можно сказать нехалявная (за поинты определенные), то загрузку осуществляю через php-файл. Но при таком скачивании постоянно выдается ошибка и загрузку приходится возобновлять.

На данный момент использую для вывода файла через скрипт следующую функцию, которую нашёл в интернете:

function downloadFile($filename, $mimetype='application/octet-stream') {
    if (!file_exists($filename)) die('Файл не найден');
    $from=$to=0; $cr=NULL;
    if (isset($_SERVER['HTTP_RANGE'])) {
        $range=substr($_SERVER['HTTP_RANGE'], strpos($_SERVER['HTTP_RANGE'], '=')+1);
        $from=strtok($range, '-');
        $to=strtok('/'); if ($to>0) $to++;
        if ($to) $to-=$from;
        header('HTTP/1.1 206 Partial Content');
        $cr='Content-Range: bytes ' . $from . '-' . (($to)?($to . '/' . $to+1):filesize($filename));
    } else    header('HTTP/1.1 200 Ok');
    $etag=md5($filename);
    $etag=substr($etag, 0, 8) . '-' . substr($etag, 8, 7) . '-' . substr($etag, 15, 8);
    header('ETag: "' . $etag . '"');
    header('Accept-Ranges: bytes');
    header('Content-Length: ' . (filesize($filename)-$to+$from));
    if ($cr) header($cr);
    header('Connection: close');
    header('Content-Type: ' . $mimetype);
    header('Last-Modified: ' . gmdate('r', filemtime($filename)));
    $f=fopen($filename, 'r');
    header('Content-Disposition: attachment; filename="' . basename($filename) . '";');
    if ($from) fseek($f, $from, SEEK_SET);
    if (!isset($to) or empty($to)) {
        $size=filesize($filename)-$from;
    } else {
        $size=$to;
    }
    $downloaded=0;
    while(!feof($f) and !connection_status() and ($downloaded<$size)) {
        echo fread($f, 512000);
        $downloaded+=512000;
        flush();
    }
    fclose($f);
}


Плюс этой функции в том, что хоть докачку файла поддерживает, а то без докачки вообще скачать невозможно, т.к. за время скачивания ошибок 5 возникнет. Но не у всех браузеров есть докачка и возобновление загрузки после ошибки!
Как быть? В чем проблема? Проблема в php-скрипте или же это уже прихоти сервера?
Как например другие коммерческие файлообменники дают скачивать файлы через скрипт без всяких сбоев?

  Ответить  
 
 автор: Петр   (22.07.2009 в 09:41)   письмо автору
 
   для: Xzed   (21.07.2009 в 21:45)
 

А если скачивать теже файлы без скрипта а напрямую по ссылке? Тоже обрывы происходят?
поиграй с размером буфера, попробуй уменьшить его fread($f, 512000);

  Ответить  
 
 автор: Xzed   (22.07.2009 в 21:30)   письмо автору
 
   для: Петр   (22.07.2009 в 09:41)
 

Напрямую (не через скрипт) качает отлично.
Спасибо за совет насчёт буфера.

Кстати, а может есть какие либо другие алгоритмы или решения для отдачи файла юзеру за поинты?

Вот также нашел альтернативную функцию:
// $filepath – путь к файлу, который мы хотим отдать  
// $mimetype – тип отдаваемых данных (можно не менять)  
function func_download_file($filepath, $mimetype = 'application/octet-stream') {  
    $fsize = filesize($filepath); // берем размер файла  
    $ftime = date('D, d M Y H:i:s T', filemtime($filepath)); // определяем дату его модификации  
  
    $fd = @fopen($filepath, 'rb'); // открываем файл на чтение в бинарном режиме  
  
    if (isset($_SERVER['HTTP_RANGE'])) { // поддерживается ли докачка?  
        $range = $_SERVER['HTTP_RANGE']; // определяем, с какого байта скачивать файл  
        $range = str_replace('bytes=', '', $range);  
        list($range, $end) = explode('-', $range);  
  
        if (!empty($range)) {  
            fseek($fd, $range);  
        }  
    } else { // докачка не поддерживается  
        $range = 0;  
    }  
  
    if ($range) {  
        header($_SERVER['SERVER_PROTOCOL'].' 206 Partial Content'); // говорим браузеру, что это часть какого-то контента  
    } else {  
        header($_SERVER['SERVER_PROTOCOL'].' 200 OK'); // стандартный ответ браузеру  
    }  
  
    // прочие заголовки, необходимые для правильной работы  
    header('Content-Disposition: attachment; filename='.basename($filepath));  
    header('Last-Modified: '.$ftime);  
    header('Accept-Ranges: bytes');  
    header('Content-Length: '.($fsize - $range));  
    header("Content-Range: bytes $range-".($fsize - 1).'/'.$fsize);  
    header('Content-Type: '.$mimetype);  
    header('Content-transfer-encoding: binary');  
  
    fpassthru($fd); // отдаем часть файла в браузер (программу докачки)  
    fclose($fd);  
  
    exit;  
}  


Результат тоже не особо радует. Также обрывает.

Кто использует такие же функции в своих скриптах? Поделитесь опытом, расскажите как у Вас скачивает файлы через эту функцию и какой у Вас интернет?
Если проблему не решим, то хотя бы диагностику проведем, а дальше думать будем...

  Ответить  
 
 автор: Xzed   (26.07.2009 в 10:36)   письмо автору
 
   для: Xzed   (22.07.2009 в 21:30)
 

Ничего не помогает. У тех кто сидит с GPRS-интернетом (а у меня как раз WAP-сайт) или модемом никогда ничего таким образом не скачает.

Да и такой скрипт нагрузку на сервер будет немалую создавать при приличной посещаемости.
Вывод таков: надо искать другие пути решения отдачи файлов юзерам ненапрямую. Или...

Помимо того, что скрипт считает количество скачиваний и отнимает у юзеров поинты, он ещё и выполняет защитную функцию.
Права на папки в файлообменнике как правилo 777. То есть злоумышленник, найдя способ залить шел, наверняка воспользуется данными папками. Но у меня доступ к файлам в этих папка закрыт .htaccessом (строчкой Deny from all), поэтому скачать (запустить) файл можно только через скрипт, а скачать через скрипт можно только промодерированные файлы. Поэтому я бы и мог сделать юзерам скачивание файлов без всяких поинтов, а счётчик сделал бы типа
<? 
счётчик
=счётчик+1
header
("Location: прямая ссылка на файл");
?>

Но если я открою публичный доступ к папкам файлообменника, чтобы качать файлы напрямую, то появится потенциальная угроза.
Вопрос в следующем: можно ли каким-либо образом разрешить серверу хранить в папках файлы только определенного формата и mime-типа?
Например в папке music, чтобы были только *.mp3, а если будет какой-либо *.php, то сервер просто выдаст типа "Forbidden" или "Not found"?

  Ответить  
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования