iPwnTech
iPwnTech

Reputation: 545

Large files failing to download using readfile()

I have the following code to force download an IPA file (after codesigning it with a script). It works fine with smaller files but with larger files, my web server starts returning a 500 Internal Server Error. Would someone be able to help me tweak my existing code to overcome this issue?

$time = md5(time());

// Runs code signing script here
// And then attempts to initiate download

$path = "done/$time/";         
$latest_ctime = 0;
$latest_filename = '';    

$d = dir($path);
while (false !== ($entry = $d->read())) {
  $filepath = "{$path}/{$entry}";
  if (is_file($filepath) && filectime($filepath) > $latest_ctime) {
    $latest_ctime = filectime($filepath);
    $latest_filename = $entry;
  }
}        

 header("Cache-Control: public");
 header("Content-Description: File Transfer");
 header("Content-Disposition: attachment; filename=$time.ipa");
 header("Content-Type: application/ipa");
 header("Content-Transfer-Encoding: binary");
 // Read the file from disk
 readfile("done/$time/".$latest_filename);
       // header('location: dashboard.php');
   } else {
// Throwback

die("Failed. Contact support. // <p>$sign</p>");

}

Upvotes: 0

Views: 609

Answers (2)

Volodymyr Chumak
Volodymyr Chumak

Reputation: 766

Here is an example:

$filepath = "done/{$time}/{$latest_filename}";
$size     = filesize($filepath);
$mimetype = 'application/ipa';

// Turn off buffering
if (ob_get_level()) {
    ob_end_clean();
}

$handle = fopen($filepath, 'rb');
if ($handle !== false && $size > 0) {
    @flock($handle, LOCK_SH);

    $filename               = rawurldecode($filepath);
    $old_max_execution_time = ini_get('max_execution_time');
    $old_cache_limiter      = session_cache_limiter();

    ini_set('max_execution_time', 0);
    session_cache_limiter(false);

    header("Cache-Control: public");
    header("Content-Description: File Transfer");
    header('Content-Type: ' . $mimetype);
    header('Content-Transfer-Encoding: binary');
    header('Content-disposition: attachment; filename="'. $filename .'"');
    // or your variant
    // header("Content-Disposition: attachment; filename=" . md5(time()));

    header("Content-Length: $size");

    $start = 0;
    $end   = $size - 1;
    $chunk = 8 * 1024;

    $requested  = (float)$end - (float)$start + 1;

    while (! $error) {
        if ($chunk >= $requested) {
            $chunk = (integer)$requested;
        }

        set_time_limit(0);

        while (! feof($handle) && (connection_status() === 0)) {
            if (! $buffer = @fread($handle, $chunk)) {
                $error = true;
                break 2;
            }

            print($buffer);
            flush();
        }

        @flock($handle, LOCK_UN);
        @fclose($handle);

        ini_set('max_execution_time', $old_max_execution_time);
        session_cache_limiter($old_cache_limiter);
        break;
    }

    if ($error) {
        // 500 - Internal server error
        exit;
    }
} else {
    // Can't open file
    exit;
}

Upvotes: 1

Volodymyr Chumak
Volodymyr Chumak

Reputation: 766

Maybe problem in script time execution. Try to set ini_set('max_execution_time', 0); Also try to read and send file by chunks.

Upvotes: 0

Related Questions