diff options
| -rw-r--r-- | admin_site_upgrade.php | 17 | ||||
| -rw-r--r-- | library/WT/File.php | 34 |
2 files changed, 35 insertions, 16 deletions
diff --git a/admin_site_upgrade.php b/admin_site_upgrade.php index 178d6411b1..55d7181414 100644 --- a/admin_site_upgrade.php +++ b/admin_site_upgrade.php @@ -298,15 +298,18 @@ echo '</li>'; echo '<li>', /* I18N: The system is about to [...]; %s is a URL. */ WT_I18N::translate('Download %s…', $download_url_html); +$zip_file = WT_DATA_DIR . basename($download_url); +$zip_dir = WT_DATA_DIR . basename($download_url, '.zip'); +$zip_stream = fopen($zip_file, 'w'); $start_time = microtime(true); -$zip_data = WT_File::fetchUrl($download_url); -$end_time = microtime(true); -$zip_file = WT_DATA_DIR . basename($download_url); -$zip_dir = WT_DATA_DIR . basename($download_url, '.zip'); -echo '<br>', /* I18N: %1$s is a number of KB, %2$s is a (fractional) number of seconds */ WT_I18N::translate('%1$sKB were downloaded in %2$s seconds.', WT_I18N::number(strlen($zip_data) / 1024), WT_I18N::number($end_time - $start_time, 2)); -if ($zip_data) { +WT_File::fetchUrl($download_url, $zip_stream); +$end_time = microtime(true); +$zip_size = filesize($zip_file); +fclose($zip_stream); + +echo '<br>', /* I18N: %1$s is a number of KB, %2$s is a (fractional) number of seconds */ WT_I18N::translate('%1$sKB were downloaded in %2$s seconds.', WT_I18N::number($zip_size / 1024), WT_I18N::number($end_time - $start_time, 2)); +if ($zip_size) { echo $icon_success; - file_put_contents($zip_file, $zip_data); } else { echo $icon_failure; } diff --git a/library/WT/File.php b/library/WT/File.php index 3a1e68bb21..a0af30c373 100644 --- a/library/WT/File.php +++ b/library/WT/File.php @@ -28,9 +28,12 @@ class WT_File { // Fetch a remote file // Note that fopen() and file_get_contents() are often unvailable, as they // can easily be exploited by application bugs, and are therefore disabled. + // Hence we use fsockopen(). + // To allow arbitrarily large downloads with small memory limits, we either + // write output to a stream or return it. ////////////////////////////////////////////////////////////////////////////// - public static function fetchUrl($url, $timeout=3) { + public static function fetchUrl($url, $stream=null) { $host = parse_url($url, PHP_URL_HOST); $port = parse_url($url, PHP_URL_PORT); $path = parse_url($url, PHP_URL_PATH); @@ -41,25 +44,38 @@ class WT_File { $scheme = $port == 443 ? 'ssl://' : ''; - $fp = @fsockopen($scheme . $host, $port, $errno, $errstr, $timeout); + $fp = @fsockopen($scheme . $host, $port, $errno, $errstr, 5); if (!$fp) { return null; } fputs($fp, "GET $path HTTP/1.0\r\nHost: $host\r\nConnection: Close\r\n\r\n"); - $response = ''; - while ($data = fread($fp, 8192)) { - $response .= $data; - } - fclose($fp); + // The first part of the response include the HTTP headers + $response = fread($fp, 65536); // The file has moved? Follow it. if (preg_match('/^HTTP\/1.[01] 30[23].+\nLocation: ([^\r\n]+)/s', $response, $match)) { - return WT_File::fetchUrl($match[1]); + fclose($fp); + return WT_File::fetchUrl($match[1], $stream); } else { // The response includes headers, a blank line, then the content - return substr($response, strpos($response, "\r\n\r\n") + 4); + $response = substr($response, strpos($response, "\r\n\r\n") + 4); + } + + if ($stream) { + fwrite($stream, $response); + while ($tmp = fread($fp, 8192)) { + fwrite($stream, $tmp); + } + fclose($fp); + return null; + } else { + while ($tmp = fread($fp, 8192)) { + $response .= $tmp; + } + fclose($fp); + return $response; } } |
