diff options
author | Stefan Giehl <stefan@matomo.org> | 2021-01-01 03:30:49 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-01 03:30:49 +0300 |
commit | 339b5cd33c5f47a2a67730b3bfb9eed210219585 (patch) | |
tree | 27cfd92572dc24465238e66bfb59e9dee0cd0e0b | |
parent | 52c573a0572f079c99bfa3331b8ef4164e199281 (diff) |
Don't accept files that are bigger than the upload limit when uploading plugins (#16849)
* Don't accept files that are bigger than the upload limit when uploading plugins
* improve / simplify code
* adds some tests
-rw-r--r-- | core/SettingsServer.php | 60 | ||||
-rw-r--r-- | plugins/CorePluginsAdmin/Controller.php | 2 | ||||
-rw-r--r-- | plugins/CorePluginsAdmin/CorePluginsAdmin.php | 1 | ||||
-rw-r--r-- | plugins/CorePluginsAdmin/angularjs/plugins/plugin-upload.directive.js | 3 | ||||
-rw-r--r-- | plugins/CorePluginsAdmin/lang/en.json | 1 | ||||
-rw-r--r-- | plugins/Marketplace/Controller.php | 2 | ||||
-rw-r--r-- | plugins/Marketplace/templates/uploadPluginDialog.twig | 2 | ||||
-rw-r--r-- | tests/PHPUnit/Unit/SettingsServerTest.php | 47 |
8 files changed, 102 insertions, 16 deletions
diff --git a/core/SettingsServer.php b/core/SettingsServer.php index 6846502ac4..3f61670fd6 100644 --- a/core/SettingsServer.php +++ b/core/SettingsServer.php @@ -196,26 +196,12 @@ class SettingsServer * Prior to PHP 5.2.1, or on Windows, --enable-memory-limit is not a * compile-time default, so ini_get('memory_limit') may return false. * - * @see http://www.php.net/manual/en/faq.using.php#faq.using.shorthandbytes * @return int|bool memory limit in megabytes, or false if there is no limit */ public static function getMemoryLimitValue() { if (($memory = ini_get('memory_limit')) > 0) { - // handle shorthand byte options (case-insensitive) - $shorthandByteOption = substr($memory, -1); - switch ($shorthandByteOption) { - case 'G': - case 'g': - return substr($memory, 0, -1) * 1024; - case 'M': - case 'm': - return substr($memory, 0, -1); - case 'K': - case 'k': - return substr($memory, 0, -1) / 1024; - } - return $memory / 1048576; + return self::getMegaBytesFromShorthandByte($memory); } // no memory limit @@ -223,6 +209,50 @@ class SettingsServer } /** + * Get php post_max_size (in Megabytes) + * + * @return int|bool max upload size in megabytes, or false if there is no limit + */ + public static function getPostMaxUploadSize() + { + if (($maxPostSize = ini_get('post_max_size')) > 0) { + return self::getMegaBytesFromShorthandByte($maxPostSize); + } + + // no max upload size + return false; + } + + /** + * @see http://www.php.net/manual/en/faq.using.php#faq.using.shorthandbytes + * @param $value + * @return false|float|int + */ + private static function getMegaBytesFromShorthandByte($value) + { + $value = str_replace(' ', '', $value); + + $shorthandByteOption = substr($value, -1); + switch ($shorthandByteOption) { + case 'G': + case 'g': + return substr($value, 0, -1) * 1024; + case 'M': + case 'm': + return substr($value, 0, -1); + case 'K': + case 'k': + return substr($value, 0, -1) / 1024; + } + + if (is_numeric($value)) { + return (int) $value / 1048576; + } + + return false; + } + + /** * Set maximum script execution time. * * @param int $executionTime max execution time in seconds (0 = no limit) diff --git a/plugins/CorePluginsAdmin/Controller.php b/plugins/CorePluginsAdmin/Controller.php index da005443f2..df3f1de171 100644 --- a/plugins/CorePluginsAdmin/Controller.php +++ b/plugins/CorePluginsAdmin/Controller.php @@ -28,6 +28,7 @@ use Piwik\Plugins\Marketplace\Controller as MarketplaceController; use Piwik\Plugins\Marketplace\Plugins; use Piwik\Settings\Storage\Backend\PluginSettingsTable; use Piwik\SettingsPiwik; +use Piwik\SettingsServer; use Piwik\Translation\Translator; use Piwik\Url; use Piwik\Version; @@ -236,6 +237,7 @@ class Controller extends Plugin\ControllerAdmin } $view->isPluginUploadEnabled = CorePluginsAdmin::isPluginUploadEnabled(); + $view->uploadLimit = SettingsServer::getPostMaxUploadSize(); $view->installNonce = Nonce::getNonce(MarketplaceController::INSTALL_NONCE); return $view; diff --git a/plugins/CorePluginsAdmin/CorePluginsAdmin.php b/plugins/CorePluginsAdmin/CorePluginsAdmin.php index c8a72cf488..aeef54b2db 100644 --- a/plugins/CorePluginsAdmin/CorePluginsAdmin.php +++ b/plugins/CorePluginsAdmin/CorePluginsAdmin.php @@ -72,6 +72,7 @@ class CorePluginsAdmin extends Plugin public function getClientSideTranslationKeys(&$translations) { $translations[] = 'CorePluginsAdmin_NoZipFileSelected'; + $translations[] = 'CorePluginsAdmin_FileExceedsUploadLimit'; $translations[] = 'CorePluginsAdmin_NoPluginSettings'; $translations[] = 'CoreAdminHome_PluginSettingsIntro'; $translations[] = 'CoreAdminHome_PluginSettingsSaveSuccess'; diff --git a/plugins/CorePluginsAdmin/angularjs/plugins/plugin-upload.directive.js b/plugins/CorePluginsAdmin/angularjs/plugins/plugin-upload.directive.js index 741b561011..dff036c519 100644 --- a/plugins/CorePluginsAdmin/angularjs/plugins/plugin-upload.directive.js +++ b/plugins/CorePluginsAdmin/angularjs/plugins/plugin-upload.directive.js @@ -37,6 +37,9 @@ if (!fileName || '.zip' != fileName.slice(-4)) { event.preventDefault(); alert(_pk_translate('CorePluginsAdmin_NoZipFileSelected')); + } else if ($zipFile.data('maxSize') > 0 && $zipFile[0].files[0].size > $zipFile.data('maxSize')*1048576) { + event.preventDefault(); + alert(_pk_translate('CorePluginsAdmin_FileExceedsUploadLimit')); } }); }; diff --git a/plugins/CorePluginsAdmin/lang/en.json b/plugins/CorePluginsAdmin/lang/en.json index 020b96d3f7..54f674b9b0 100644 --- a/plugins/CorePluginsAdmin/lang/en.json +++ b/plugins/CorePluginsAdmin/lang/en.json @@ -33,6 +33,7 @@ "MissingRequirementsNotice": "Please update %1$s %2$s to a newer version, %1$s %3$s is required.", "MissingRequirementsPleaseInstallNotice": "Please install %1$s %2$s as it is required by %3$s.", "NoZipFileSelected": "Please select a ZIP file.", + "FileExceedsUploadLimit": "The selected file exceeds the upload limit of your server.", "NumUpdatesAvailable": "%s Update(s) available", "NoPluginSettings": "No plugin settings that can be configured", "Origin": "Origin", diff --git a/plugins/Marketplace/Controller.php b/plugins/Marketplace/Controller.php index c2d9d6e6d8..aae329640c 100644 --- a/plugins/Marketplace/Controller.php +++ b/plugins/Marketplace/Controller.php @@ -26,6 +26,7 @@ use Piwik\Plugins\Marketplace\Input\PurchaseType; use Piwik\Plugins\Marketplace\Input\Sort; use Piwik\ProxyHttp; use Piwik\SettingsPiwik; +use Piwik\SettingsServer; use Piwik\Url; use Piwik\View; use Exception; @@ -287,6 +288,7 @@ class Controller extends \Piwik\Plugin\ControllerAdmin $view->isAutoUpdatePossible = SettingsPiwik::isAutoUpdatePossible(); $view->isAutoUpdateEnabled = SettingsPiwik::isAutoUpdateEnabled(); $view->isPluginUploadEnabled = CorePluginsAdmin::isPluginUploadEnabled(); + $view->uploadLimit = SettingsServer::getPostMaxUploadSize(); $view->inReportingMenu = (bool) Common::getRequestVar('embed', 0, 'int'); return $view->render(); diff --git a/plugins/Marketplace/templates/uploadPluginDialog.twig b/plugins/Marketplace/templates/uploadPluginDialog.twig index 7da4efddc5..ec9a9e1acf 100644 --- a/plugins/Marketplace/templates/uploadPluginDialog.twig +++ b/plugins/Marketplace/templates/uploadPluginDialog.twig @@ -6,7 +6,7 @@ <form enctype="multipart/form-data" method="post" id="uploadPluginForm" action="{{ linkTo({'module':'CorePluginsAdmin', 'action':'uploadPlugin', 'nonce': installNonce}) }}"> - <input type="file" name="pluginZip"> + <input type="file" name="pluginZip" data-max-size="{{ uploadLimit }}"> <br /> <div piwik-field uicontrol="password" name="confirmPassword" autocomplete="off" data-title="{{ 'Login_ConfirmPasswordToContinue'|translate|e('html_attr') }}" diff --git a/tests/PHPUnit/Unit/SettingsServerTest.php b/tests/PHPUnit/Unit/SettingsServerTest.php new file mode 100644 index 0000000000..0c74e7a921 --- /dev/null +++ b/tests/PHPUnit/Unit/SettingsServerTest.php @@ -0,0 +1,47 @@ +<?php +/** + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +namespace Piwik\Tests\Unit; + +use Piwik\SettingsServer; + +/** + * @group Core + * @group SettingsServer + */ +class SettingsServerTest extends \PHPUnit\Framework\TestCase +{ + /** + * Dataprovider for testGetMegaBytesFromShorthandByte + */ + public function getShorthandByteTestData() + { + return [ + ['8M', 8], + ['10 m', 10], + ['2g', 2048], + ['1K', 1/1024], + ['1048576', 1], + ['garbl', false], + ['17sdfsdf', false], + ]; + } + + /** + * @dataProvider getShorthandByteTestData + */ + public function testGetMegaBytesFromShorthandByte($data, $expected) + { + $class = new \ReflectionClass(SettingsServer::class); + $method = $class->getMethod('getMegaBytesFromShorthandByte'); + $method->setAccessible(true); + $output = $method->invoke($class, $data); + + $this->assertEquals($expected, $output); + } +}
\ No newline at end of file |