summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobin McCorkell <rmccorkell@owncloud.com>2015-08-17 13:27:47 +0100
committerRobin McCorkell <rmccorkell@owncloud.com>2015-08-17 13:27:47 +0100
commit675d852c7d141f2dd83c32bb82a8c894838d6907 (patch)
tree9bc33fcbdf82dd2cb7df3f89c6f9fc9dc5f53870
parent47e05c97a2302804fa8f0a28d3198ba686c2e656 (diff)
parentaac84f732dd192a5f13fe4b31ad0a384d6aa890b (diff)
downloadnextcloud-server-675d852c7d141f2dd83c32bb82a8c894838d6907.tar.gz
nextcloud-server-675d852c7d141f2dd83c32bb82a8c894838d6907.zip
Merge pull request #17182 from owncloud/user_ini_upload_size
Update .user.ini when setting upload size limit
-rw-r--r--apps/files/admin.php3
-rw-r--r--apps/files/templates/admin.php2
-rw-r--r--lib/private/files.php91
-rw-r--r--tests/data/setUploadLimit/htaccess60
-rw-r--r--tests/data/setUploadLimit/user.ini7
-rw-r--r--tests/lib/files.php135
6 files changed, 263 insertions, 35 deletions
diff --git a/apps/files/admin.php b/apps/files/admin.php
index 70f537d0db9..349c27ff742 100644
--- a/apps/files/admin.php
+++ b/apps/files/admin.php
@@ -42,9 +42,10 @@ if($_POST && OC_Util::isCallRegistered()) {
}
$htaccessWritable=is_writable(OC::$SERVERROOT.'/.htaccess');
+$userIniWritable=is_writable(OC::$SERVERROOT.'/.user.ini');
$tmpl = new OCP\Template( 'files', 'admin' );
-$tmpl->assign( 'uploadChangable', $htaccessWorking and $htaccessWritable );
+$tmpl->assign( 'uploadChangable', ($htaccessWorking and $htaccessWritable) or $userIniWritable );
$tmpl->assign( 'uploadMaxFilesize', $maxUploadFilesize);
// max possible makes only sense on a 32 bit system
$tmpl->assign( 'displayMaxPossibleUploadSize', PHP_INT_SIZE===4);
diff --git a/apps/files/templates/admin.php b/apps/files/templates/admin.php
index adf756a12be..822fc779bd3 100644
--- a/apps/files/templates/admin.php
+++ b/apps/files/templates/admin.php
@@ -10,6 +10,8 @@
<br/>
<input type="hidden" value="<?php p($_['requesttoken']); ?>" name="requesttoken" />
<?php if($_['uploadChangable']): ?>
+ <?php p($l->t('With PHP-FPM this value may take up to 5 minutes to take effect after saving.')); ?>
+ <br/>
<input type="submit" name="submitFilesAdminSettings" id="submitFilesAdminSettings"
value="<?php p($l->t( 'Save' )); ?>"/>
<?php else: ?>
diff --git a/lib/private/files.php b/lib/private/files.php
index b61d09d8a0c..6268bf8a129 100644
--- a/lib/private/files.php
+++ b/lib/private/files.php
@@ -21,6 +21,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Valerio Ponte <valerio.ponte@gmail.com>
* @author Vincent Petry <pvince81@owncloud.com>
+ * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
@@ -268,58 +269,80 @@ class OC_Files {
* set the maximum upload size limit for apache hosts using .htaccess
*
* @param int $size file size in bytes
+ * @param array $files override '.htaccess' and '.user.ini' locations
* @return bool false on failure, size on success
*/
- static function setUploadLimit($size) {
+ public static function setUploadLimit($size, $files = []) {
//don't allow user to break his config
- if ($size > PHP_INT_MAX) {
- //max size is always 1 byte lower than computerFileSize returns
- if ($size > PHP_INT_MAX + 1)
- return false;
- $size -= 1;
- }
+ $size = intval($size);
if ($size < self::UPLOAD_MIN_LIMIT_BYTES) {
return false;
}
$size = OC_Helper::phpFileSize($size);
- //don't allow user to break his config -- broken or malicious size input
- if (intval($size) === 0) {
- return false;
- }
-
- //suppress errors in case we don't have permissions for
- $htaccess = @file_get_contents(OC::$SERVERROOT . '/.htaccess');
- if (!$htaccess) {
- return false;
- }
-
$phpValueKeys = array(
'upload_max_filesize',
'post_max_size'
);
- foreach ($phpValueKeys as $key) {
- $pattern = '/php_value ' . $key . ' (\S)*/';
- $setting = 'php_value ' . $key . ' ' . $size;
- $hasReplaced = 0;
- $content = preg_replace($pattern, $setting, $htaccess, 1, $hasReplaced);
- if ($content !== null) {
- $htaccess = $content;
+ // default locations if not overridden by $files
+ $files = array_merge([
+ '.htaccess' => OC::$SERVERROOT . '/.htaccess',
+ '.user.ini' => OC::$SERVERROOT . '/.user.ini'
+ ], $files);
+
+ $updateFiles = [
+ $files['.htaccess'] => [
+ 'pattern' => '/php_value %1$s (\S)*/',
+ 'setting' => 'php_value %1$s %2$s'
+ ],
+ $files['.user.ini'] => [
+ 'pattern' => '/%1$s=(\S)*/',
+ 'setting' => '%1$s=%2$s'
+ ]
+ ];
+
+ $success = true;
+
+ foreach ($updateFiles as $filename => $patternMap) {
+ // suppress warnings from fopen()
+ $handle = @fopen($filename, 'r+');
+ if (!$handle) {
+ \OCP\Util::writeLog('files',
+ 'Can\'t write upload limit to ' . $filename . '. Please check the file permissions',
+ \OCP\Util::WARN);
+ $success = false;
+ continue; // try to update as many files as possible
}
- if ($hasReplaced === 0) {
- $htaccess .= "\n" . $setting;
+
+ $content = '';
+ while (!feof($handle)) {
+ $content .= fread($handle, 1000);
}
+
+ foreach ($phpValueKeys as $key) {
+ $pattern = vsprintf($patternMap['pattern'], [$key]);
+ $setting = vsprintf($patternMap['setting'], [$key, $size]);
+ $hasReplaced = 0;
+ $newContent = preg_replace($pattern, $setting, $content, 1, $hasReplaced);
+ if ($newContent !== null) {
+ $content = $newContent;
+ }
+ if ($hasReplaced === 0) {
+ $content .= "\n" . $setting;
+ }
+ }
+
+ // write file back
+ ftruncate($handle, 0);
+ rewind($handle);
+ fwrite($handle, $content);
+
+ fclose($handle);
}
- //check for write permissions
- if (is_writable(OC::$SERVERROOT . '/.htaccess')) {
- file_put_contents(OC::$SERVERROOT . '/.htaccess', $htaccess);
+ if ($success) {
return OC_Helper::computerFileSize($size);
- } else {
- \OCP\Util::writeLog('files',
- 'Can\'t write upload limit to ' . OC::$SERVERROOT . '/.htaccess. Please check the file permissions',
- \OCP\Util::WARN);
}
return false;
}
diff --git a/tests/data/setUploadLimit/htaccess b/tests/data/setUploadLimit/htaccess
new file mode 100644
index 00000000000..65957a29838
--- /dev/null
+++ b/tests/data/setUploadLimit/htaccess
@@ -0,0 +1,60 @@
+# Version: 8.2.0
+<IfModule mod_headers.c>
+ <IfModule mod_fcgid.c>
+ <IfModule mod_setenvif.c>
+ SetEnvIfNoCase ^Authorization$ "(.+)" XAUTHORIZATION=$1
+ RequestHeader set XAuthorization %{XAUTHORIZATION}e env=XAUTHORIZATION
+ </IfModule>
+ </IfModule>
+
+ <IfModule mod_env.c>
+ # Add security and privacy related headers
+ Header set X-Content-Type-Options "nosniff"
+ Header set X-XSS-Protection "1; mode=block"
+ Header set X-Robots-Tag "none"
+ Header set X-Frame-Options "SAMEORIGIN"
+ SetEnv modHeadersAvailable true
+ </IfModule>
+
+ # Add cache control for CSS and JS files
+ <FilesMatch "\.(css|js)$">
+ Header set Cache-Control "max-age=7200, public"
+ </FilesMatch>
+</IfModule>
+<IfModule mod_php5.c>
+php_value upload_max_filesize 513M
+php_value post_max_size 513M
+php_value memory_limit 512M
+php_value mbstring.func_overload 0
+php_value always_populate_raw_post_data -1
+php_value default_charset 'UTF-8'
+php_value output_buffering off
+<IfModule mod_env.c>
+ SetEnv htaccessWorking true
+</IfModule>
+</IfModule>
+<IfModule mod_rewrite.c>
+RewriteEngine on
+RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
+RewriteRule ^\.well-known/host-meta /public.php?service=host-meta [QSA,L]
+RewriteRule ^\.well-known/host-meta\.json /public.php?service=host-meta-json [QSA,L]
+RewriteRule ^\.well-known/carddav /remote.php/carddav/ [R=301,L]
+RewriteRule ^\.well-known/caldav /remote.php/caldav/ [R=301,L]
+RewriteRule ^apps/calendar/caldav\.php remote.php/caldav/ [QSA,L]
+RewriteRule ^apps/contacts/carddav\.php remote.php/carddav/ [QSA,L]
+RewriteRule ^remote/(.*) remote.php [QSA,L]
+RewriteRule ^(build|tests|config|lib|3rdparty|templates)/.* - [R=404,L]
+RewriteRule ^(\.|autotest|occ|issue|indie|db_|console).* - [R=404,L]
+</IfModule>
+<IfModule mod_mime.c>
+AddType image/svg+xml svg svgz
+AddEncoding gzip svgz
+</IfModule>
+<IfModule mod_dir.c>
+DirectoryIndex index.php index.html
+</IfModule>
+AddDefaultCharset utf-8
+Options -Indexes
+<IfModule pagespeed_module>
+ ModPagespeed Off
+</IfModule>
diff --git a/tests/data/setUploadLimit/user.ini b/tests/data/setUploadLimit/user.ini
new file mode 100644
index 00000000000..c5996e8d47e
--- /dev/null
+++ b/tests/data/setUploadLimit/user.ini
@@ -0,0 +1,7 @@
+upload_max_filesize=513M
+post_max_size=513M
+memory_limit=512M
+mbstring.func_overload=0
+always_populate_raw_post_data=-1
+default_charset='UTF-8'
+output_buffering=off
diff --git a/tests/lib/files.php b/tests/lib/files.php
new file mode 100644
index 00000000000..6808b3e9f64
--- /dev/null
+++ b/tests/lib/files.php
@@ -0,0 +1,135 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Test;
+
+class Files extends \Test\TestCase {
+
+ const UPLOAD_LIMIT_DEFAULT_STR = '513M';
+ const UPLOAD_LIMIT_SETTING_STR = '2M';
+ const UPLOAD_LIMIT_SETTING_BYTES = 2097152;
+
+ /** @var array $tmpDirs */
+ private $tmpDirs = [];
+
+ /**
+ * @return array
+ */
+ private function getUploadLimitTestFiles() {
+ $dir = \OC::$server->getTempManager()->getTemporaryFolder();
+ $this->tmpDirs[] = $dir;
+ $result = [
+ '.htaccess' => $dir . '/htaccess',
+ '.user.ini' => $dir . '/user.ini'
+ ];
+ copy(\OC::$SERVERROOT . '/tests/data/setUploadLimit/htaccess', $result['.htaccess']);
+ copy(\OC::$SERVERROOT . '/tests/data/setUploadLimit/user.ini', $result['.user.ini']);
+ return $result;
+ }
+
+ protected function tearDown() {
+ foreach ($this->tmpDirs as $dir) {
+ \OC_Helper::rmdirr($dir);
+ }
+ parent::tearDown();
+ }
+
+ public function testSetUploadLimitSizeSanity() {
+ $this->assertFalse(\OC_Files::setUploadLimit(PHP_INT_MAX + 10));
+ $this->assertFalse(\OC_Files::setUploadLimit(\OC_Files::UPLOAD_MIN_LIMIT_BYTES - 10));
+ $this->assertFalse(\OC_Files::setUploadLimit('foobar'));
+ }
+
+ public function setUploadLimitWriteProvider() {
+ return [
+ [
+ // both files writable
+ true, true,
+ self::UPLOAD_LIMIT_SETTING_BYTES, self::UPLOAD_LIMIT_SETTING_BYTES,
+ self::UPLOAD_LIMIT_SETTING_STR, self::UPLOAD_LIMIT_SETTING_STR
+ ],
+ [
+ // neither file writable
+ false, false,
+ self::UPLOAD_LIMIT_SETTING_BYTES, false,
+ self::UPLOAD_LIMIT_DEFAULT_STR, self::UPLOAD_LIMIT_DEFAULT_STR
+ ],
+ [
+ // only .htaccess writable
+ true, false,
+ self::UPLOAD_LIMIT_SETTING_BYTES, false,
+ self::UPLOAD_LIMIT_SETTING_STR, self::UPLOAD_LIMIT_DEFAULT_STR
+ ],
+ [
+ // only .user.ini writable
+ false, true,
+ self::UPLOAD_LIMIT_SETTING_BYTES, false,
+ self::UPLOAD_LIMIT_DEFAULT_STR, self::UPLOAD_LIMIT_SETTING_STR
+ ],
+ [
+ // test rounding of values
+ true, true,
+ self::UPLOAD_LIMIT_SETTING_BYTES + 20, self::UPLOAD_LIMIT_SETTING_BYTES,
+ self::UPLOAD_LIMIT_SETTING_STR, self::UPLOAD_LIMIT_SETTING_STR
+ ]
+ ];
+ }
+
+ /**
+ * @dataProvider setUploadLimitWriteProvider
+ */
+ public function testSetUploadLimitWrite(
+ $htaccessWritable, $userIniWritable,
+ $setSize, $expectedSize,
+ $htaccessStr, $userIniStr
+ ) {
+ $files = $this->getUploadLimitTestFiles();
+ chmod($files['.htaccess'], ($htaccessWritable ? 0644 : 0444));
+ chmod($files['.user.ini'], ($userIniWritable ? 0644 : 0444));
+
+ $htaccessSize = filesize($files['.htaccess']);
+ $userIniSize = filesize($files['.user.ini']);
+ $htaccessSizeMod = 2*(strlen($htaccessStr) - strlen(self::UPLOAD_LIMIT_DEFAULT_STR));
+ $userIniSizeMod = 2*(strlen($userIniStr) - strlen(self::UPLOAD_LIMIT_DEFAULT_STR));
+
+ $this->assertEquals($expectedSize, \OC_Files::setUploadLimit($setSize, $files));
+
+ // check file contents
+ $htaccess = file_get_contents($files['.htaccess']);
+ $this->assertEquals(1,
+ preg_match('/php_value upload_max_filesize '.$htaccessStr.'/', $htaccess)
+ );
+ $this->assertEquals(1,
+ preg_match('/php_value post_max_size '.$htaccessStr.'/', $htaccess)
+ );
+ $this->assertEquals($htaccessSize + $htaccessSizeMod, filesize($files['.htaccess']));
+
+ $userIni = file_get_contents($files['.user.ini']);
+ $this->assertEquals(1,
+ preg_match('/upload_max_filesize='.$userIniStr.'/', $userIni)
+ );
+ $this->assertEquals(1,
+ preg_match('/post_max_size='.$userIniStr.'/', $userIni)
+ );
+ $this->assertEquals($userIniSize + $userIniSizeMod, filesize($files['.user.ini']));
+ }
+}