diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index ae29727f6b..99da8f9e70 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -2844,18 +2844,6 @@ parameters: count: 3 path: src/Controllers/Export/ExportController.php - - - message: '#^Call to an undefined method object\:\:exportFooter\(\)\.$#' - identifier: method.notFound - count: 1 - path: src/Controllers/Export/ExportController.php - - - - message: '#^Call to an undefined method object\:\:exportHeader\(\)\.$#' - identifier: method.notFound - count: 1 - path: src/Controllers/Export/ExportController.php - - message: ''' #^Call to deprecated method getInstance\(\) of class PhpMyAdmin\\Config\: @@ -2880,7 +2868,7 @@ parameters: - message: '#^Construct empty\(\) is not allowed\. Use more strict comparison\.$#' identifier: empty.notAllowed - count: 5 + count: 4 path: src/Controllers/Export/ExportController.php - @@ -2931,18 +2919,6 @@ parameters: count: 1 path: src/Controllers/Export/ExportController.php - - - message: '#^Parameter \#1 \$exportPlugin of method PhpMyAdmin\\Export\\Export\:\:getFinalFilenameAndMimetypeForFilename\(\) expects PhpMyAdmin\\Plugins\\ExportPlugin, object given\.$#' - identifier: argument.type - count: 1 - path: src/Controllers/Export/ExportController.php - - - - message: '#^Parameter \#1 \$exportType of method PhpMyAdmin\\Export\\Export\:\:getFilenameAndMimetype\(\) expects string, mixed given\.$#' - identifier: argument.type - count: 1 - path: src/Controllers/Export/ExportController.php - - message: '#^Parameter \#1 \$exportType of method PhpMyAdmin\\Export\\Export\:\:getHtmlForDisplayedExportFooter\(\) expects string, mixed given\.$#' identifier: argument.type @@ -2986,7 +2962,13 @@ parameters: path: src/Controllers/Export/ExportController.php - - message: '#^Parameter \#2 \$compression of method PhpMyAdmin\\Export\\Export\:\:getFinalFilenameAndMimetypeForFilename\(\) expects string, mixed given\.$#' + message: '#^Parameter \#2 \$compression of method PhpMyAdmin\\Export\\Export\:\:getFinalFilename\(\) expects string, mixed given\.$#' + identifier: argument.type + count: 2 + path: src/Controllers/Export/ExportController.php + + - + message: '#^Parameter \#2 \$compression of method PhpMyAdmin\\Export\\Export\:\:getMimeType\(\) expects string, mixed given\.$#' identifier: argument.type count: 1 path: src/Controllers/Export/ExportController.php @@ -2998,13 +2980,7 @@ parameters: path: src/Controllers/Export/ExportController.php - - message: '#^Parameter \#2 \$exportPlugin of static method PhpMyAdmin\\Export\\Export\:\:exportRaw\(\) expects PhpMyAdmin\\Plugins\\ExportPlugin, object given\.$#' - identifier: argument.type - count: 1 - path: src/Controllers/Export/ExportController.php - - - - message: '#^Parameter \#2 \$rememberTemplate of method PhpMyAdmin\\Export\\Export\:\:getFilenameAndMimetype\(\) expects string, mixed given\.$#' + message: '#^Parameter \#2 \$exportType of method PhpMyAdmin\\Export\\Export\:\:rememberFilename\(\) expects string, mixed given\.$#' identifier: argument.type count: 1 path: src/Controllers/Export/ExportController.php @@ -3015,42 +2991,18 @@ parameters: count: 1 path: src/Controllers/Export/ExportController.php - - - message: '#^Parameter \#3 \$exportPlugin of method PhpMyAdmin\\Export\\Export\:\:exportServer\(\) expects PhpMyAdmin\\Plugins\\ExportPlugin, object given\.$#' - identifier: argument.type - count: 1 - path: src/Controllers/Export/ExportController.php - - - - message: '#^Parameter \#3 \$exportPlugin of method PhpMyAdmin\\Export\\Export\:\:getFilenameAndMimetype\(\) expects PhpMyAdmin\\Plugins\\ExportPlugin, object given\.$#' - identifier: argument.type - count: 1 - path: src/Controllers/Export/ExportController.php - - message: '#^Parameter \#3 \$saveFilename of method PhpMyAdmin\\Export\\Export\:\:closeFile\(\) expects string, mixed given\.$#' identifier: argument.type count: 1 path: src/Controllers/Export/ExportController.php - - - message: '#^Parameter \#4 \$compression of method PhpMyAdmin\\Export\\Export\:\:getFilenameAndMimetype\(\) expects string, mixed given\.$#' - identifier: argument.type - count: 1 - path: src/Controllers/Export/ExportController.php - - message: '#^Parameter \#4 \$errorUrl of method PhpMyAdmin\\Export\\Export\:\:exportServer\(\) expects string, mixed given\.$#' identifier: argument.type count: 1 path: src/Controllers/Export/ExportController.php - - - message: '#^Parameter \#4 \$exportPlugin of method PhpMyAdmin\\Export\\Export\:\:exportTable\(\) expects PhpMyAdmin\\Plugins\\ExportPlugin, object given\.$#' - identifier: argument.type - count: 2 - path: src/Controllers/Export/ExportController.php - - message: '#^Parameter \#4 \$tableStructure of method PhpMyAdmin\\Export\\Export\:\:exportDatabase\(\) expects array\, array\ given\.$#' identifier: argument.type @@ -3075,12 +3027,6 @@ parameters: count: 2 path: src/Controllers/Export/ExportController.php - - - message: '#^Parameter \#6 \$exportPlugin of method PhpMyAdmin\\Export\\Export\:\:exportDatabase\(\) expects PhpMyAdmin\\Plugins\\ExportPlugin, object given\.$#' - identifier: argument.type - count: 2 - path: src/Controllers/Export/ExportController.php - - message: '#^Parameter \#6 \$exportType of method PhpMyAdmin\\Export\\Export\:\:exportTable\(\) expects string, mixed given\.$#' identifier: argument.type @@ -8700,7 +8646,7 @@ parameters: Use dependency injection instead\.$# ''' identifier: staticMethod.deprecated - count: 3 + count: 2 path: src/Export/Export.php - diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 9e94606269..a50ffe0a40 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1470,16 +1470,6 @@ - - - - - - - - - - @@ -1516,7 +1506,6 @@ - @@ -1637,14 +1626,9 @@ - - - - - @@ -5306,7 +5290,6 @@ - diff --git a/src/Controllers/Export/ExportController.php b/src/Controllers/Export/ExportController.php index 49c293046c..f49fb33c8b 100644 --- a/src/Controllers/Export/ExportController.php +++ b/src/Controllers/Export/ExportController.php @@ -21,6 +21,7 @@ use PhpMyAdmin\Message; use PhpMyAdmin\Plugins; use PhpMyAdmin\Plugins\Export\ExportSql; use PhpMyAdmin\Plugins\Export\ExportXml; +use PhpMyAdmin\Plugins\ExportPlugin; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Sanitize; use PhpMyAdmin\SqlParser\Parser; @@ -80,7 +81,7 @@ final class ExportController implements InvocableController /** @var array|null $aliasesParam */ $aliasesParam = $request->getParsedBodyParam('aliases'); $structureOrDataForced = (bool) $request->getParsedBodyParamAsStringOrNull('structure_or_data_forced'); - $rememberTemplate = $request->getParsedBodyParam('remember_template'); + $rememberTemplate = $request->getParsedBodyParamAsString('remember_template', ''); $dbSelect = $request->getParsedBodyParam('db_select'); $tableStructure = $request->getParsedBodyParam('table_structure'); $lockTables = $request->hasBodyParam('lock_tables'); @@ -103,7 +104,7 @@ final class ExportController implements InvocableController ]); // Check export type - if ($exportPlugin === null) { + if (! $exportPlugin instanceof ExportPlugin) { $this->response->setRequestStatus(false); $this->response->addHTML(Message::error(__('Bad type!'))->getDisplay()); @@ -235,26 +236,24 @@ final class ExportController implements InvocableController // Generate filename and mime type if needed $mimeType = ''; if ($GLOBALS['asfile']) { - if (empty($rememberTemplate)) { - $rememberTemplate = ''; + $filenameTemplate = $request->getParsedBodyParamAsString('filename_template'); + + if ((bool) $rememberTemplate) { + $this->export->rememberFilename($config, $GLOBALS['export_type'], $filenameTemplate); } - [$filename, $mimeType] = $this->export->getFilenameAndMimetype( - $GLOBALS['export_type'], - $rememberTemplate, + $filename = $this->export->getFinalFilename( $exportPlugin, $GLOBALS['compression'], - $request->getParsedBodyParamAsString('filename_template'), + Sanitize::sanitizeFilename(Util::expandUserString($filenameTemplate), true), ); + + $mimeType = $this->export->getMimeType($exportPlugin, $GLOBALS['compression']); } // For raw query export, filename will be export.extension if ($GLOBALS['export_type'] === 'raw') { - [$filename] = $this->export->getFinalFilenameAndMimetypeForFilename( - $exportPlugin, - $GLOBALS['compression'], - 'export', - ); + $filename = $this->export->getFinalFilename($exportPlugin, $GLOBALS['compression'], 'export'); } // Open file on server if needed diff --git a/src/Export/Export.php b/src/Export/Export.php index 6be6b6b81b..b4cacd7d2e 100644 --- a/src/Export/Export.php +++ b/src/Export/Export.php @@ -19,7 +19,6 @@ use PhpMyAdmin\MessageType; use PhpMyAdmin\Plugins; use PhpMyAdmin\Plugins\ExportPlugin; use PhpMyAdmin\Plugins\SchemaPlugin; -use PhpMyAdmin\Sanitize; use PhpMyAdmin\Table\Table; use PhpMyAdmin\Url; use PhpMyAdmin\Util; @@ -279,20 +278,11 @@ class Export return (int) $memoryLimit; } - /** - * Returns the filename and MIME type for a compression and an export plugin - * - * @param ExportPlugin $exportPlugin the export plugin - * @param string $compression compression asked - * @param string $filename the filename - * - * @return string[] the filename and mime type - */ - public function getFinalFilenameAndMimetypeForFilename( + public function getFinalFilename( ExportPlugin $exportPlugin, string $compression, string $filename, - ): array { + ): string { // Grab basic dump extension and mime type // Check if the user already added extension; // get the substring where the extension would be if it was included @@ -303,62 +293,39 @@ class Export $filename .= $requiredExtension; } - $mediaType = $exportPlugin->getProperties()->getMimeType(); - - // If dump is going to be compressed, set correct mime_type and add - // compression to extension + // If dump is going to be compressed, add compression to extension if ($compression === 'gzip') { $filename .= '.gz'; - $mediaType = 'application/x-gzip'; } elseif ($compression === 'zip') { $filename .= '.zip'; - $mediaType = 'application/zip'; } - return [$filename, $mediaType]; + return $filename; } - /** - * Return the filename and MIME type for export file - * - * @param string $exportType type of export - * @param string $rememberTemplate whether to remember template - * @param ExportPlugin $exportPlugin the export plugin - * @param string $compression compression asked - * @param string $filenameTemplate the filename template - * - * @return string[] the filename template and mime type - */ - public function getFilenameAndMimetype( + public function getMimeType(ExportPlugin $exportPlugin, string $compression): string + { + return match ($compression) { + 'gzip' => 'application/x-gzip', + 'zip' => 'application/zip', + default => $exportPlugin->getProperties()->getMimeType(), + }; + } + + public function rememberFilename( + Config $config, string $exportType, - string $rememberTemplate, - ExportPlugin $exportPlugin, - string $compression, string $filenameTemplate, - ): array { - $config = Config::getInstance(); + ): void { if ($exportType === 'server') { - if ($rememberTemplate !== '' && $rememberTemplate !== '0') { - $config->setUserValue('pma_server_filename_template', 'Export/file_template_server', $filenameTemplate); - } + $config->setUserValue('pma_server_filename_template', 'Export/file_template_server', $filenameTemplate); } elseif ($exportType === 'database') { - if ($rememberTemplate !== '' && $rememberTemplate !== '0') { - $config->setUserValue('pma_db_filename_template', 'Export/file_template_database', $filenameTemplate); - } + $config->setUserValue('pma_db_filename_template', 'Export/file_template_database', $filenameTemplate); } elseif ($exportType === 'raw') { - if ($rememberTemplate !== '' && $rememberTemplate !== '0') { - $config->setUserValue('pma_raw_filename_template', 'Export/file_template_raw', $filenameTemplate); - } - } elseif ($rememberTemplate !== '' && $rememberTemplate !== '0') { + $config->setUserValue('pma_raw_filename_template', 'Export/file_template_raw', $filenameTemplate); + } else { $config->setUserValue('pma_table_filename_template', 'Export/file_template_table', $filenameTemplate); } - - $filename = Util::expandUserString($filenameTemplate); - // remove dots in filename (coming from either the template or already - // part of the filename) to avoid a remote code execution vulnerability - $filename = Sanitize::sanitizeFilename($filename, true); - - return $this->getFinalFilenameAndMimetypeForFilename($exportPlugin, $compression, $filename); } /** diff --git a/tests/unit/Export/ExportTest.php b/tests/unit/Export/ExportTest.php index fe7100d9f0..96fc5bd4cc 100644 --- a/tests/unit/Export/ExportTest.php +++ b/tests/unit/Export/ExportTest.php @@ -60,7 +60,7 @@ class ExportTest extends AbstractTestCase self::assertSame($expected, $actual); } - public function testGetFinalFilenameAndMimetypeForFilename(): void + public function testGetFinalFilename(): void { $dbi = $this->createDatabaseInterface(); DatabaseInterface::$instance = $dbi; @@ -70,16 +70,28 @@ class ExportTest extends AbstractTestCase new Export($dbi), new Transformations(), ); - $finalFileName = $export->getFinalFilenameAndMimetypeForFilename($exportPlugin, 'zip', 'myfilename'); - self::assertSame(['myfilename.php.zip', 'application/zip'], $finalFileName); - $finalFileName = $export->getFinalFilenameAndMimetypeForFilename($exportPlugin, 'gzip', 'myfilename'); - self::assertSame(['myfilename.php.gz', 'application/x-gzip'], $finalFileName); - $finalFileName = $export->getFinalFilenameAndMimetypeForFilename( - $exportPlugin, - 'gzip', - 'export.db1.table1.file', + $finalFileName = $export->getFinalFilename($exportPlugin, 'zip', 'myfilename'); + self::assertSame('myfilename.php.zip', $finalFileName); + $finalFileName = $export->getFinalFilename($exportPlugin, 'gzip', 'myfilename'); + self::assertSame('myfilename.php.gz', $finalFileName); + $finalFileName = $export->getFinalFilename($exportPlugin, 'gzip', 'export.db1.table1.file'); + self::assertSame('export.db1.table1.file.php.gz', $finalFileName); + } + + public function testGetMimeType(): void + { + $dbi = $this->createDatabaseInterface(); + DatabaseInterface::$instance = $dbi; + $export = new Export($dbi); + $exportPlugin = new ExportPhparray( + new Relation($dbi), + new Export($dbi), + new Transformations(), ); - self::assertSame(['export.db1.table1.file.php.gz', 'application/x-gzip'], $finalFileName); + $mimeType = $export->getMimeType($exportPlugin, 'zip'); + self::assertSame('application/zip', $mimeType); + $mimeType = $export->getMimeType($exportPlugin, 'gzip'); + self::assertSame('application/x-gzip', $mimeType); } public function testExportDatabase(): void