From 66aa9b4e27deac3037ac382cc845cd26f05c682f Mon Sep 17 00:00:00 2001 From: Nicolai Ehemann Date: Fri, 17 Jan 2014 14:26:17 +0100 Subject: [PATCH 1/3] lib/files.php: make use of === instead of == --- lib/private/files.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/private/files.php b/lib/private/files.php index e6c81d58bd..d4a8112d23 100644 --- a/lib/private/files.php +++ b/lib/private/files.php @@ -51,7 +51,7 @@ class OC_Files { $xsendfile = true; } - if (is_array($files) && count($files) == 1) { + if (is_array($files) && count($files) === 1) { $files = $files[0]; } @@ -178,7 +178,7 @@ class OC_Files { if (isset($_SERVER['HTTP_RANGE']) && preg_match("/^bytes=([0-9]+)-([0-9]*)$/", $_SERVER['HTTP_RANGE'], $range)) { $filelength = filesize($filename); - if ($range[2] == "") { + if ($range[2] === "") { $range[2] = $filelength - 1; } header("Content-Range: bytes $range[1]-$range[2]/" . $filelength); @@ -280,7 +280,7 @@ class OC_Files { } //don't allow user to break his config -- broken or malicious size input - if (intval($size) == 0) { + if (intval($size) === 0) { return false; } @@ -302,7 +302,7 @@ class OC_Files { if ($content !== null) { $htaccess = $content; } - if ($hasReplaced == 0) { + if ($hasReplaced === 0) { $htaccess .= "\n" . $setting; } } From 791772abea631c503d95e21f584a66b47dc042f4 Mon Sep 17 00:00:00 2001 From: Nicolai Ehemann Date: Thu, 16 Jan 2014 17:21:19 +0100 Subject: [PATCH 2/3] refactored/cleaned up lib/files.php cleaned up get() logic fixed get() to only send headers if requested (xsendfile could get in the way) do no longer readfile() when already using mod_xsendfile or similar --- lib/private/files.php | 161 ++++++++++++++++++++++-------------------- 1 file changed, 84 insertions(+), 77 deletions(-) diff --git a/lib/private/files.php b/lib/private/files.php index d4a8112d23..105c839177 100644 --- a/lib/private/files.php +++ b/lib/private/files.php @@ -21,6 +21,12 @@ * */ +class GET_TYPE { + const FILE = 1; + const ZIP_FILES = 2; + const ZIP_DIR = 3; +} + /** * Class for fileserver access * @@ -36,6 +42,21 @@ class OC_Files { return \OC\Files\Filesystem::getDirectoryContent($path); } + private static function sendHeaders($filename, $name, $zip = false) { + OC_Response::setContentDispositionHeader($name, 'attachment'); + header('Content-Transfer-Encoding: binary'); + OC_Response::disableCaching(); + if ($zip) { + header('Content-Type: application/zip'); + } else { + $filesize = \OC\Files\Filesystem::filesize($filename); + header('Content-Type: '.\OC\Files\Filesystem::getMimeType($filename)); + if ($filesize > -1) { + header("Content-Length: ".$filesize); + } + } + } + /** * return the content of a file or return a zip file containing multiple files * @@ -56,87 +77,43 @@ class OC_Files { } if (is_array($files)) { - self::validateZipDownload($dir, $files); - $executionTime = intval(ini_get('max_execution_time')); - set_time_limit(0); - $zip = new ZipArchive(); - $filename = OC_Helper::tmpFile('.zip'); - if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)!==true) { - $l = OC_L10N::get('lib'); - throw new Exception($l->t('cannot open "%s"', array($filename))); - } - foreach ($files as $file) { - $file = $dir . '/' . $file; - if (\OC\Files\Filesystem::is_file($file)) { - $tmpFile = \OC\Files\Filesystem::toTmpFile($file); - self::$tmpFiles[] = $tmpFile; - $zip->addFile($tmpFile, basename($file)); - } elseif (\OC\Files\Filesystem::is_dir($file)) { - self::zipAddDir($file, $zip); - } - } - $zip->close(); - if ($xsendfile) { - $filename = OC_Helper::moveToNoClean($filename); - } + $get_type = GET_TYPE::ZIP_FILES; $basename = basename($dir); if ($basename) { $name = $basename . '.zip'; } else { $name = 'owncloud.zip'; } - - set_time_limit($executionTime); - } elseif (\OC\Files\Filesystem::is_dir($dir . '/' . $files)) { + $filename = $dir . '/' . $name; + } else { + $filename = $dir . '/' . $files; + if (\OC\Files\Filesystem::is_dir($dir . '/' . $files)) { + $get_type = GET_TYPE::ZIP_DIR; + $name = $files . '.zip'; + } else { + $get_type = GET_TYPE::FILE; + $name = $files; + } + } + + if ($get_type === GET_TYPE::FILE) { + $zip = false; + if ($xsendfile && OC_App::isEnabled('files_encryption')) { + $xsendfile = false; + } + } else { self::validateZipDownload($dir, $files); - $executionTime = intval(ini_get('max_execution_time')); - set_time_limit(0); $zip = new ZipArchive(); $filename = OC_Helper::tmpFile('.zip'); if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)!==true) { $l = OC_L10N::get('lib'); throw new Exception($l->t('cannot open "%s"', array($filename))); } - $file = $dir . '/' . $files; - self::zipAddDir($file, $zip); - $zip->close(); - if ($xsendfile) { - $filename = OC_Helper::moveToNoClean($filename); - } - $name = $files . '.zip'; - set_time_limit($executionTime); - } else { - $zip = false; - $filename = $dir . '/' . $files; - $name = $files; - if ($xsendfile && OC_App::isEnabled('files_encryption')) { - $xsendfile = false; - } } OC_Util::obEnd(); if ($zip or \OC\Files\Filesystem::isReadable($filename)) { - OC_Response::setContentDispositionHeader($name, 'attachment'); - header('Content-Transfer-Encoding: binary'); - OC_Response::disableCaching(); - if ($zip) { - ini_set('zlib.output_compression', 'off'); - header('Content-Type: application/zip'); - header('Content-Length: ' . filesize($filename)); - self::addSendfileHeader($filename); - }else{ - $filesize = \OC\Files\Filesystem::filesize($filename); - header('Content-Type: '.\OC\Files\Filesystem::getMimeType($filename)); - if ($filesize > -1) { - header("Content-Length: ".$filesize); - } - if ($xsendfile) { - list($storage) = \OC\Files\Filesystem::resolvePath(\OC\Files\Filesystem::getView()->getAbsolutePath($filename)); - if ($storage instanceof \OC\Files\Storage\Local) { - self::addSendfileHeader(\OC\Files\Filesystem::getLocalFile($filename)); - } - } - } - } elseif ($zip or !\OC\Files\Filesystem::file_exists($filename)) { + self::sendHeaders($filename, $name, $zip); + } elseif (!\OC\Files\Filesystem::file_exists($filename)) { header("HTTP/1.0 404 Not Found"); $tmpl = new OC_Template('', '404', 'guest'); $tmpl->assign('file', $name); @@ -149,19 +126,49 @@ class OC_Files { return ; } if ($zip) { - $handle = fopen($filename, 'r'); - if ($handle) { - $chunkSize = 8 * 1024; // 1 MB chunks - while (!feof($handle)) { - echo fread($handle, $chunkSize); - flush(); + $executionTime = intval(ini_get('max_execution_time')); + set_time_limit(0); + if ($get_type === GET_TYPE::ZIP_FILES) { + foreach ($files as $file) { + $file = $dir . '/' . $file; + if (\OC\Files\Filesystem::is_file($file)) { + $tmpFile = \OC\Files\Filesystem::toTmpFile($file); + self::$tmpFiles[] = $tmpFile; + $zip->addFile($tmpFile, basename($file)); + } elseif (\OC\Files\Filesystem::is_dir($file)) { + self::zipAddDir($file, $zip); + } + } + } elseif ($get_type === GET_TYPE::ZIP_DIR) { + $file = $dir . '/' . $files; + self::zipAddDir($file, $zip); + } + $zip->close(); + if ($xsendfile) { + $filename = OC_Helper::moveToNoClean($filename); + self::addSendfileHeader($filename); + } else { + $handle = fopen($filename, 'r'); + if ($handle) { + $chunkSize = 8 * 1024; // 1 MB chunks + while (!feof($handle)) { + echo fread($handle, $chunkSize); + flush(); + } } } - if (!$xsendfile) { - unlink($filename); + set_time_limit($executionTime); + } else { + if ($xsendfile) { + list($storage) = \OC\Files\Filesystem::resolvePath($filename); + if ($storage instanceof \OC\Files\Storage\Local) { + self::addSendfileHeader(\OC\Files\Filesystem::getLocalFile($filename)); + } else { + \OC\Files\Filesystem::readfile($filename); + } + } else { + \OC\Files\Filesystem::readfile($filename); } - }else{ - \OC\Files\Filesystem::readfile($filename); } foreach (self::$tmpFiles as $tmpFile) { if (file_exists($tmpFile) and is_file($tmpFile)) { @@ -175,7 +182,7 @@ class OC_Files { header("X-Sendfile: " . $filename); } if (isset($_SERVER['MOD_X_SENDFILE2_ENABLED'])) { - if (isset($_SERVER['HTTP_RANGE']) && + if (isset($_SERVER['HTTP_RANGE']) && preg_match("/^bytes=([0-9]+)-([0-9]*)$/", $_SERVER['HTTP_RANGE'], $range)) { $filelength = filesize($filename); if ($range[2] === "") { @@ -188,7 +195,7 @@ class OC_Files { header("X-Sendfile: " . $filename); } } - + if (isset($_SERVER['MOD_X_ACCEL_REDIRECT_ENABLED'])) { header("X-Accel-Redirect: " . $filename); } From 99ad4e80007bca5062709e16652b953ad9e73dc7 Mon Sep 17 00:00:00 2001 From: Nicolai Ehemann Date: Wed, 22 Jan 2014 12:49:52 +0100 Subject: [PATCH 3/3] switched zip file creation to ZipStreamer to create zip files directly in memory --- lib/private/files.php | 42 +++++++++--------------------------------- 1 file changed, 9 insertions(+), 33 deletions(-) diff --git a/lib/private/files.php b/lib/private/files.php index 105c839177..5370f9e167 100644 --- a/lib/private/files.php +++ b/lib/private/files.php @@ -20,6 +20,7 @@ * License along with this library. If not, see . * */ +require_once( 'ZipStreamer/ZipStreamer.php' ); class GET_TYPE { const FILE = 1; @@ -32,8 +33,6 @@ class GET_TYPE { * */ class OC_Files { - static $tmpFiles = array(); - static public function getFileInfo($path, $includeMountPoints = true){ return \OC\Files\Filesystem::getFileInfo($path, $includeMountPoints); } @@ -103,12 +102,7 @@ class OC_Files { } } else { self::validateZipDownload($dir, $files); - $zip = new ZipArchive(); - $filename = OC_Helper::tmpFile('.zip'); - if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)!==true) { - $l = OC_L10N::get('lib'); - throw new Exception($l->t('cannot open "%s"', array($filename))); - } + $zip = new ZipStreamer(false); } OC_Util::obEnd(); if ($zip or \OC\Files\Filesystem::isReadable($filename)) { @@ -132,9 +126,9 @@ class OC_Files { foreach ($files as $file) { $file = $dir . '/' . $file; if (\OC\Files\Filesystem::is_file($file)) { - $tmpFile = \OC\Files\Filesystem::toTmpFile($file); - self::$tmpFiles[] = $tmpFile; - $zip->addFile($tmpFile, basename($file)); + $fh = \OC\Files\Filesystem::fopen($file, 'r'); + $zip->addFileFromStream($fh, basename($file)); + fclose($fh); } elseif (\OC\Files\Filesystem::is_dir($file)) { self::zipAddDir($file, $zip); } @@ -143,20 +137,7 @@ class OC_Files { $file = $dir . '/' . $files; self::zipAddDir($file, $zip); } - $zip->close(); - if ($xsendfile) { - $filename = OC_Helper::moveToNoClean($filename); - self::addSendfileHeader($filename); - } else { - $handle = fopen($filename, 'r'); - if ($handle) { - $chunkSize = 8 * 1024; // 1 MB chunks - while (!feof($handle)) { - echo fread($handle, $chunkSize); - flush(); - } - } - } + $zip->finalize(); set_time_limit($executionTime); } else { if ($xsendfile) { @@ -170,11 +151,6 @@ class OC_Files { \OC\Files\Filesystem::readfile($filename); } } - foreach (self::$tmpFiles as $tmpFile) { - if (file_exists($tmpFile) and is_file($tmpFile)) { - unlink($tmpFile); - } - } } private static function addSendfileHeader($filename) { @@ -210,9 +186,9 @@ class OC_Files { $filename=$file['name']; $file=$dir.'/'.$filename; if(\OC\Files\Filesystem::is_file($file)) { - $tmpFile=\OC\Files\Filesystem::toTmpFile($file); - OC_Files::$tmpFiles[]=$tmpFile; - $zip->addFile($tmpFile, $internalDir.$filename); + $fh = \OC\Files\Filesystem::fopen($file, 'r'); + $zip->addFileFromStream($fh, $internalDir.$filename); + fclose($fh); }elseif(\OC\Files\Filesystem::is_dir($file)) { self::zipAddDir($file, $zip, $internalDir); }