summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--admin_site_upgrade.php17
-rw-r--r--library/WT/File.php34
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;
}
}