Защищенный от дурака, загрузка силы перекрестного браузера в PHP

Я использую вызванную загрузку для загрузки главным образом zip и mp3s на сайте, который я сделал (http://pr1pad.kissyour.net) - чтобы отследить загрузки в аналитике Google в базе данных и скрыть реальный путь загрузки:

Это - это:

extending CI model

... - bunch of code

function _fullread ($sd, $len) {
 $ret = '';
 $read = 0;
 while ($read < $len && ($buf = fread($sd, $len - $read))) {
  $read += strlen($buf);
  $ret .= $buf;
 }
 return $ret;
}

function download(){    
    /* DOWNLOAD ITSELF */

    ini_set('memory_limit', '160M');
    apache_setenv('no-gzip', '1');
    ob_end_flush();

    header("Pragma: public");
    header("Expires: 0");
    header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
    header("Cache-Control: public",FALSE);
    header("Content-Description: File Transfer");
    header("Content-type: application/octet-stream");
     if (isset($_SERVER['HTTP_USER_AGENT']) && 
      (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false))
      header('Content-Type: application/force-download'); //IE HEADER
    header("Accept-Ranges: bytes");
    header("Content-Disposition: attachment; filename=\"" . basename("dir-with-    files/".$filename) . "\";");
    header("Content-Transfer-Encoding: binary");
    header("Content-Length: " . filesize("dir-with-files/".$filename));

    // Send file for download
    if ($stream = fopen("dir-with-files/$filename", 'rb')){
     while(!feof($stream) && connection_status() == 0){
      //reset time limit for big files
      set_time_limit(0);
      print($this->_fullread($stream,1024*16));
      flush();
     }
     fclose($stream);
    }
}

Это находится на ЛАМПЕ с CI 1.7.2 - Это - мой собственный метод, соединенный из различных практических руководств на всем протяжении Интернета, потому что во время разработки, эти проблемы подошли: - предел сервера. ini_set не помогли, таким образом, я использовал буферизованный _fullread вместо этого нормальный fread, который использовался insted @readonly - ob_end_flush (), потому что сайт, сделал в CI1.7.2, и я должен был убрать буфер

Теперь... Это не работает. Это сделало, затем это прекратило показывать ожидаемое время размера/загрузки - я пытался очистить его и в то время как я очищал код, что-то произошло, я не знаю то, что и в любой предыдущей версии - это не работало (никакое изменение в настройках вообще) - редактирование: не работайте =, производит все в окно браузера.

Таким образом, я сказал, завинтите его, я посмотрю здесь.

Так, я в основном ищу сценарий или функцию, которую я могу поместить в свою выходную модель и сделаю:

  • Звоните загрузка силы (в Chrome запускают загрузку, в IE, FF, Safari открываются, модальные открываются/сохраняют/отменяют),
  • Покажите размер файла и оцененное dl время (это до браузера, я знаю, но сначала, браузер должен знать размер файла
  • РАБОТА (протестированный и подтвержденный!) в IE6,7,8, FF3, Opera, Chrome и и сафари на ПК + Mac (Linux... Я действительно не забочусь) - это для части заголовка
  • на сервере у меня есть также что-то как предел памяти 56 МБ, к которому я не могу добавить, таким образом, это также важно

Заранее спасибо.

Править: Теперь я чувствую себя более завинченным затем когда-либо/прежде чем, так как я пытался вызвать загрузку с .htaccess - в то время как это работало, это имело немногих незначительных/главных (выберите Ваш), проблемы

  • это показало полный путь (незначительный для меня)
  • это ожидает, пока целая загрузка не закончена (показывающий "соединяющийся"), и затем просто покажите, что это загружает - и загружает за одну секунду (главный для меня)

Теперь, хотя я удалил .htaccess, он все еще ожидает, пока загрузка не завершена (так же, как если бы он загружал для кэширования сначала), и это просто get's connected и шоу открывается/сохраняет диалоговое окно.

6
задан Adam Kiss 10 February 2010 в 16:21
поделиться

5 ответов

Это зависит от того, кто пишет код клиента. Если вы пишете клиент и сервер, то это не имеет большого значения. Вы либо испытаете боль при создании URL-адресов на клиенте или на сервере.

Однако если вы создаете сервер и ожидаете, что другие люди напишут клиентский код, то они будут любить вас гораздо больше, если вы предоставите полные URI. Разрешение относительных URI может быть немного сложным. Сначала способ их разрешения зависит от возвращенного типа носителя. Html имеет базовый тег, Xml может иметь xml: базовые теги в каждом вложенном элементе, каналы Atom могут иметь базу в канале и другую базу в содержимом. Если вы не предоставляете клиенту явную информацию о базовом URI, то они должны получить базовый URI из URI запроса или, возможно, из заголовка Content-Location! И берегись этой следящей косой черты. Базовый URI определяется путем игнорирования всех символов справа от последней косой черты. Это означает, что завершающая косая черта теперь очень важна при разрешении относительных URI.

Единственным вопросом, требующим небольшого упоминания, является размер документа. Если вы возвращаете большой список элементов, где каждый элемент может иметь несколько ссылок, использование абсолютных URL-адресов может добавить значительное количество байтов в вашу сущность, если вы не сжимаете сущность. Это проблема perf, и вы должны решить, является ли она значимой в каждом конкретном случае.

-121--849623-

Программы Android могут взаимодействовать с другими пользователями с помощью своих намерений. Интенты немного похожи на удаленные вызовы процедур: вы запрашиваете у другой программы определенное действие (например, сканировать штрих-код), и другая программа выполнит эту задачу для вас. Результат возвращается по завершении задачи.

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

Более подробную информацию об этом сканере можно найти на странице Google Code этого проекта: http://code.google.com/p/zxing/wiki/ScanningViaIntent

-121--1305052-

Таким образом, я использовал этот код (это измененная версия возобновления загрузки HTTP найдена в Интернете)

function _output_file($file, $path)
{
    $size = filesize($path.$file);

    @ob_end_clean(); //turn off output buffering to decrease cpu usage

    // required for IE, otherwise Content-Disposition may be ignored
    if(ini_get('zlib.output_compression'))
    ini_set('zlib.output_compression', 'Off');

    header('Content-Type: application/force-download');
    header('Content-Disposition: attachment; filename="'.basename($file).'"');
    header("Content-Transfer-Encoding: binary");
    header('Accept-Ranges: bytes');

    /* The three lines below basically make the 
    download non-cacheable */
    header("Cache-control: no-cache, pre-check=0, post-check=0");
    header("Cache-control: private");
    header('Pragma: private');
    header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");

    // multipart-download and download resuming support
    if(isset($_SERVER['HTTP_RANGE']))
    {
        list($a, $range) = explode("=",$_SERVER['HTTP_RANGE'],2);
        list($range) = explode(",",$range,2);
        list($range, $range_end) = explode("-", $range);
        $range=intval($range);
        if(!$range_end) {
            $range_end=$size-1;
        } else {
            $range_end=intval($range_end);
        }

        $new_length = $range_end-$range+1;
        header("HTTP/1.1 206 Partial Content");
        header("Content-Length: $new_length");
        header("Content-Range: bytes $range-$range_end/$size");
    } else {
        $new_length=$size;
        header("Content-Length: ".$size);
    }

    /* output the file itself */
    $chunksize = 1*(1024*1024); //you may want to change this
    $bytes_send = 0;
    if ($file = fopen($path.$file, 'rb'))
    {
        if(isset($_SERVER['HTTP_RANGE']))
        fseek($file, $range);

        while
            (!feof($file) && 
             (!connection_aborted()) && 
             ($bytes_send<$new_length) )
        {
            $buffer = fread($file, $chunksize);
            print($buffer); //echo($buffer); // is also possible
            flush();
            $bytes_send += strlen($buffer);
        }
    fclose($file);
    } else die('Error - can not open file.');

die();
}

, а затем в модели:

function download_file($filename){
    /*
        DOWNLOAD
    */
    $path = "datadirwithmyfiles/"; //directory

    //track analytics

    include('includes/Galvanize.php'); //great plugin
    $GA = new Galvanize('UA-XXXXXXX-7');
    $GA->trackPageView();

    $this->_output_file($filename, $path);

}

Он работает, как и ожидалось во всех упомянутых браузерах на Win/MAC - до сих пор

8
ответ дан 9 December 2019 в 22:34
поделиться

Есть одна странная вещь: вы вызываете ob_end_flush () в начале функции. Это фактически очищает выходной буфер, но также сначала выводит все на клиент (я предполагаю, включая Content-Headers, установленные CodeIgniter). Измените вызов на ob_end_clean () , он очищает буфер и отбрасывает его. Это даст вам чистый старт для создания ваших собственных заголовков.

Другой совет:

Вместо того, чтобы читать файл как поток и передавать его по блокам, вы можете попробовать эту функцию:

// ...
if (file_exists("dir-with-files/$filename")) {
   readfile($file);
}

Она позаботится почти обо всем.

1
ответ дан 9 December 2019 в 22:34
поделиться

print ($ this -> _ fullread ($ stream, 1024 * 16));

Я полагаю, _fullread находится внутри класса? Если код выглядит так, как показано выше, то $ this -> работать не будет.

Выводит ли он содержимое файла на экран, если вы закомментировали весь материал заголовка?

0
ответ дан 9 December 2019 в 22:34
поделиться

Просто выстрел в темноте... каждый заголовок, который я посылаю в своем коде 'принудительной загрузки' (который не так хорошо протестирован, как ваш), тот же самый, что и ваш, за исключением того, что я звоню: header("Cache-Control: private",false);

вместо него: header("Cache-Control: public",FALSE);

Не знаю, поможет это или нет.

0
ответ дан 9 December 2019 в 22:34
поделиться

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

Если у вас есть обычная загрузка файла, Apache может поддерживать возобновленную загрузку через HTTP, но в случае, если загрузка приостановлена, Apache не имеет возможности выяснить, где в вашем скрипте выполнялись какие-либо объекты, когда клиент запрашивает следующий кусок.

По сути, когда браузер приостанавливает загрузку, он полностью разрывает соединение с веб-сервером. Когда вы возобновляете загрузку, соединение снова открывается, и запрос содержит флаг, говорящий «Начать с байта номер X». Но для веб-сервера, смотрящего на ваш PHP выше, откуда берется байт X?

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

РЕДАКТИРОВАТЬ: Кажется, вы сможете справиться с этим случаем, но с вашей стороны потребуется МНОГО кода. См. http://www.php.net/manual/en/function.fread.php # 84115 .

0
ответ дан 9 December 2019 в 22:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: