Merge pull request #17182 from owncloud/user_ini_upload_size
Update .user.ini when setting upload size limit
This commit is contained in:
commit
675d852c7d
6 changed files with 263 additions and 35 deletions
|
@ -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);
|
||||
|
|
|
@ -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: ?>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
60
tests/data/setUploadLimit/htaccess
Normal file
60
tests/data/setUploadLimit/htaccess
Normal file
|
@ -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>
|
7
tests/data/setUploadLimit/user.ini
Normal file
7
tests/data/setUploadLimit/user.ini
Normal file
|
@ -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
|
135
tests/lib/files.php
Normal file
135
tests/lib/files.php
Normal file
|
@ -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']));
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue