PHP Загрузка файла размером 7 ГБ прекращается раньше, чем в диапазоне от 3 до 4,5 ГБ - PullRequest
0 голосов
/ 07 августа 2020

У меня есть игра, которую я пытаюсь выпустить, и ее размер составляет 7 ГБ. Я использую PHP для его распространения. Написанный мной сценарий PHP может начать загрузку без проблем, и я могу использовать тот же сценарий для гораздо меньшего размера zip-архива, и он отлично загружается. Я также могу без проблем распаковать файл меньшего размера и извлечь его содержимое. Однако, когда я пытаюсь загрузить файл большего размера, кажется, что он прерывается раньше, где-то между 3 ГБ и 4,5 ГБ. Это в основном случайное, хотя большую часть времени оно имеет тенденцию останавливаться на отметке 4,3 ГБ. Очевидно, что когда я пытаюсь распаковать неполный файл, он поврежден и не может быть разархивирован. также пробовал использовать while (!feof($handle)) вместо while($size > $bytes_read) с тем же результатом. Я также пробовал отключить сжатие через .htaccess, например, SetEnv no-gzip dont-vary. Моя версия php - 7.3.

Я застрял на этом несколько дней и не уверен, что делаю не так. Помощь будет принята с благодарностью!

РЕДАКТИРОВАТЬ с дополнительной информацией:

  1. Настройка ini_set('memory_limit',-1);, похоже, не повлияла.
  2. Как test, я установил usleep(1000000);, загрузка стала намного медленнее, и файл перестал загружаться примерно на 900 МБ. Это заставляет меня думать, что это должна быть проблема с тайм-аутом, но тогда почему ini_set('max_execution_time','0'); не решает это?
  3. var_dump(ini_get('safe_mode')); равно bool(false)
  4. Я считаю, что тайм-аут время ожидания Apachi. Я рассчитал время загрузки несколько раз, и она останавливается ровно через 300 секунд, что является тайм-аутом Apachi по умолчанию. У меня есть бизнес-аккаунт в GoDaddy, и они отказываются изменять тайм-аут Apachi.
    ob_clean(); // Clear any previously written headers in the output buffer
    flush();
    ini_set('memory_limit','1G');
    ini_set('max_execution_time','0');
    $file = "builds/RoA.zip";
    $chunksize = 5 * (1024 * 1024); // different chunk sizes don't make a difference
    ob_start();
    set_time_limit(0);
    // ini_get(max_execution_time) returns 0
    
    if (is_file($file))
    {
        $ext = pathinfo($file, PATHINFO_EXTENSION);
        $basename = pathinfo($file, PATHINFO_BASENAME);
        $size = intval(sprintf("%u", filesize($file)));
        // http headers for zip downloads
        header("Pragma: public");
        header("Expires: 0");
        header("Cache-Control: public");
        header("Cache-Control: must-revalidate, post-check=0, pre-check=0", FALSE);
        header("Content-Description: File Transfer");
        //header("Content-Type: application/zip");
        header('Content-Type: application/octet-stream');
        header('Content-Transfer-Encoding: binary');
        header('Content-Length: '.$size); // gives correct size to Google Chrome. Is able to see progress.
        header("Content-Disposition: attachment; filename=\"".$basename."\"");

        $handle = fopen($file, 'rb') or die("Couldn't get handle");
        
        $bytes_read = 0;
        while($size > $bytes_read)
        {
            set_time_limit(30);
            $buffer = fread($handle, $chunksize);
            echo $buffer;
            $bytes_read+=$chunksize;
            
            ob_flush();
            flush();
        }

        fclose($handle); 
        
        ob_end_flush();
        exit;
    }
...