From ba0250fdca94f048d81bcbe95595524299869369 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Fri, 21 Nov 2025 21:44:01 +0000 Subject: [PATCH 01/21] Clean up exportHeader Signed-off-by: Kamil Tekiela --- src/Plugins/Export/ExportCodegen.php | 8 --- src/Plugins/Export/ExportCsv.php | 10 +-- src/Plugins/Export/ExportExcel.php | 26 +------ src/Plugins/Export/ExportMediawiki.php | 8 --- src/Plugins/Export/ExportPdf.php | 9 +-- src/Plugins/Export/ExportTexytext.php | 8 --- src/Plugins/ExportPlugin.php | 5 +- tests/unit/Plugins/Export/ExportExcelTest.php | 72 ++----------------- tests/unit/Plugins/Export/ExportPdfTest.php | 9 +-- 9 files changed, 23 insertions(+), 132 deletions(-) diff --git a/src/Plugins/Export/ExportCodegen.php b/src/Plugins/Export/ExportCodegen.php index 78ad5bd38f..5868963c45 100644 --- a/src/Plugins/Export/ExportCodegen.php +++ b/src/Plugins/Export/ExportCodegen.php @@ -82,14 +82,6 @@ class ExportCodegen extends ExportPlugin return $exportPluginProperties; } - /** - * Outputs export header - */ - public function exportHeader(): bool - { - return true; - } - /** * Outputs export footer */ diff --git a/src/Plugins/Export/ExportCsv.php b/src/Plugins/Export/ExportCsv.php index 9e23a996c1..43ac6f5eed 100644 --- a/src/Plugins/Export/ExportCsv.php +++ b/src/Plugins/Export/ExportCsv.php @@ -107,12 +107,8 @@ class ExportCsv extends ExportPlugin return $exportPluginProperties; } - /** - * Outputs export header - */ - public function exportHeader(): bool + private function setupExportConfiguration(): void { - // Here we just prepare some values for export if ($this->terminated === '' || strtolower($this->terminated) === 'auto') { $this->terminated = "\n"; } else { @@ -124,8 +120,6 @@ class ExportCsv extends ExportPlugin } $this->separator = str_replace('\\t', "\011", $this->separator); - - return true; } /** @@ -319,6 +313,8 @@ class ExportCsv extends ExportPlugin $request->getParsedBodyParam('csv_null'), $exportConfig['csv_null'] ?? $this->null, ); + + $this->setupExportConfiguration(); } private function setStringValue(mixed $fromRequest, mixed $fromConfig): string diff --git a/src/Plugins/Export/ExportExcel.php b/src/Plugins/Export/ExportExcel.php index 01793b0803..b4afb2feee 100644 --- a/src/Plugins/Export/ExportExcel.php +++ b/src/Plugins/Export/ExportExcel.php @@ -102,12 +102,8 @@ class ExportExcel extends ExportPlugin return $exportPluginProperties; } - /** - * Outputs export header - */ - public function exportHeader(): bool + private function setupExportConfiguration(): void { - // Here we just prepare some values for export $this->terminated = "\015\012"; switch ($this->edition) { case 'win': // as tested on Windows with Excel 2002 and Excel 2007 @@ -121,8 +117,6 @@ class ExportExcel extends ExportPlugin $this->enclosed = '"'; $this->escaped = '"'; - - return true; } /** @@ -295,22 +289,8 @@ class ExportExcel extends ExportPlugin $request->getParsedBodyParam('excel_null'), $exportConfig['excel_null'] ?? null, ); - $this->separator = $this->setStringValue( - $request->getParsedBodyParam('excel_separator'), - $exportConfig['excel_separator'] ?? null, - ); - $this->enclosed = $this->setStringValue( - $request->getParsedBodyParam('excel_enclosed'), - $exportConfig['excel_enclosed'] ?? null, - ); - $this->escaped = $this->setStringValue( - $request->getParsedBodyParam('excel_escaped'), - $exportConfig['excel_escaped'] ?? null, - ); - $this->terminated = $this->setStringValue( - $request->getParsedBodyParam('excel_terminated'), - $exportConfig['excel_terminated'] ?? null, - ); + + $this->setupExportConfiguration(); } private function setStringValue(mixed $fromRequest, mixed $fromConfig): string diff --git a/src/Plugins/Export/ExportMediawiki.php b/src/Plugins/Export/ExportMediawiki.php index fc5bbe759a..476f2fd156 100644 --- a/src/Plugins/Export/ExportMediawiki.php +++ b/src/Plugins/Export/ExportMediawiki.php @@ -92,14 +92,6 @@ class ExportMediawiki extends ExportPlugin return $exportPluginProperties; } - /** - * Outputs export header - */ - public function exportHeader(): bool - { - return true; - } - /** * Outputs export footer */ diff --git a/src/Plugins/Export/ExportPdf.php b/src/Plugins/Export/ExportPdf.php index 9338e42872..d10cf492d1 100644 --- a/src/Plugins/Export/ExportPdf.php +++ b/src/Plugins/Export/ExportPdf.php @@ -101,10 +101,7 @@ class ExportPdf extends ExportPlugin return $exportPluginProperties; } - /** - * Outputs export header - */ - public function exportHeader(): bool + private function setupExportConfiguration(): void { $pdf = $this->getPdf(); $pdf->Open(); @@ -112,8 +109,6 @@ class ExportPdf extends ExportPlugin $pdf->setTitleFontSize(18); $pdf->setTitleText($this->pdfReportTitle); $pdf->setTopMargin(30); - - return true; } /** @@ -291,5 +286,7 @@ class ExportPdf extends ExportPlugin $this->doRelation = (bool) ($request->getParsedBodyParam('pdf_relation') ?? $exportConfig['pdf_relation'] ?? false); $this->doMime = (bool) ($request->getParsedBodyParam('pdf_mime') ?? $exportConfig['pdf_mime'] ?? false); + + $this->setupExportConfiguration(); } } diff --git a/src/Plugins/Export/ExportTexytext.php b/src/Plugins/Export/ExportTexytext.php index 629e2604fb..d840dc1bfe 100644 --- a/src/Plugins/Export/ExportTexytext.php +++ b/src/Plugins/Export/ExportTexytext.php @@ -99,14 +99,6 @@ class ExportTexytext extends ExportPlugin return $exportPluginProperties; } - /** - * Outputs export header - */ - public function exportHeader(): bool - { - return true; - } - /** * Outputs export footer */ diff --git a/src/Plugins/ExportPlugin.php b/src/Plugins/ExportPlugin.php index 27a894bafa..fade3e7f5f 100644 --- a/src/Plugins/ExportPlugin.php +++ b/src/Plugins/ExportPlugin.php @@ -47,7 +47,10 @@ abstract class ExportPlugin implements Plugin /** * Outputs export header */ - abstract public function exportHeader(): bool; + public function exportHeader(): bool + { + return true; + } /** * Outputs export footer diff --git a/tests/unit/Plugins/Export/ExportExcelTest.php b/tests/unit/Plugins/Export/ExportExcelTest.php index f114de3fcb..22abec7a06 100644 --- a/tests/unit/Plugins/Export/ExportExcelTest.php +++ b/tests/unit/Plugins/Export/ExportExcelTest.php @@ -239,7 +239,7 @@ class ExportExcelTest extends AbstractTestCase Export::$saveOnServer = false; $request = ServerRequestFactory::create()->createServerRequest('POST', 'https://example.com/') - ->withParsedBody(['excel_columns' => 'On', 'excel_terminated' => ';']); + ->withParsedBody(['excel_columns' => 'On']); $this->object->setExportOptions($request, []); @@ -252,72 +252,10 @@ class ExportExcelTest extends AbstractTestCase $result = ob_get_clean(); self::assertSame( - 'idnamedatetimefield;1abcd2011-01-20 02:00:02;2foo2010-01-20 02:00:02;3Abcd2012-01-20 02:00:02;', - $result, - ); - - // case 3 - $request = ServerRequestFactory::create()->createServerRequest('POST', 'https://example.com/') - ->withParsedBody(['excel_columns' => 'On', 'excel_enclosed' => '"', 'excel_terminated' => ';']); - - $this->object->setExportOptions($request, []); - - ob_start(); - self::assertTrue($this->object->exportData( - 'test_db', - 'test_table', - 'SELECT * FROM `test_db`.`test_table`;', - )); - $result = ob_get_clean(); - - self::assertSame( - '"id""name""datetimefield";"1""abcd""2011-01-20 02:00:02";' - . '"2""foo""2010-01-20 02:00:02";"3""Abcd""2012-01-20 02:00:02";', - $result, - ); - - // case 4 - ob_start(); - self::assertTrue($this->object->exportData( - 'test_db', - 'test_table', - 'SELECT * FROM `test_db`.`test_table`;', - )); - $result = ob_get_clean(); - - self::assertSame( - '"id""name""datetimefield";"1""abcd""2011-01-20 02:00:02";' - . '"2""foo""2010-01-20 02:00:02";"3""Abcd""2012-01-20 02:00:02";', - $result, - ); - - // case 5 - ob_start(); - self::assertTrue($this->object->exportData( - 'test_db', - 'test_table', - 'SELECT * FROM `test_db`.`test_table`;', - )); - $result = ob_get_clean(); - - self::assertSame( - '"id""name""datetimefield";"1""abcd""2011-01-20 02:00:02";' - . '"2""foo""2010-01-20 02:00:02";"3""Abcd""2012-01-20 02:00:02";', - $result, - ); - - // case 6 - ob_start(); - self::assertTrue($this->object->exportData( - 'test_db', - 'test_table', - 'SELECT * FROM `test_db`.`test_table`;', - )); - $result = ob_get_clean(); - - self::assertSame( - '"id""name""datetimefield";"1""abcd""2011-01-20 02:00:02";' - . '"2""foo""2010-01-20 02:00:02";"3""Abcd""2012-01-20 02:00:02";', + '"id";"name";"datetimefield"' . "\015\012" + . '"1";"abcd";"2011-01-20 02:00:02"' . "\015\012" + . '"2";"foo";"2010-01-20 02:00:02"' . "\015\012" + . '"3";"Abcd";"2012-01-20 02:00:02"' . "\015\012", $result, ); } diff --git a/tests/unit/Plugins/Export/ExportPdfTest.php b/tests/unit/Plugins/Export/ExportPdfTest.php index 9e45fa5949..0c07b34cc7 100644 --- a/tests/unit/Plugins/Export/ExportPdfTest.php +++ b/tests/unit/Plugins/Export/ExportPdfTest.php @@ -7,6 +7,7 @@ namespace PhpMyAdmin\Tests\Plugins\Export; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Dbal\DatabaseInterface; use PhpMyAdmin\Export\Export; +use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Plugins\Export\ExportPdf; use PhpMyAdmin\Plugins\Export\Helpers\Pdf; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup; @@ -154,7 +155,7 @@ class ExportPdfTest extends AbstractTestCase ); } - public function testExportHeader(): void + public function testSetExportOptions(): void { $pdf = $this->getMockBuilder(Pdf::class) ->disableOriginalConstructor() @@ -169,9 +170,9 @@ class ExportPdfTest extends AbstractTestCase $attrPdf = new ReflectionProperty(ExportPdf::class, 'pdf'); $attrPdf->setValue($this->object, $pdf); - self::assertTrue( - $this->object->exportHeader(), - ); + $request = ServerRequestFactory::create()->createServerRequest('POST', 'https://example.com/'); + + $this->object->setExportOptions($request, []); } public function testExportFooter(): void From 09a60731d4a6818f89542cd4a9ce2da3b5447924 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Fri, 21 Nov 2025 21:47:20 +0000 Subject: [PATCH 02/21] Clean up exportFooter Signed-off-by: Kamil Tekiela --- src/Plugins/Export/ExportCodegen.php | 8 -------- src/Plugins/Export/ExportCsv.php | 8 -------- src/Plugins/Export/ExportExcel.php | 8 -------- src/Plugins/Export/ExportLatex.php | 8 -------- src/Plugins/Export/ExportMediawiki.php | 8 -------- src/Plugins/Export/ExportPhparray.php | 8 -------- src/Plugins/Export/ExportTexytext.php | 8 -------- src/Plugins/ExportPlugin.php | 5 ++++- 8 files changed, 4 insertions(+), 57 deletions(-) diff --git a/src/Plugins/Export/ExportCodegen.php b/src/Plugins/Export/ExportCodegen.php index 5868963c45..086b2886ce 100644 --- a/src/Plugins/Export/ExportCodegen.php +++ b/src/Plugins/Export/ExportCodegen.php @@ -82,14 +82,6 @@ class ExportCodegen extends ExportPlugin return $exportPluginProperties; } - /** - * Outputs export footer - */ - public function exportFooter(): bool - { - return true; - } - /** * Outputs database header * diff --git a/src/Plugins/Export/ExportCsv.php b/src/Plugins/Export/ExportCsv.php index 43ac6f5eed..0558bf0bf9 100644 --- a/src/Plugins/Export/ExportCsv.php +++ b/src/Plugins/Export/ExportCsv.php @@ -122,14 +122,6 @@ class ExportCsv extends ExportPlugin $this->separator = str_replace('\\t', "\011", $this->separator); } - /** - * Outputs export footer - */ - public function exportFooter(): bool - { - return true; - } - /** * Outputs database header * diff --git a/src/Plugins/Export/ExportExcel.php b/src/Plugins/Export/ExportExcel.php index b4afb2feee..5c6d2c26ca 100644 --- a/src/Plugins/Export/ExportExcel.php +++ b/src/Plugins/Export/ExportExcel.php @@ -119,14 +119,6 @@ class ExportExcel extends ExportPlugin $this->escaped = '"'; } - /** - * Outputs export footer - */ - public function exportFooter(): bool - { - return true; - } - /** * Outputs database header * diff --git a/src/Plugins/Export/ExportLatex.php b/src/Plugins/Export/ExportLatex.php index 02f3ffa72f..7deaab0a85 100644 --- a/src/Plugins/Export/ExportLatex.php +++ b/src/Plugins/Export/ExportLatex.php @@ -236,14 +236,6 @@ class ExportLatex extends ExportPlugin return $this->export->outputHandler($head); } - /** - * Outputs export footer - */ - public function exportFooter(): bool - { - return true; - } - /** * Outputs database header * diff --git a/src/Plugins/Export/ExportMediawiki.php b/src/Plugins/Export/ExportMediawiki.php index 476f2fd156..44dd1e5f47 100644 --- a/src/Plugins/Export/ExportMediawiki.php +++ b/src/Plugins/Export/ExportMediawiki.php @@ -92,14 +92,6 @@ class ExportMediawiki extends ExportPlugin return $exportPluginProperties; } - /** - * Outputs export footer - */ - public function exportFooter(): bool - { - return true; - } - /** * Outputs database header * diff --git a/src/Plugins/Export/ExportPhparray.php b/src/Plugins/Export/ExportPhparray.php index 89a9c04d61..cb720b18fe 100644 --- a/src/Plugins/Export/ExportPhparray.php +++ b/src/Plugins/Export/ExportPhparray.php @@ -89,14 +89,6 @@ class ExportPhparray extends ExportPlugin return true; } - /** - * Outputs export footer - */ - public function exportFooter(): bool - { - return true; - } - /** * Outputs database header * diff --git a/src/Plugins/Export/ExportTexytext.php b/src/Plugins/Export/ExportTexytext.php index d840dc1bfe..2f68142d83 100644 --- a/src/Plugins/Export/ExportTexytext.php +++ b/src/Plugins/Export/ExportTexytext.php @@ -99,14 +99,6 @@ class ExportTexytext extends ExportPlugin return $exportPluginProperties; } - /** - * Outputs export footer - */ - public function exportFooter(): bool - { - return true; - } - /** * Outputs database header * diff --git a/src/Plugins/ExportPlugin.php b/src/Plugins/ExportPlugin.php index fade3e7f5f..6a3cfc0311 100644 --- a/src/Plugins/ExportPlugin.php +++ b/src/Plugins/ExportPlugin.php @@ -55,7 +55,10 @@ abstract class ExportPlugin implements Plugin /** * Outputs export footer */ - abstract public function exportFooter(): bool; + public function exportFooter(): bool + { + return true; + } /** * Outputs database header From f80d2b7f12a7a16f9df3708480ba5acb59e1d8b6 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Fri, 21 Nov 2025 21:49:50 +0000 Subject: [PATCH 03/21] Clean up exportDBHeader Signed-off-by: Kamil Tekiela --- src/Plugins/Export/ExportCodegen.php | 11 ----------- src/Plugins/Export/ExportCsv.php | 11 ----------- src/Plugins/Export/ExportExcel.php | 11 ----------- src/Plugins/Export/ExportMediawiki.php | 11 ----------- src/Plugins/Export/ExportOds.php | 11 ----------- src/Plugins/Export/ExportPdf.php | 11 ----------- src/Plugins/Export/ExportYaml.php | 11 ----------- src/Plugins/ExportPlugin.php | 5 ++++- 8 files changed, 4 insertions(+), 78 deletions(-) diff --git a/src/Plugins/Export/ExportCodegen.php b/src/Plugins/Export/ExportCodegen.php index 086b2886ce..98ebab5ea7 100644 --- a/src/Plugins/Export/ExportCodegen.php +++ b/src/Plugins/Export/ExportCodegen.php @@ -82,17 +82,6 @@ class ExportCodegen extends ExportPlugin return $exportPluginProperties; } - /** - * Outputs database header - * - * @param string $db Database name - * @param string $dbAlias Aliases of db - */ - public function exportDBHeader(string $db, string $dbAlias = ''): bool - { - return true; - } - /** * Outputs database footer * diff --git a/src/Plugins/Export/ExportCsv.php b/src/Plugins/Export/ExportCsv.php index 0558bf0bf9..7b0810aff8 100644 --- a/src/Plugins/Export/ExportCsv.php +++ b/src/Plugins/Export/ExportCsv.php @@ -122,17 +122,6 @@ class ExportCsv extends ExportPlugin $this->separator = str_replace('\\t', "\011", $this->separator); } - /** - * Outputs database header - * - * @param string $db Database name - * @param string $dbAlias Alias of db - */ - public function exportDBHeader(string $db, string $dbAlias = ''): bool - { - return true; - } - /** * Outputs database footer * diff --git a/src/Plugins/Export/ExportExcel.php b/src/Plugins/Export/ExportExcel.php index 5c6d2c26ca..81513ed653 100644 --- a/src/Plugins/Export/ExportExcel.php +++ b/src/Plugins/Export/ExportExcel.php @@ -119,17 +119,6 @@ class ExportExcel extends ExportPlugin $this->escaped = '"'; } - /** - * Outputs database header - * - * @param string $db Database name - * @param string $dbAlias Alias of db - */ - public function exportDBHeader(string $db, string $dbAlias = ''): bool - { - return true; - } - /** * Outputs database footer * diff --git a/src/Plugins/Export/ExportMediawiki.php b/src/Plugins/Export/ExportMediawiki.php index 44dd1e5f47..aff58e2db0 100644 --- a/src/Plugins/Export/ExportMediawiki.php +++ b/src/Plugins/Export/ExportMediawiki.php @@ -92,17 +92,6 @@ class ExportMediawiki extends ExportPlugin return $exportPluginProperties; } - /** - * Outputs database header - * - * @param string $db Database name - * @param string $dbAlias Alias of db - */ - public function exportDBHeader(string $db, string $dbAlias = ''): bool - { - return true; - } - /** * Outputs database footer * diff --git a/src/Plugins/Export/ExportOds.php b/src/Plugins/Export/ExportOds.php index 0f44aaa604..630fadcbea 100644 --- a/src/Plugins/Export/ExportOds.php +++ b/src/Plugins/Export/ExportOds.php @@ -155,17 +155,6 @@ class ExportOds extends ExportPlugin ); } - /** - * Outputs database header - * - * @param string $db Database name - * @param string $dbAlias Aliases of db - */ - public function exportDBHeader(string $db, string $dbAlias = ''): bool - { - return true; - } - /** * Outputs database footer * diff --git a/src/Plugins/Export/ExportPdf.php b/src/Plugins/Export/ExportPdf.php index d10cf492d1..adb94dd87d 100644 --- a/src/Plugins/Export/ExportPdf.php +++ b/src/Plugins/Export/ExportPdf.php @@ -122,17 +122,6 @@ class ExportPdf extends ExportPlugin return $this->export->outputHandler($pdf->getPDFData()); } - /** - * Outputs database header - * - * @param string $db Database name - * @param string $dbAlias Aliases of db - */ - public function exportDBHeader(string $db, string $dbAlias = ''): bool - { - return true; - } - /** * Outputs database footer * diff --git a/src/Plugins/Export/ExportYaml.php b/src/Plugins/Export/ExportYaml.php index e12d8fae1b..e0b8b8d8d3 100644 --- a/src/Plugins/Export/ExportYaml.php +++ b/src/Plugins/Export/ExportYaml.php @@ -82,17 +82,6 @@ class ExportYaml extends ExportPlugin return true; } - /** - * Outputs database header - * - * @param string $db Database name - * @param string $dbAlias Aliases of db - */ - public function exportDBHeader(string $db, string $dbAlias = ''): bool - { - return true; - } - /** * Outputs database footer * diff --git a/src/Plugins/ExportPlugin.php b/src/Plugins/ExportPlugin.php index 6a3cfc0311..ae366b39de 100644 --- a/src/Plugins/ExportPlugin.php +++ b/src/Plugins/ExportPlugin.php @@ -66,7 +66,10 @@ abstract class ExportPlugin implements Plugin * @param string $db Database name * @param string $dbAlias Aliases of db */ - abstract public function exportDBHeader(string $db, string $dbAlias = ''): bool; + public function exportDBHeader(string $db, string $dbAlias = ''): bool + { + return true; + } /** * Outputs database footer From bcb8bd7c3eb29c9aedc73b4ded7ce743f95bb365 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Fri, 21 Nov 2025 21:51:19 +0000 Subject: [PATCH 04/21] Clean up exportDBFooter Signed-off-by: Kamil Tekiela --- src/Plugins/Export/ExportCodegen.php | 10 ---------- src/Plugins/Export/ExportCsv.php | 10 ---------- src/Plugins/Export/ExportExcel.php | 10 ---------- src/Plugins/Export/ExportHtmlword.php | 10 ---------- src/Plugins/Export/ExportJson.php | 10 ---------- src/Plugins/Export/ExportLatex.php | 10 ---------- src/Plugins/Export/ExportMediawiki.php | 10 ---------- src/Plugins/Export/ExportOds.php | 10 ---------- src/Plugins/Export/ExportOdt.php | 10 ---------- src/Plugins/Export/ExportPdf.php | 10 ---------- src/Plugins/Export/ExportPhparray.php | 10 ---------- src/Plugins/Export/ExportTexytext.php | 10 ---------- src/Plugins/Export/ExportYaml.php | 10 ---------- src/Plugins/ExportPlugin.php | 5 ++++- 14 files changed, 4 insertions(+), 131 deletions(-) diff --git a/src/Plugins/Export/ExportCodegen.php b/src/Plugins/Export/ExportCodegen.php index 98ebab5ea7..a4c9c0809e 100644 --- a/src/Plugins/Export/ExportCodegen.php +++ b/src/Plugins/Export/ExportCodegen.php @@ -82,16 +82,6 @@ class ExportCodegen extends ExportPlugin return $exportPluginProperties; } - /** - * Outputs database footer - * - * @param string $db Database name - */ - public function exportDBFooter(string $db): bool - { - return true; - } - /** * Outputs CREATE DATABASE statement * diff --git a/src/Plugins/Export/ExportCsv.php b/src/Plugins/Export/ExportCsv.php index 7b0810aff8..7c7a8f3968 100644 --- a/src/Plugins/Export/ExportCsv.php +++ b/src/Plugins/Export/ExportCsv.php @@ -122,16 +122,6 @@ class ExportCsv extends ExportPlugin $this->separator = str_replace('\\t', "\011", $this->separator); } - /** - * Outputs database footer - * - * @param string $db Database name - */ - public function exportDBFooter(string $db): bool - { - return true; - } - /** * Outputs CREATE DATABASE statement * diff --git a/src/Plugins/Export/ExportExcel.php b/src/Plugins/Export/ExportExcel.php index 81513ed653..a733a53ccf 100644 --- a/src/Plugins/Export/ExportExcel.php +++ b/src/Plugins/Export/ExportExcel.php @@ -119,16 +119,6 @@ class ExportExcel extends ExportPlugin $this->escaped = '"'; } - /** - * Outputs database footer - * - * @param string $db Database name - */ - public function exportDBFooter(string $db): bool - { - return true; - } - /** * Outputs CREATE DATABASE statement * diff --git a/src/Plugins/Export/ExportHtmlword.php b/src/Plugins/Export/ExportHtmlword.php index 0517b27d48..f871a18d38 100644 --- a/src/Plugins/Export/ExportHtmlword.php +++ b/src/Plugins/Export/ExportHtmlword.php @@ -147,16 +147,6 @@ class ExportHtmlword extends ExportPlugin ); } - /** - * Outputs database footer - * - * @param string $db Database name - */ - public function exportDBFooter(string $db): bool - { - return true; - } - /** * Outputs CREATE DATABASE statement * diff --git a/src/Plugins/Export/ExportJson.php b/src/Plugins/Export/ExportJson.php index 5586a632a8..b8486c59e8 100644 --- a/src/Plugins/Export/ExportJson.php +++ b/src/Plugins/Export/ExportJson.php @@ -147,16 +147,6 @@ class ExportJson extends ExportPlugin return $this->export->outputHandler($data . ',' . "\n"); } - /** - * Outputs database footer - * - * @param string $db Database name - */ - public function exportDBFooter(string $db): bool - { - return true; - } - /** * Outputs CREATE DATABASE statement * diff --git a/src/Plugins/Export/ExportLatex.php b/src/Plugins/Export/ExportLatex.php index 7deaab0a85..623e11e020 100644 --- a/src/Plugins/Export/ExportLatex.php +++ b/src/Plugins/Export/ExportLatex.php @@ -255,16 +255,6 @@ class ExportLatex extends ExportPlugin return $this->export->outputHandler($head); } - /** - * Outputs database footer - * - * @param string $db Database name - */ - public function exportDBFooter(string $db): bool - { - return true; - } - /** * Outputs CREATE DATABASE statement * diff --git a/src/Plugins/Export/ExportMediawiki.php b/src/Plugins/Export/ExportMediawiki.php index aff58e2db0..616e68e00d 100644 --- a/src/Plugins/Export/ExportMediawiki.php +++ b/src/Plugins/Export/ExportMediawiki.php @@ -92,16 +92,6 @@ class ExportMediawiki extends ExportPlugin return $exportPluginProperties; } - /** - * Outputs database footer - * - * @param string $db Database name - */ - public function exportDBFooter(string $db): bool - { - return true; - } - /** * Outputs CREATE DATABASE statement * diff --git a/src/Plugins/Export/ExportOds.php b/src/Plugins/Export/ExportOds.php index 630fadcbea..9a1702dffb 100644 --- a/src/Plugins/Export/ExportOds.php +++ b/src/Plugins/Export/ExportOds.php @@ -155,16 +155,6 @@ class ExportOds extends ExportPlugin ); } - /** - * Outputs database footer - * - * @param string $db Database name - */ - public function exportDBFooter(string $db): bool - { - return true; - } - /** * Outputs CREATE DATABASE statement * diff --git a/src/Plugins/Export/ExportOdt.php b/src/Plugins/Export/ExportOdt.php index 8a328f7b3a..d78f596f64 100644 --- a/src/Plugins/Export/ExportOdt.php +++ b/src/Plugins/Export/ExportOdt.php @@ -194,16 +194,6 @@ class ExportOdt extends ExportPlugin return true; } - /** - * Outputs database footer - * - * @param string $db Database name - */ - public function exportDBFooter(string $db): bool - { - return true; - } - /** * Outputs CREATE DATABASE statement * diff --git a/src/Plugins/Export/ExportPdf.php b/src/Plugins/Export/ExportPdf.php index adb94dd87d..148a6f44f6 100644 --- a/src/Plugins/Export/ExportPdf.php +++ b/src/Plugins/Export/ExportPdf.php @@ -122,16 +122,6 @@ class ExportPdf extends ExportPlugin return $this->export->outputHandler($pdf->getPDFData()); } - /** - * Outputs database footer - * - * @param string $db Database name - */ - public function exportDBFooter(string $db): bool - { - return true; - } - /** * Outputs CREATE DATABASE statement * diff --git a/src/Plugins/Export/ExportPhparray.php b/src/Plugins/Export/ExportPhparray.php index cb720b18fe..edcd4bb7ac 100644 --- a/src/Plugins/Export/ExportPhparray.php +++ b/src/Plugins/Export/ExportPhparray.php @@ -110,16 +110,6 @@ class ExportPhparray extends ExportPlugin return true; } - /** - * Outputs database footer - * - * @param string $db Database name - */ - public function exportDBFooter(string $db): bool - { - return true; - } - /** * Outputs CREATE DATABASE statement * diff --git a/src/Plugins/Export/ExportTexytext.php b/src/Plugins/Export/ExportTexytext.php index 2f68142d83..3351cefcc1 100644 --- a/src/Plugins/Export/ExportTexytext.php +++ b/src/Plugins/Export/ExportTexytext.php @@ -116,16 +116,6 @@ class ExportTexytext extends ExportPlugin ); } - /** - * Outputs database footer - * - * @param string $db Database name - */ - public function exportDBFooter(string $db): bool - { - return true; - } - /** * Outputs CREATE DATABASE statement * diff --git a/src/Plugins/Export/ExportYaml.php b/src/Plugins/Export/ExportYaml.php index e0b8b8d8d3..f4f780cefb 100644 --- a/src/Plugins/Export/ExportYaml.php +++ b/src/Plugins/Export/ExportYaml.php @@ -82,16 +82,6 @@ class ExportYaml extends ExportPlugin return true; } - /** - * Outputs database footer - * - * @param string $db Database name - */ - public function exportDBFooter(string $db): bool - { - return true; - } - /** * Outputs CREATE DATABASE statement * diff --git a/src/Plugins/ExportPlugin.php b/src/Plugins/ExportPlugin.php index ae366b39de..64b7d56346 100644 --- a/src/Plugins/ExportPlugin.php +++ b/src/Plugins/ExportPlugin.php @@ -76,7 +76,10 @@ abstract class ExportPlugin implements Plugin * * @param string $db Database name */ - abstract public function exportDBFooter(string $db): bool; + public function exportDBFooter(string $db): bool + { + return true; + } /** * Outputs CREATE DATABASE statement From 4bbbb95727c70126c67f61e7cefddaa9a22b1188 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Fri, 21 Nov 2025 21:53:09 +0000 Subject: [PATCH 05/21] Clean up exportDBCreate Signed-off-by: Kamil Tekiela --- src/Plugins/Export/ExportCodegen.php | 11 ----------- src/Plugins/Export/ExportCsv.php | 11 ----------- src/Plugins/Export/ExportExcel.php | 11 ----------- src/Plugins/Export/ExportHtmlword.php | 11 ----------- src/Plugins/Export/ExportJson.php | 11 ----------- src/Plugins/Export/ExportLatex.php | 11 ----------- src/Plugins/Export/ExportMediawiki.php | 11 ----------- src/Plugins/Export/ExportOds.php | 11 ----------- src/Plugins/Export/ExportOdt.php | 11 ----------- src/Plugins/Export/ExportPdf.php | 11 ----------- src/Plugins/Export/ExportPhparray.php | 11 ----------- src/Plugins/Export/ExportTexytext.php | 11 ----------- src/Plugins/Export/ExportXml.php | 11 ----------- src/Plugins/Export/ExportYaml.php | 11 ----------- src/Plugins/ExportPlugin.php | 5 ++++- 15 files changed, 4 insertions(+), 155 deletions(-) diff --git a/src/Plugins/Export/ExportCodegen.php b/src/Plugins/Export/ExportCodegen.php index a4c9c0809e..6bbdc27b38 100644 --- a/src/Plugins/Export/ExportCodegen.php +++ b/src/Plugins/Export/ExportCodegen.php @@ -82,17 +82,6 @@ class ExportCodegen extends ExportPlugin return $exportPluginProperties; } - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $dbAlias Aliases of db - */ - public function exportDBCreate(string $db, string $dbAlias = ''): bool - { - return true; - } - /** * Outputs the content of a table in NHibernate format * diff --git a/src/Plugins/Export/ExportCsv.php b/src/Plugins/Export/ExportCsv.php index 7c7a8f3968..f9fafda16a 100644 --- a/src/Plugins/Export/ExportCsv.php +++ b/src/Plugins/Export/ExportCsv.php @@ -122,17 +122,6 @@ class ExportCsv extends ExportPlugin $this->separator = str_replace('\\t', "\011", $this->separator); } - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $dbAlias Aliases of db - */ - public function exportDBCreate(string $db, string $dbAlias = ''): bool - { - return true; - } - /** * Outputs the content of a table in CSV format * diff --git a/src/Plugins/Export/ExportExcel.php b/src/Plugins/Export/ExportExcel.php index a733a53ccf..2dff18dc0a 100644 --- a/src/Plugins/Export/ExportExcel.php +++ b/src/Plugins/Export/ExportExcel.php @@ -119,17 +119,6 @@ class ExportExcel extends ExportPlugin $this->escaped = '"'; } - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $dbAlias Aliases of db - */ - public function exportDBCreate(string $db, string $dbAlias = ''): bool - { - return true; - } - /** * Outputs the content of a table in CSV format * diff --git a/src/Plugins/Export/ExportHtmlword.php b/src/Plugins/Export/ExportHtmlword.php index f871a18d38..68d4d1c529 100644 --- a/src/Plugins/Export/ExportHtmlword.php +++ b/src/Plugins/Export/ExportHtmlword.php @@ -147,17 +147,6 @@ class ExportHtmlword extends ExportPlugin ); } - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $dbAlias Aliases of db - */ - public function exportDBCreate(string $db, string $dbAlias = ''): bool - { - return true; - } - /** * Outputs the content of a table in HTML-Word format * diff --git a/src/Plugins/Export/ExportJson.php b/src/Plugins/Export/ExportJson.php index b8486c59e8..c41d8b5ff7 100644 --- a/src/Plugins/Export/ExportJson.php +++ b/src/Plugins/Export/ExportJson.php @@ -147,17 +147,6 @@ class ExportJson extends ExportPlugin return $this->export->outputHandler($data . ',' . "\n"); } - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $dbAlias Aliases of db - */ - public function exportDBCreate(string $db, string $dbAlias = ''): bool - { - return true; - } - /** * Outputs the content of a table in JSON format * diff --git a/src/Plugins/Export/ExportLatex.php b/src/Plugins/Export/ExportLatex.php index 623e11e020..6296769eee 100644 --- a/src/Plugins/Export/ExportLatex.php +++ b/src/Plugins/Export/ExportLatex.php @@ -255,17 +255,6 @@ class ExportLatex extends ExportPlugin return $this->export->outputHandler($head); } - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $dbAlias Aliases of db - */ - public function exportDBCreate(string $db, string $dbAlias = ''): bool - { - return true; - } - /** * Outputs the content of a table in JSON format * diff --git a/src/Plugins/Export/ExportMediawiki.php b/src/Plugins/Export/ExportMediawiki.php index 616e68e00d..38709bd7ef 100644 --- a/src/Plugins/Export/ExportMediawiki.php +++ b/src/Plugins/Export/ExportMediawiki.php @@ -92,17 +92,6 @@ class ExportMediawiki extends ExportPlugin return $exportPluginProperties; } - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $dbAlias Aliases of db - */ - public function exportDBCreate(string $db, string $dbAlias = ''): bool - { - return true; - } - /** * Outputs table's structure * diff --git a/src/Plugins/Export/ExportOds.php b/src/Plugins/Export/ExportOds.php index 9a1702dffb..f70c9d82cb 100644 --- a/src/Plugins/Export/ExportOds.php +++ b/src/Plugins/Export/ExportOds.php @@ -155,17 +155,6 @@ class ExportOds extends ExportPlugin ); } - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $dbAlias Aliases of db - */ - public function exportDBCreate(string $db, string $dbAlias = ''): bool - { - return true; - } - /** * Outputs the content of a table in NHibernate format * diff --git a/src/Plugins/Export/ExportOdt.php b/src/Plugins/Export/ExportOdt.php index d78f596f64..85f1a75d28 100644 --- a/src/Plugins/Export/ExportOdt.php +++ b/src/Plugins/Export/ExportOdt.php @@ -194,17 +194,6 @@ class ExportOdt extends ExportPlugin return true; } - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $dbAlias Aliases of db - */ - public function exportDBCreate(string $db, string $dbAlias = ''): bool - { - return true; - } - /** * Outputs the content of a table in NHibernate format * diff --git a/src/Plugins/Export/ExportPdf.php b/src/Plugins/Export/ExportPdf.php index 148a6f44f6..c5850cf609 100644 --- a/src/Plugins/Export/ExportPdf.php +++ b/src/Plugins/Export/ExportPdf.php @@ -122,17 +122,6 @@ class ExportPdf extends ExportPlugin return $this->export->outputHandler($pdf->getPDFData()); } - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $dbAlias Aliases of db - */ - public function exportDBCreate(string $db, string $dbAlias = ''): bool - { - return true; - } - /** * Outputs the content of a table in NHibernate format * diff --git a/src/Plugins/Export/ExportPhparray.php b/src/Plugins/Export/ExportPhparray.php index edcd4bb7ac..7078187c19 100644 --- a/src/Plugins/Export/ExportPhparray.php +++ b/src/Plugins/Export/ExportPhparray.php @@ -110,17 +110,6 @@ class ExportPhparray extends ExportPlugin return true; } - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $dbAlias Aliases of db - */ - public function exportDBCreate(string $db, string $dbAlias = ''): bool - { - return true; - } - /** * Outputs the content of a table in PHP array format * diff --git a/src/Plugins/Export/ExportTexytext.php b/src/Plugins/Export/ExportTexytext.php index 3351cefcc1..276bf7471e 100644 --- a/src/Plugins/Export/ExportTexytext.php +++ b/src/Plugins/Export/ExportTexytext.php @@ -116,17 +116,6 @@ class ExportTexytext extends ExportPlugin ); } - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $dbAlias Aliases of db - */ - public function exportDBCreate(string $db, string $dbAlias = ''): bool - { - return true; - } - /** * Outputs the content of a table in NHibernate format * diff --git a/src/Plugins/Export/ExportXml.php b/src/Plugins/Export/ExportXml.php index cd116c4c60..c4ab0b5a84 100644 --- a/src/Plugins/Export/ExportXml.php +++ b/src/Plugins/Export/ExportXml.php @@ -389,17 +389,6 @@ class ExportXml extends ExportPlugin return true; } - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $dbAlias Aliases of db - */ - public function exportDBCreate(string $db, string $dbAlias = ''): bool - { - return true; - } - /** * Outputs the content of a table in XML format * diff --git a/src/Plugins/Export/ExportYaml.php b/src/Plugins/Export/ExportYaml.php index f4f780cefb..8ae7dda0be 100644 --- a/src/Plugins/Export/ExportYaml.php +++ b/src/Plugins/Export/ExportYaml.php @@ -82,17 +82,6 @@ class ExportYaml extends ExportPlugin return true; } - /** - * Outputs CREATE DATABASE statement - * - * @param string $db Database name - * @param string $dbAlias Aliases of db - */ - public function exportDBCreate(string $db, string $dbAlias = ''): bool - { - return true; - } - /** * Outputs the content of a table in JSON format * diff --git a/src/Plugins/ExportPlugin.php b/src/Plugins/ExportPlugin.php index 64b7d56346..474f52f056 100644 --- a/src/Plugins/ExportPlugin.php +++ b/src/Plugins/ExportPlugin.php @@ -87,7 +87,10 @@ abstract class ExportPlugin implements Plugin * @param string $db Database name * @param string $dbAlias Aliases of db */ - abstract public function exportDBCreate(string $db, string $dbAlias = ''): bool; + public function exportDBCreate(string $db, string $dbAlias = ''): bool + { + return true; + } /** * Outputs the content of a table From 73f870ad4ac14bd56deec3aeb69c9f8f71c97496 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Fri, 21 Nov 2025 22:09:18 +0000 Subject: [PATCH 06/21] Clean up ExportPdf Signed-off-by: Kamil Tekiela --- src/Plugins/Export/ExportOds.php | 5 -- src/Plugins/Export/ExportOdt.php | 5 -- src/Plugins/Export/ExportPdf.php | 93 +++++++-------------- src/Plugins/ExportPlugin.php | 8 -- tests/unit/Plugins/Export/ExportPdfTest.php | 34 +------- 5 files changed, 34 insertions(+), 111 deletions(-) diff --git a/src/Plugins/Export/ExportOds.php b/src/Plugins/Export/ExportOds.php index f70c9d82cb..b51b68f69d 100644 --- a/src/Plugins/Export/ExportOds.php +++ b/src/Plugins/Export/ExportOds.php @@ -37,11 +37,6 @@ class ExportOds extends ExportPlugin private bool $columns = false; private string $null = ''; - protected function init(): void - { - $this->buffer = ''; - } - /** @psalm-return non-empty-lowercase-string */ public function getName(): string { diff --git a/src/Plugins/Export/ExportOdt.php b/src/Plugins/Export/ExportOdt.php index 85f1a75d28..e1842b1e18 100644 --- a/src/Plugins/Export/ExportOdt.php +++ b/src/Plugins/Export/ExportOdt.php @@ -43,11 +43,6 @@ class ExportOdt extends ExportPlugin private bool $doRelation = false; private string $null = ''; - protected function init(): void - { - $this->buffer = ''; - } - /** @psalm-return non-empty-lowercase-string */ public function getName(): string { diff --git a/src/Plugins/Export/ExportPdf.php b/src/Plugins/Export/ExportPdf.php index c5850cf609..55fefca1a8 100644 --- a/src/Plugins/Export/ExportPdf.php +++ b/src/Plugins/Export/ExportPdf.php @@ -45,18 +45,6 @@ class ExportPdf extends ExportPlugin return 'pdf'; } - /** - * Initialize the local variables that are used for export PDF. - */ - protected function init(): void - { - if (! empty($_POST['pdf_report_title'])) { - $this->pdfReportTitle = $_POST['pdf_report_title']; - } - - $this->setPdf(new Pdf('L', 'pt', 'A3')); - } - protected function setProperties(): ExportPluginProperties { $exportPluginProperties = new ExportPluginProperties(); @@ -103,12 +91,11 @@ class ExportPdf extends ExportPlugin private function setupExportConfiguration(): void { - $pdf = $this->getPdf(); - $pdf->Open(); + $this->pdf->Open(); - $pdf->setTitleFontSize(18); - $pdf->setTitleText($this->pdfReportTitle); - $pdf->setTopMargin(30); + $this->pdf->setTitleFontSize(18); + $this->pdf->setTitleText($this->pdfReportTitle); + $this->pdf->setTopMargin(30); } /** @@ -116,10 +103,8 @@ class ExportPdf extends ExportPlugin */ public function exportFooter(): bool { - $pdf = $this->getPdf(); - // instead of $pdf->Output(): - return $this->export->outputHandler($pdf->getPDFData()); + return $this->export->outputHandler($this->pdf->getPDFData()); } /** @@ -138,14 +123,13 @@ class ExportPdf extends ExportPlugin ): bool { $dbAlias = $this->getDbAlias($aliases, $db); $tableAlias = $this->getTableAlias($aliases, $db, $table); - $pdf = $this->getPdf(); - $pdf->setCurrentDb($db); - $pdf->setCurrentTable($table); - $pdf->setDbAlias($dbAlias); - $pdf->setTableAlias($tableAlias); - $pdf->setAliases($aliases); - $pdf->setPurpose(__('Dumping data')); - $pdf->mysqlReport($sqlQuery); + $this->pdf->setCurrentDb($db); + $this->pdf->setCurrentTable($table); + $this->pdf->setDbAlias($dbAlias); + $this->pdf->setTableAlias($tableAlias); + $this->pdf->setAliases($aliases); + $this->pdf->setPurpose(__('Dumping data')); + $this->pdf->mysqlReport($sqlQuery); return true; } @@ -158,17 +142,16 @@ class ExportPdf extends ExportPlugin */ public function exportRawQuery(string|null $db, string $sqlQuery): bool { - $pdf = $this->getPdf(); - $pdf->setDbAlias('----'); - $pdf->setTableAlias('----'); - $pdf->setPurpose(__('Query result data')); + $this->pdf->setDbAlias('----'); + $this->pdf->setTableAlias('----'); + $this->pdf->setPurpose(__('Query result data')); if ($db !== null) { - $pdf->setCurrentDb($db); + $this->pdf->setCurrentDb($db); DatabaseInterface::getInstance()->selectDb($db); } - $pdf->mysqlReport($sqlQuery); + $this->pdf->mysqlReport($sqlQuery); return true; } @@ -186,7 +169,6 @@ class ExportPdf extends ExportPlugin $purpose = ''; $dbAlias = $this->getDbAlias($aliases, $db); $tableAlias = $this->getTableAlias($aliases, $db, $table); - $pdf = $this->getPdf(); // getting purpose to show at top switch ($exportMode) { case 'create_table': @@ -202,42 +184,23 @@ class ExportPdf extends ExportPlugin $purpose = __('Stand in'); } - $pdf->setCurrentDb($db); - $pdf->setCurrentTable($table); - $pdf->setDbAlias($dbAlias); - $pdf->setTableAlias($tableAlias); - $pdf->setAliases($aliases); - $pdf->setPurpose($purpose); + $this->pdf->setCurrentDb($db); + $this->pdf->setCurrentTable($table); + $this->pdf->setDbAlias($dbAlias); + $this->pdf->setTableAlias($tableAlias); + $this->pdf->setAliases($aliases); + $this->pdf->setPurpose($purpose); match ($exportMode) { - 'create_table', 'create_view' => $pdf->getTableDef($db, $table, $this->doRelation, true, $this->doMime), - 'triggers' => $pdf->getTriggers($db, $table), + 'create_table', + 'create_view' => $this->pdf->getTableDef($db, $table, $this->doRelation, true, $this->doMime), + 'triggers' => $this->pdf->getTriggers($db, $table), default => true, }; return true; } - /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ - - /** - * Gets the PhpMyAdmin\Plugins\Export\Helpers\Pdf instance - */ - private function getPdf(): Pdf - { - return $this->pdf; - } - - /** - * Instantiates the PhpMyAdmin\Plugins\Export\Helpers\Pdf class - * - * @param Pdf $pdf The instance - */ - private function setPdf(Pdf $pdf): void - { - $this->pdf = $pdf; - } - public static function isAvailable(): bool { return class_exists(TCPDF::class) && extension_loaded('curl'); @@ -246,6 +209,10 @@ class ExportPdf extends ExportPlugin /** @inheritDoc */ public function setExportOptions(ServerRequest $request, array $exportConfig): void { + $this->pdfReportTitle = $request->getParsedBodyParam('pdf_report_title', ''); + + $this->pdf = new Pdf('L', 'pt', 'A3'); + $this->structureOrData = $this->setStructureOrData( $request->getParsedBodyParam('pdf_structure_or_data'), $exportConfig['pdf_structure_or_data'] ?? null, diff --git a/src/Plugins/ExportPlugin.php b/src/Plugins/ExportPlugin.php index 474f52f056..853a2824a9 100644 --- a/src/Plugins/ExportPlugin.php +++ b/src/Plugins/ExportPlugin.php @@ -40,7 +40,6 @@ abstract class ExportPlugin implements Plugin protected Export $export, public Transformations $transformations, ) { - $this->init(); $this->properties = $this->setProperties(); } @@ -186,13 +185,6 @@ abstract class ExportPlugin implements Plugin return ''; } - /** - * Plugin specific initializations. - */ - protected function init(): void - { - } - /** * Gets the export specific format plugin properties * diff --git a/tests/unit/Plugins/Export/ExportPdfTest.php b/tests/unit/Plugins/Export/ExportPdfTest.php index 0c07b34cc7..4f2a80b2ba 100644 --- a/tests/unit/Plugins/Export/ExportPdfTest.php +++ b/tests/unit/Plugins/Export/ExportPdfTest.php @@ -157,22 +157,13 @@ class ExportPdfTest extends AbstractTestCase public function testSetExportOptions(): void { - $pdf = $this->getMockBuilder(Pdf::class) - ->disableOriginalConstructor() - ->getMock(); - - $pdf->expects(self::once()) - ->method('Open'); - - $pdf->expects(self::once()) - ->method('setTopMargin'); - - $attrPdf = new ReflectionProperty(ExportPdf::class, 'pdf'); - $attrPdf->setValue($this->object, $pdf); - $request = ServerRequestFactory::create()->createServerRequest('POST', 'https://example.com/'); $this->object->setExportOptions($request, []); + + $attrPdf = new ReflectionProperty(ExportPdf::class, 'pdf'); + $pdf = $attrPdf->getValue($this->object); + self::assertInstanceOf(Pdf::class, $pdf); } public function testExportFooter(): void @@ -235,21 +226,4 @@ class ExportPdfTest extends AbstractTestCase ), ); } - - /** - * Test for - * - PhpMyAdmin\Plugins\Export\ExportPdf::setPdf - * - PhpMyAdmin\Plugins\Export\ExportPdf::getPdf - */ - public function testSetGetPdf(): void - { - $setter = new ReflectionMethod(ExportPdf::class, 'setPdf'); - $setter->invoke($this->object, new Pdf()); - - $getter = new ReflectionMethod(ExportPdf::class, 'getPdf'); - self::assertInstanceOf( - Pdf::class, - $getter->invoke($this->object), - ); - } } From 13b34aa4719ca26f0db3c2ef7fac4f0e47187a33 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Sat, 22 Nov 2025 00:05:02 +0000 Subject: [PATCH 07/21] OutputHandler Signed-off-by: Kamil Tekiela --- phpstan-baseline.neon | 56 +--- psalm-baseline.xml | 52 +--- src/Controllers/Export/ExportController.php | 93 ++---- src/Export/Export.php | 270 ++---------------- src/Export/OutputHandler.php | 257 +++++++++++++++++ src/Plugins/Export/ExportCodegen.php | 4 +- src/Plugins/Export/ExportCsv.php | 4 +- src/Plugins/Export/ExportExcel.php | 4 +- src/Plugins/Export/ExportHtmlword.php | 18 +- src/Plugins/Export/ExportJson.php | 16 +- src/Plugins/Export/ExportLatex.php | 26 +- src/Plugins/Export/ExportMediawiki.php | 4 +- src/Plugins/Export/ExportOds.php | 7 +- src/Plugins/Export/ExportOdt.php | 2 +- src/Plugins/Export/ExportPdf.php | 2 +- src/Plugins/Export/ExportPhparray.php | 10 +- src/Plugins/Export/ExportSql.php | 79 +++-- src/Plugins/Export/ExportTexytext.php | 10 +- src/Plugins/Export/ExportXml.php | 15 +- src/Plugins/Export/ExportYaml.php | 6 +- src/Table/TableMover.php | 7 +- tests/unit/Export/ExportTest.php | 9 +- .../unit/Plugins/Export/ExportCodegenTest.php | 7 +- tests/unit/Plugins/Export/ExportCsvTest.php | 24 +- tests/unit/Plugins/Export/ExportExcelTest.php | 23 +- .../Plugins/Export/ExportHtmlwordTest.php | 13 +- tests/unit/Plugins/Export/ExportJsonTest.php | 7 +- tests/unit/Plugins/Export/ExportLatexTest.php | 7 +- .../Plugins/Export/ExportMediawikiTest.php | 7 +- tests/unit/Plugins/Export/ExportOdsTest.php | 7 +- tests/unit/Plugins/Export/ExportOdtTest.php | 7 +- tests/unit/Plugins/Export/ExportPdfTest.php | 7 +- .../Plugins/Export/ExportPhparrayTest.php | 7 +- tests/unit/Plugins/Export/ExportSqlTest.php | 12 +- .../Plugins/Export/ExportTexytextTest.php | 6 +- tests/unit/Plugins/Export/ExportXmlTest.php | 12 +- tests/unit/Plugins/Export/ExportYamlTest.php | 6 +- 37 files changed, 464 insertions(+), 639 deletions(-) create mode 100644 src/Export/OutputHandler.php diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 8b1973b3b8..c2ae2c35c4 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -2181,30 +2181,12 @@ parameters: count: 1 path: src/Controllers/Export/ExportController.php - - - message: '#^Parameter \#1 \$fileHandle of method PhpMyAdmin\\Export\\Export\:\:closeFile\(\) expects resource, resource\|null given\.$#' - identifier: argument.type - count: 1 - path: src/Controllers/Export/ExportController.php - - message: '#^Parameter \#3 \$tableStructure of method PhpMyAdmin\\Export\\Export\:\:exportDatabase\(\) expects array\, array\ given\.$#' identifier: argument.type count: 2 path: src/Controllers/Export/ExportController.php - - - message: '#^Property PhpMyAdmin\\Export\\Export\:\:\$dumpBuffer \(string\) does not accept array\|bool\|string\.$#' - identifier: assign.propertyType - count: 2 - path: src/Controllers/Export/ExportController.php - - - - message: '#^Static property PhpMyAdmin\\Export\\Export\:\:\$compression \(''''\|''gzip''\|''none''\|''zip''\) does not accept string\.$#' - identifier: assign.propertyType - count: 1 - path: src/Controllers/Export/ExportController.php - - message: '#^Static property PhpMyAdmin\\Export\\Export\:\:\$tableData \(array\\) does not accept array\\.$#' identifier: assign.propertyType @@ -6165,30 +6147,12 @@ parameters: count: 4 path: src/Export/Export.php - - - message: '#^Method PhpMyAdmin\\Export\\Export\:\:compress\(\) return type has no value type specified in iterable type array\.$#' - identifier: missingType.iterableValue - count: 1 - path: src/Export/Export.php - - - - message: '#^Only booleans are allowed in a negated boolean, string\|false given\.$#' - identifier: booleanNot.exprNotBoolean - count: 1 - path: src/Export/Export.php - - message: '#^Parameter \#1 \$identifier of static method PhpMyAdmin\\Util\:\:backquote\(\) expects string\|Stringable\|null, mixed given\.$#' identifier: argument.type count: 1 path: src/Export/Export.php - - - message: '#^Parameter \#1 \$stream of function fwrite expects resource, resource\|null given\.$#' - identifier: argument.type - count: 1 - path: src/Export/Export.php - - message: '#^Parameter \#2 \$dbAlias of method PhpMyAdmin\\Plugins\\ExportPlugin\:\:exportDBCreate\(\) expects string, mixed given\.$#' identifier: argument.type @@ -6261,6 +6225,18 @@ parameters: count: 1 path: src/Export/Options.php + - + message: '#^Only booleans are allowed in a negated boolean, string\|false given\.$#' + identifier: booleanNot.exprNotBoolean + count: 1 + path: src/Export/OutputHandler.php + + - + message: '#^Property PhpMyAdmin\\Export\\OutputHandler\:\:\$dumpBuffer \(string\) does not accept string\|false\.$#' + identifier: assign.propertyType + count: 2 + path: src/Export/OutputHandler.php + - message: '#^Parameter \#1 \$id of class PhpMyAdmin\\Export\\Template constructor expects int, mixed given\.$#' identifier: argument.type @@ -9460,13 +9436,7 @@ parameters: path: src/Plugins/Export/ExportPdf.php - - message: '#^Construct empty\(\) is not allowed\. Use more strict comparison\.$#' - identifier: empty.notAllowed - count: 1 - path: src/Plugins/Export/ExportPdf.php - - - - message: '#^Parameter \#1 \$line of method PhpMyAdmin\\Export\\Export\:\:outputHandler\(\) expects string, mixed given\.$#' + message: '#^Parameter \#1 \$line of callable PhpMyAdmin\\Export\\OutputHandler expects string, mixed given\.$#' identifier: argument.type count: 1 path: src/Plugins/Export/ExportPdf.php diff --git a/psalm-baseline.xml b/psalm-baseline.xml index a0d1a6fde9..2ae66f41a5 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1275,32 +1275,6 @@ - - export->dumpBuffer]]> - export->dumpBuffer]]> - - - export->dumpBuffer]]> - export->dumpBuffer]]> - - - export->compress( - $this->export->dumpBuffer, - Export::$compression, - $filename, - )]]> - export->compress( - $this->export->dumpBufferObjects, - Export::$compression, - $filename, - )]]> - - - - - - getParsedBodyParamAsString('compression')]]> - @@ -4186,14 +4160,10 @@ - - - - @@ -4221,6 +4191,17 @@ settings['SaveDir'])]]> + + + fileHandle]]> + + + createFile($dumpBuffer, $filename)]]> + + + + + @@ -6161,17 +6142,14 @@ - getPDFData()]]> + pdf->getPDFData()]]> - - - + + pdfReportTitle]]> + - - - diff --git a/src/Controllers/Export/ExportController.php b/src/Controllers/Export/ExportController.php index f0c64b575e..24eaa90855 100644 --- a/src/Controllers/Export/ExportController.php +++ b/src/Controllers/Export/ExportController.php @@ -13,6 +13,7 @@ use PhpMyAdmin\Current; use PhpMyAdmin\Encoding; use PhpMyAdmin\Exceptions\ExportException; use PhpMyAdmin\Export\Export; +use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Http\Factory\ResponseFactory; use PhpMyAdmin\Http\Response; use PhpMyAdmin\Http\ServerRequest; @@ -76,12 +77,8 @@ final readonly class ExportController implements InvocableController Current::$charset = $request->getParsedBodyParamAsString('charset'); } - if ($request->hasBodyParam('compression')) { - Export::$compression = $request->getParsedBodyParamAsString('compression'); - } - if ($request->hasBodyParam('knjenc')) { - Export::$kanjiEncoding = $request->getParsedBodyParamAsString('knjenc'); + $this->export->outputHandler->kanjiEncoding = $request->getParsedBodyParamAsString('knjenc'); } if ($request->hasBodyParam('maxsize')) { @@ -99,7 +96,7 @@ final readonly class ExportController implements InvocableController } if ($request->hasBodyParam('xkana')) { - Export::$xkana = $request->getParsedBodyParamAsString('xkana'); + $this->export->outputHandler->xkana = $request->getParsedBodyParamAsString('xkana'); } // sanitize this parameter which will be used below in a file inclusion @@ -138,11 +135,6 @@ final readonly class ExportController implements InvocableController /** * init and variable checking */ - Export::$compression = ''; - Export::$saveOnServer = false; - Export::$bufferNeeded = false; - Export::$saveFilename = ''; - Export::$fileHandle = null; $filename = ''; $separateFiles = ''; @@ -150,21 +142,21 @@ final readonly class ExportController implements InvocableController $isQuickExport = $quickOrCustom === 'quick'; if ($outputFormat === 'astext') { - Export::$asFile = false; + OutputHandler::$asFile = false; } else { - Export::$asFile = true; + OutputHandler::$asFile = true; if ($asSeparateFiles && $compressionParam === 'zip') { $separateFiles = $asSeparateFiles; } if (in_array($compressionParam, $compressionMethods, true)) { - Export::$compression = $compressionParam; - Export::$bufferNeeded = true; + $this->export->outputHandler->compression = $compressionParam; + $this->export->outputHandler->bufferNeeded = true; } if (($isQuickExport && $quickExportOnServer) || (! $isQuickExport && $onServerParam)) { // Will we save dump on server? - Export::$saveOnServer = $this->config->settings['SaveDir'] !== ''; + $this->export->outputHandler->saveOnServer = $this->config->settings['SaveDir'] !== ''; } } @@ -212,33 +204,27 @@ final readonly class ExportController implements InvocableController } register_shutdown_function([$this->export, 'shutdown']); - // Start with empty buffer - $this->export->dumpBuffer = ''; - $this->export->dumpBufferLength = 0; - - // Array of dump buffers - used in separate file exports - $this->export->dumpBufferObjects = []; // We send fake headers to avoid browser timeout when buffering - Export::$timeStart = time(); + $this->export->outputHandler->timeStart = time(); - Export::$outputKanjiConversion = Encoding::canConvertKanji(); + $this->export->outputHandler->outputKanjiConversion = Encoding::canConvertKanji(); // Do we need to convert charset? - Export::$outputCharsetConversion = Export::$asFile + $this->export->outputHandler->outputCharsetConversion = OutputHandler::$asFile && Encoding::isSupported() && isset(Current::$charset) && Current::$charset !== 'utf-8' && in_array(Current::$charset, Encoding::listEncodings(), true); // Use on the fly compression? - Export::$onFlyCompression = $this->config->settings['CompressOnFly'] && Export::$compression === 'gzip'; - if (Export::$onFlyCompression) { - Export::$memoryLimit = $this->export->getMemoryLimit(); + $this->export->outputHandler->onFlyCompression = $this->config->settings['CompressOnFly'] && ($this->export->outputHandler)->compression === 'gzip'; + if ($this->export->outputHandler->onFlyCompression) { + $this->export->outputHandler->memoryLimit = $this->export->getMemoryLimit(); } // Generate filename and mime type if needed $mimeType = ''; - if (Export::$asFile) { + if (OutputHandler::$asFile) { $filenameTemplate = $request->getParsedBodyParamAsString('filename_template', ''); if ((bool) $rememberTemplate) { @@ -247,21 +233,21 @@ final readonly class ExportController implements InvocableController $filename = $this->export->getFinalFilename( $exportPlugin, - Export::$compression, + $this->export->outputHandler->compression, Sanitize::sanitizeFilename(Util::expandUserString($filenameTemplate), true), ); - $mimeType = $this->export->getMimeType($exportPlugin, Export::$compression); + $mimeType = $this->export->getMimeType($exportPlugin, $this->export->outputHandler->compression); } // For raw query export, filename will be export.extension if ($exportType === ExportType::Raw) { - $filename = $this->export->getFinalFilename($exportPlugin, Export::$compression, 'export'); + $filename = $this->export->getFinalFilename($exportPlugin, $this->export->outputHandler->compression, 'export'); } // Open file on server if needed - if (Export::$saveOnServer) { - [Export::$saveFilename, $message, Export::$fileHandle] = $this->export->openFile($filename, $isQuickExport); + if ($this->export->outputHandler->saveOnServer) { + $message = $this->export->openFile($filename, $isQuickExport); // problem opening export file on server? if ($message !== null) { @@ -270,7 +256,7 @@ final readonly class ExportController implements InvocableController return $this->response->response(); } - } elseif (Export::$asFile) { + } elseif (OutputHandler::$asFile) { /** * Send headers depending on whether the user chose to download a dump file * or not @@ -300,8 +286,7 @@ final readonly class ExportController implements InvocableController try { // Re - initialize - $this->export->dumpBuffer = ''; - $this->export->dumpBufferLength = 0; + $this->export->outputHandler->clearBuffer(); // TODO: This is a temporary hack to avoid GLOBALS. Replace this with something better. if ($exportPlugin instanceof ExportXml) { @@ -404,7 +389,7 @@ final readonly class ExportController implements InvocableController // Ignore } - if (Export::$saveOnServer && Current::$message !== null) { + if ($this->export->outputHandler->saveOnServer && Current::$message !== null) { $location = $this->export->getPageLocationAndSaveMessage($exportType, Current::$message); $this->response->redirect($location); @@ -414,47 +399,27 @@ final readonly class ExportController implements InvocableController /** * Send the dump as a file... */ - if (! Export::$asFile) { + if (! OutputHandler::$asFile) { echo $this->export->getHtmlForDisplayedExportFooter($exportType, Current::$database, Current::$table); return $this->response->response(); } // Convert the charset if required. - if (Export::$outputCharsetConversion) { - $this->export->dumpBuffer = Encoding::convertString( - 'utf-8', - Current::$charset ?? 'utf-8', - $this->export->dumpBuffer, - ); - } + ($this->export->outputHandler)->convertBufferCharset(); // Compression needed? - if (Export::$compression !== '') { - if ($separateFiles !== '') { - $this->export->dumpBuffer = $this->export->compress( - $this->export->dumpBufferObjects, - Export::$compression, - $filename, - ); - } else { - $this->export->dumpBuffer = $this->export->compress( - $this->export->dumpBuffer, - Export::$compression, - $filename, - ); - } - } + $this->export->outputHandler->compress($separateFiles !== '', $filename); /* If we saved on server, we have to close file now */ - if (Export::$saveOnServer) { - $message = $this->export->closeFile(Export::$fileHandle, $this->export->dumpBuffer, Export::$saveFilename); + if ($this->export->outputHandler->saveOnServer) { + $message = $this->export->outputHandler->closeFile(); $location = $this->export->getPageLocationAndSaveMessage($exportType, $message); $this->response->redirect($location); return $this->response->response(); } - return $this->responseFactory->createResponse()->write($this->export->dumpBuffer); + return $this->responseFactory->createResponse()->write($this->export->outputHandler->getBuffer()); } } diff --git a/src/Export/Export.php b/src/Export/Export.php index a51ac386a2..a232df8e67 100644 --- a/src/Export/Export.php +++ b/src/Export/Export.php @@ -9,15 +9,12 @@ namespace PhpMyAdmin\Export; use PhpMyAdmin\Config; use PhpMyAdmin\ConfigStorage\RelationParameters; -use PhpMyAdmin\Core; use PhpMyAdmin\Current; use PhpMyAdmin\Dbal\DatabaseInterface; -use PhpMyAdmin\Encoding; use PhpMyAdmin\Exceptions\ExportException; use PhpMyAdmin\FlashMessenger; use PhpMyAdmin\Identifiers\DatabaseName; use PhpMyAdmin\Message; -use PhpMyAdmin\MessageType; use PhpMyAdmin\Plugins; use PhpMyAdmin\Plugins\Export\ExportSql; use PhpMyAdmin\Plugins\ExportPlugin; @@ -26,22 +23,14 @@ use PhpMyAdmin\Plugins\SchemaPlugin; use PhpMyAdmin\Table\Table; use PhpMyAdmin\Url; use PhpMyAdmin\Util; -use PhpMyAdmin\Utils\UserAgentParser; -use PhpMyAdmin\ZipExtension; use function __; use function array_filter; use function array_merge_recursive; use function error_get_last; -use function fclose; use function file_exists; use function fopen; -use function function_exists; -use function fwrite; -use function gzencode; -use function header; use function htmlentities; -use function htmlspecialchars; use function http_build_query; use function implode; use function in_array; @@ -50,57 +39,30 @@ use function ini_parse_quantity; use function is_array; use function is_file; use function is_numeric; -use function is_string; use function is_writable; use function mb_strlen; use function mb_strtolower; use function mb_substr; -use function ob_list_handlers; use function preg_match; use function preg_replace; use function str_contains; -use function strlen; -use function substr; -use function time; - -use const ENT_COMPAT; /** * PhpMyAdmin\Export\Export class */ class Export { - public string $dumpBuffer = ''; - - public int $dumpBufferLength = 0; - - /** @var string[] */ - public array $dumpBufferObjects = []; - - public static bool $asFile = false; - public static bool $saveOnServer = false; - public static bool $outputCharsetConversion = false; - public static bool $outputKanjiConversion = false; - public static bool $bufferNeeded = false; public static bool $singleTable = false; - /** @var ''|'none'|'zip'|'gzip' */ - public static string $compression = ''; - - /** @var resource|null */ - public static mixed $fileHandle = null; - public static string $kanjiEncoding = ''; - public static string $xkana = ''; public static string $maxSize = ''; - public static int $memoryLimit = 0; - public static bool $onFlyCompression = false; /** @var array */ public static array $tableData = []; - public static string $saveFilename = ''; - public static int $timeStart = 0; + + public OutputHandler $outputHandler; public function __construct(private DatabaseInterface $dbi) { + $this->outputHandler = new OutputHandler(); } /** @@ -117,131 +79,6 @@ class Export $_SESSION['pma_export_error'] = $error['message']; } - /** - * Detect ob_gzhandler - */ - public function isGzHandlerEnabled(): bool - { - /** @var string[] $handlers */ - $handlers = ob_list_handlers(); - - return in_array('ob_gzhandler', $handlers, true); - } - - /** - * Detect whether gzencode is needed; it might not be needed if - * the server is already compressing by itself - */ - public function gzencodeNeeded(): bool - { - /** - * We should gzencode only if the function exists - * but we don't want to compress twice, therefore - * gzencode only if transparent compression is not enabled - * but transparent compression does not apply when saving to server - */ - return function_exists('gzencode') - && ((! ini_get('zlib.output_compression') - && ! $this->isGzHandlerEnabled()) - || self::$saveOnServer - || (new UserAgentParser(Core::getEnv('HTTP_USER_AGENT')))->getUserBrowserAgent() === 'CHROME'); - } - - /** - * Output handler for all exports, if needed buffering, it stores data into - * $this->dumpBuffer, otherwise it prints them out. - * - * @param string $line the insert statement - */ - public function outputHandler(string $line): bool - { - // Kanji encoding convert feature - if (self::$outputKanjiConversion) { - $line = Encoding::kanjiStrConv($line, self::$kanjiEncoding, self::$xkana); - } - - // If we have to buffer data, we will perform everything at once at the end - if (self::$bufferNeeded) { - $this->dumpBuffer .= $line; - if (self::$onFlyCompression) { - $this->dumpBufferLength += strlen($line); - - if ($this->dumpBufferLength > self::$memoryLimit) { - if (self::$outputCharsetConversion) { - $this->dumpBuffer = Encoding::convertString( - 'utf-8', - Current::$charset ?? 'utf-8', - $this->dumpBuffer, - ); - } - - if (self::$compression === 'gzip' && $this->gzencodeNeeded()) { - // as a gzipped file - // without the optional parameter level because it bugs - $this->dumpBuffer = (string) gzencode($this->dumpBuffer); - } - - if (self::$saveOnServer) { - $writeResult = @fwrite(self::$fileHandle, $this->dumpBuffer); - // Here, use strlen rather than mb_strlen to get the length - // in bytes to compare against the number of bytes written. - if ($writeResult === false || $writeResult !== strlen($this->dumpBuffer)) { - Current::$message = Message::error( - __('Insufficient space to save the file %s.'), - ); - Current::$message->addParam(self::$saveFilename); - - return false; - } - } else { - echo $this->dumpBuffer; - } - - $this->dumpBuffer = ''; - $this->dumpBufferLength = 0; - } - } else { - $timeNow = time(); - if (self::$timeStart >= $timeNow + 30) { - self::$timeStart = $timeNow; - header('X-pmaPing: Pong'); - } - } - } elseif (self::$asFile) { - if (self::$outputCharsetConversion) { - $line = Encoding::convertString('utf-8', Current::$charset ?? 'utf-8', $line); - } - - if (self::$saveOnServer && $line !== '') { - $writeResult = self::$fileHandle !== null ? @fwrite(self::$fileHandle, $line) : false; - // Here, use strlen rather than mb_strlen to get the length - // in bytes to compare against the number of bytes written. - if ($writeResult === 0 || $writeResult === false || $writeResult !== strlen($line)) { - Current::$message = Message::error( - __('Insufficient space to save the file %s.'), - ); - Current::$message->addParam(self::$saveFilename); - - return false; - } - - $timeNow = time(); - if (self::$timeStart >= $timeNow + 30) { - self::$timeStart = $timeNow; - header('X-pmaPing: Pong'); - } - } else { - // We export as file - output normally - echo $line; - } - } else { - // We export as html - replace special chars - echo htmlspecialchars($line, ENT_COMPAT); - } - - return true; - } - /** * Returns HTML containing the footer for a displayed export * @@ -355,10 +192,8 @@ class Export * * @param string $filename the export filename * @param bool $quickExport whether it's a quick export or not - * - * @psalm-return array{string, Message|null, resource|null} */ - public function openFile(string $filename, bool $quickExport): array + public function openFile(string $filename, bool $quickExport): Message|null { $fileHandle = null; $message = null; @@ -403,83 +238,10 @@ class Export } } - return [$saveFilename, $message, $fileHandle]; - } + $this->outputHandler->saveFilename = $saveFilename; + $this->outputHandler->fileHandle = $fileHandle; - /** - * Close the export file - * - * @param resource $fileHandle the export file handle - * @param string $dumpBuffer the current dump buffer - * @param string $saveFilename the export filename - * - * @return Message a message object (or empty string) - */ - public function closeFile( - $fileHandle, - string $dumpBuffer, - string $saveFilename, - ): Message { - $writeResult = @fwrite($fileHandle, $dumpBuffer); - fclose($fileHandle); - // Here, use strlen rather than mb_strlen to get the length - // in bytes to compare against the number of bytes written. - if ($dumpBuffer !== '' && $writeResult !== strlen($dumpBuffer)) { - return new Message( - __('Insufficient space to save the file %s.'), - MessageType::Error, - [$saveFilename], - ); - } - - return new Message( - __('Dump has been saved to file %s.'), - MessageType::Success, - [$saveFilename], - ); - } - - /** - * Compress the export buffer - * - * @param string[]|string $dumpBuffer the current dump buffer - * @param string $compression the compression mode - * @param string $filename the filename - */ - public function compress(array|string $dumpBuffer, string $compression, string $filename): array|string|bool - { - if ($compression === 'zip' && function_exists('gzcompress')) { - $zipExtension = new ZipExtension(); - $filename = substr($filename, 0, -4); // remove extension (.zip) - $dumpBuffer = $zipExtension->createFile($dumpBuffer, $filename); - } elseif ($compression === 'gzip' && $this->gzencodeNeeded() && is_string($dumpBuffer)) { - // without the optional parameter level because it bugs - $dumpBuffer = gzencode($dumpBuffer); - } - - return $dumpBuffer; - } - - /** - * Saves the dump buffer for a particular table in an array - * Used in separate files export - * - * @param string $objectName the name of current object to be stored - * @param bool $append optional boolean to append to an existing index or not - */ - public function saveObjectInBuffer(string $objectName, bool $append = false): void - { - if ($this->dumpBuffer !== '') { - if ($append && isset($this->dumpBufferObjects[$objectName])) { - $this->dumpBufferObjects[$objectName] .= $this->dumpBuffer; - } else { - $this->dumpBufferObjects[$objectName] = $this->dumpBuffer; - } - } - - // Re - initialize - $this->dumpBuffer = ''; - $this->dumpBufferLength = 0; + return $message; } /** @@ -550,7 +312,7 @@ class Export continue; } - $this->saveObjectInBuffer($currentDb); + $this->outputHandler->saveObjectInBuffer($currentDb); } } @@ -586,7 +348,7 @@ class Export } if ($separateFiles === 'database') { - $this->saveObjectInBuffer('database', true); + $this->outputHandler->saveObjectInBuffer('database', true); } $structureOrData = $exportPlugin->getStructureOrData(); @@ -599,7 +361,7 @@ class Export $exportPlugin->exportRoutines($db->getName(), $aliases); if ($separateFiles === 'database') { - $this->saveObjectInBuffer('routines'); + $this->outputHandler->saveObjectInBuffer('routines'); } } @@ -673,7 +435,7 @@ class Export // this buffer was filled, we save it and go to the next one if ($separateFiles === 'database') { - $this->saveObjectInBuffer('table_' . $table); + $this->outputHandler->saveObjectInBuffer('table_' . $table); } // now export the triggers (needs to be done after the data because @@ -694,7 +456,7 @@ class Export continue; } - $this->saveObjectInBuffer('table_' . $table, true); + $this->outputHandler->saveObjectInBuffer('table_' . $table, true); } if ($exportPlugin instanceof ExportSql && $exportPlugin->hasCreateView()) { @@ -712,7 +474,7 @@ class Export continue; } - $this->saveObjectInBuffer('view_' . $view); + $this->outputHandler->saveObjectInBuffer('view_' . $view); } } @@ -728,12 +490,12 @@ class Export $exportPlugin->exportMetadata($db->getName(), $tables, $metadataTypes); if ($separateFiles === 'database') { - $this->saveObjectInBuffer('metadata'); + $this->outputHandler->saveObjectInBuffer('metadata'); } } if ($separateFiles === 'database') { - $this->saveObjectInBuffer('extra'); + $this->outputHandler->saveObjectInBuffer('extra'); } if ( @@ -750,7 +512,7 @@ class Export return; } - $this->saveObjectInBuffer('events'); + $this->outputHandler->saveObjectInBuffer('events'); } /** diff --git a/src/Export/OutputHandler.php b/src/Export/OutputHandler.php new file mode 100644 index 0000000000..5ea6ddd323 --- /dev/null +++ b/src/Export/OutputHandler.php @@ -0,0 +1,257 @@ +outputKanjiConversion) { + $line = Encoding::kanjiStrConv($line, $this->kanjiEncoding, $this->xkana); + } + + // If we have to buffer data, we will perform everything at once at the end + if ($this->bufferNeeded) { + $this->dumpBuffer .= $line; + if ($this->onFlyCompression) { + $this->dumpBufferLength += strlen($line); + + if ($this->dumpBufferLength > $this->memoryLimit) { + if ($this->outputCharsetConversion) { + $this->dumpBuffer = Encoding::convertString( + 'utf-8', + Current::$charset ?? 'utf-8', + $this->dumpBuffer, + ); + } + + if ($this->compression === 'gzip' && $this->gzencodeNeeded()) { + // as a gzipped file + // without the optional parameter level because it bugs + $this->dumpBuffer = (string) gzencode($this->dumpBuffer); + } + + if ($this->saveOnServer && $this->fileHandle !== null) { + $writeResult = @fwrite($this->fileHandle, $this->dumpBuffer); + // Here, use strlen rather than mb_strlen to get the length + // in bytes to compare against the number of bytes written. + if ($writeResult !== strlen($this->dumpBuffer)) { + Current::$message = Message::error( + __('Insufficient space to save the file %s.'), + ); + Current::$message->addParam($this->saveFilename); + + return false; + } + } else { + echo $this->dumpBuffer; + } + + $this->dumpBuffer = ''; + $this->dumpBufferLength = 0; + } + } else { + $timeNow = time(); + if ($this->timeStart >= $timeNow + 30) { + $this->timeStart = $timeNow; + header('X-pmaPing: Pong'); + } + } + } elseif (self::$asFile) { + if ($this->outputCharsetConversion) { + $line = Encoding::convertString('utf-8', Current::$charset ?? 'utf-8', $line); + } + + if ($this->saveOnServer && $this->fileHandle !== null && $line !== '') { + $writeResult = @fwrite($this->fileHandle, $line); + // Here, use strlen rather than mb_strlen to get the length + // in bytes to compare against the number of bytes written. + if ($writeResult !== strlen($line)) { + Current::$message = Message::error( + __('Insufficient space to save the file %s.'), + ); + Current::$message->addParam($this->saveFilename); + + return false; + } + + $timeNow = time(); + if ($this->timeStart >= $timeNow + 30) { + $this->timeStart = $timeNow; + header('X-pmaPing: Pong'); + } + } else { + // We export as file - output normally + echo $line; + } + } else { + // We export as html - replace special chars + echo htmlspecialchars($line, ENT_COMPAT); + } + + return true; + } + + /** + * Saves the dump buffer for a particular table in an array + * Used in separate files export + * + * @param string $objectName the name of current object to be stored + * @param bool $append optional boolean to append to an existing index or not + */ + public function saveObjectInBuffer(string $objectName, bool $append = false): void + { + if ($this->dumpBuffer !== '') { + if ($append && isset($this->dumpBufferObjects[$objectName])) { + $this->dumpBufferObjects[$objectName] .= $this->dumpBuffer; + } else { + $this->dumpBufferObjects[$objectName] = $this->dumpBuffer; + } + } + + // Re - initialize + $this->dumpBuffer = ''; + $this->dumpBufferLength = 0; + } + + public function compress(bool $separateFiles, string $filename): void + { + $dumpBuffer = $separateFiles + ? $this->dumpBufferObjects + : $this->dumpBuffer; + if ($this->compression === 'zip' && function_exists('gzcompress')) { + $zipExtension = new ZipExtension(); + $filename = substr($filename, 0, -4); // remove extension (.zip) + $this->dumpBuffer = $zipExtension->createFile($dumpBuffer, $filename); + } elseif ($this->compression === 'gzip' && $this->gzencodeNeeded() && is_string($dumpBuffer)) { + // without the optional parameter level because it bugs + $this->dumpBuffer = gzencode($dumpBuffer); + } + } + + public function closeFile(): Message + { + $writeResult = false; + if ($this->fileHandle !== null) { + $writeResult = @fwrite($this->fileHandle, $this->dumpBuffer); + fclose($this->fileHandle); + $this->fileHandle = null; + } + + // Here, use strlen rather than mb_strlen to get the length + // in bytes to compare against the number of bytes written. + if ($this->dumpBuffer !== '' && $writeResult !== strlen($this->dumpBuffer)) { + return new Message( + __('Insufficient space to save the file %s.'), + MessageType::Error, + [$this->saveFilename], + ); + } + + return new Message( + __('Dump has been saved to file %s.'), + MessageType::Success, + [$this->saveFilename], + ); + } + + public function clearBuffer(): void + { + $this->dumpBuffer = ''; + $this->dumpBufferLength = 0; + } + + public function getBuffer(): string + { + return $this->dumpBuffer; + } + + public function convertBufferCharset(): void + { + if (! $this->outputCharsetConversion || $this->dumpBuffer === '') { + return; + } + + $this->dumpBuffer = Encoding::convertString('utf-8', Current::$charset ?? 'utf-8', $this->dumpBuffer); + } + + /** + * Detect whether gzencode is needed; it might not be needed if + * the server is already compressing by itself + */ + private function gzencodeNeeded(): bool + { + /** + * We should gzencode only if the function exists + * but we don't want to compress twice, therefore + * gzencode only if transparent compression is not enabled + * but transparent compression does not apply when saving to server + */ + return function_exists('gzencode') + && ((! ini_get('zlib.output_compression') + && ! $this->isGzHandlerEnabled()) + || $this->saveOnServer + || (new UserAgentParser(Core::getEnv('HTTP_USER_AGENT')))->getUserBrowserAgent() === 'CHROME'); + } + + /** + * Detect ob_gzhandler + */ + private function isGzHandlerEnabled(): bool + { + /** @var string[] $handlers */ + $handlers = ob_list_handlers(); + + return in_array('ob_gzhandler', $handlers, true); + } +} diff --git a/src/Plugins/Export/ExportCodegen.php b/src/Plugins/Export/ExportCodegen.php index 6bbdc27b38..c5f5898c33 100644 --- a/src/Plugins/Export/ExportCodegen.php +++ b/src/Plugins/Export/ExportCodegen.php @@ -97,10 +97,10 @@ class ExportCodegen extends ExportPlugin array $aliases = [], ): bool { if ($this->format === self::HANDLER_NHIBERNATE_XML) { - return $this->export->outputHandler($this->handleNHibernateXMLBody($db, $table, $aliases)); + return ($this->export->outputHandler)($this->handleNHibernateXMLBody($db, $table, $aliases)); } - return $this->export->outputHandler($this->handleNHibernateCSBody($db, $table, $aliases)); + return ($this->export->outputHandler)($this->handleNHibernateCSBody($db, $table, $aliases)); } /** diff --git a/src/Plugins/Export/ExportCsv.php b/src/Plugins/Export/ExportCsv.php index f9fafda16a..89309c314f 100644 --- a/src/Plugins/Export/ExportCsv.php +++ b/src/Plugins/Export/ExportCsv.php @@ -164,7 +164,7 @@ class ExportCsv extends ExportPlugin } $schemaInsert = implode($this->separator, $insertFields); - if (! $this->export->outputHandler($schemaInsert . $this->terminated)) { + if (! ($this->export->outputHandler)($schemaInsert . $this->terminated)) { return false; } } @@ -218,7 +218,7 @@ class ExportCsv extends ExportPlugin } $schemaInsert = implode($this->separator, $insertValues); - if (! $this->export->outputHandler($schemaInsert . $this->terminated)) { + if (! ($this->export->outputHandler)($schemaInsert . $this->terminated)) { return false; } } diff --git a/src/Plugins/Export/ExportExcel.php b/src/Plugins/Export/ExportExcel.php index 2dff18dc0a..7ae97d3e10 100644 --- a/src/Plugins/Export/ExportExcel.php +++ b/src/Plugins/Export/ExportExcel.php @@ -155,7 +155,7 @@ class ExportExcel extends ExportPlugin } $schemaInsert = implode($this->separator, $insertFields); - if (! $this->export->outputHandler($schemaInsert . $this->terminated)) { + if (! ($this->export->outputHandler)($schemaInsert . $this->terminated)) { return false; } } @@ -206,7 +206,7 @@ class ExportExcel extends ExportPlugin } $schemaInsert = implode($this->separator, $insertValues); - if (! $this->export->outputHandler($schemaInsert . $this->terminated)) { + if (! ($this->export->outputHandler)($schemaInsert . $this->terminated)) { return false; } } diff --git a/src/Plugins/Export/ExportHtmlword.php b/src/Plugins/Export/ExportHtmlword.php index 68d4d1c529..311bfb9fe8 100644 --- a/src/Plugins/Export/ExportHtmlword.php +++ b/src/Plugins/Export/ExportHtmlword.php @@ -106,7 +106,7 @@ class ExportHtmlword extends ExportPlugin */ public function exportHeader(): bool { - return $this->export->outputHandler( + return ($this->export->outputHandler)( ' @@ -127,7 +127,7 @@ class ExportHtmlword extends ExportPlugin */ public function exportFooter(): bool { - return $this->export->outputHandler(''); + return ($this->export->outputHandler)(''); } /** @@ -142,7 +142,7 @@ class ExportHtmlword extends ExportPlugin $dbAlias = $db; } - return $this->export->outputHandler( + return ($this->export->outputHandler)( '

' . __('Database') . ' ' . htmlspecialchars($dbAlias) . '

', ); } @@ -164,7 +164,7 @@ class ExportHtmlword extends ExportPlugin $tableAlias = $this->getTableAlias($aliases, $db, $table); if ( - ! $this->export->outputHandler( + ! ($this->export->outputHandler)( '

' . __('Dumping data for table') . ' ' . htmlspecialchars($tableAlias) . '

', @@ -173,7 +173,7 @@ class ExportHtmlword extends ExportPlugin return false; } - if (! $this->export->outputHandler('')) { + if (! ($this->export->outputHandler)('
')) { return false; } @@ -195,7 +195,7 @@ class ExportHtmlword extends ExportPlugin } $schemaInsert .= ''; - if (! $this->export->outputHandler($schemaInsert)) { + if (! ($this->export->outputHandler)($schemaInsert)) { return false; } } @@ -210,12 +210,12 @@ class ExportHtmlword extends ExportPlugin } $schemaInsert .= ''; - if (! $this->export->outputHandler($schemaInsert)) { + if (! ($this->export->outputHandler)($schemaInsert)) { return false; } } - return $this->export->outputHandler('
'); + return ($this->export->outputHandler)(''); } /** @@ -480,7 +480,7 @@ class ExportHtmlword extends ExportPlugin $dump .= $this->getTableDefStandIn($db, $table, $aliases); } - return $this->export->outputHandler($dump); + return ($this->export->outputHandler)($dump); } /** diff --git a/src/Plugins/Export/ExportJson.php b/src/Plugins/Export/ExportJson.php index c41d8b5ff7..16b821fda7 100644 --- a/src/Plugins/Export/ExportJson.php +++ b/src/Plugins/Export/ExportJson.php @@ -116,7 +116,7 @@ class ExportJson extends ExportPlugin return false; } - return $this->export->outputHandler('[' . "\n" . $data . ',' . "\n"); + return ($this->export->outputHandler)('[' . "\n" . $data . ',' . "\n"); } /** @@ -124,7 +124,7 @@ class ExportJson extends ExportPlugin */ public function exportFooter(): bool { - return $this->export->outputHandler(']' . "\n"); + return ($this->export->outputHandler)(']' . "\n"); } /** @@ -144,7 +144,7 @@ class ExportJson extends ExportPlugin return false; } - return $this->export->outputHandler($data . ',' . "\n"); + return ($this->export->outputHandler)($data . ',' . "\n"); } /** @@ -165,7 +165,7 @@ class ExportJson extends ExportPlugin $tableAlias = $this->getTableAlias($aliases, $db, $table); if (! $this->first) { - if (! $this->export->outputHandler(',')) { + if (! ($this->export->outputHandler)(',')) { return false; } } else { @@ -208,7 +208,7 @@ class ExportJson extends ExportPlugin ): bool { [$header, $footer] = explode('"@@DATA@@"', $buffer); - if (! $this->export->outputHandler($header . "\n" . '[' . "\n")) { + if (! ($this->export->outputHandler)($header . "\n" . '[' . "\n")) { return false; } @@ -234,7 +234,7 @@ class ExportJson extends ExportPlugin // Output table name as comment if this is the first record of the table if ($recordCnt > 1) { - if (! $this->export->outputHandler(',' . "\n")) { + if (! ($this->export->outputHandler)(',' . "\n")) { return false; } } @@ -272,12 +272,12 @@ class ExportJson extends ExportPlugin return false; } - if (! $this->export->outputHandler($encodedData)) { + if (! ($this->export->outputHandler)($encodedData)) { return false; } } - return $this->export->outputHandler("\n" . ']' . "\n" . $footer . "\n"); + return ($this->export->outputHandler)("\n" . ']' . "\n" . $footer . "\n"); } /** diff --git a/src/Plugins/Export/ExportLatex.php b/src/Plugins/Export/ExportLatex.php index 6296769eee..cb76cd0a51 100644 --- a/src/Plugins/Export/ExportLatex.php +++ b/src/Plugins/Export/ExportLatex.php @@ -233,7 +233,7 @@ class ExportLatex extends ExportPlugin . '% ' . __('Server version:') . ' ' . DatabaseInterface::getInstance()->getVersionString() . "\n" . '% ' . __('PHP Version:') . ' ' . PHP_VERSION . "\n"; - return $this->export->outputHandler($head); + return ($this->export->outputHandler)($head); } /** @@ -252,7 +252,7 @@ class ExportLatex extends ExportPlugin . '% ' . __('Database:') . ' \'' . $dbAlias . '\'' . "\n" . '% ' . "\n"; - return $this->export->outputHandler($head); + return ($this->export->outputHandler)($head); } /** @@ -309,7 +309,7 @@ class ExportLatex extends ExportPlugin . '} \\\\'; } - if (! $this->export->outputHandler($buffer)) { + if (! ($this->export->outputHandler)($buffer)) { return false; } @@ -322,13 +322,13 @@ class ExportLatex extends ExportPlugin } $buffer = mb_substr($buffer, 0, -2) . '\\\\ \\hline \hline '; - if (! $this->export->outputHandler($buffer . ' \\endfirsthead ' . "\n")) { + if (! ($this->export->outputHandler)($buffer . ' \\endfirsthead ' . "\n")) { return false; } if ($this->caption) { if ( - ! $this->export->outputHandler( + ! ($this->export->outputHandler)( '\\caption{' . Util::expandUserString( $this->dataContinuedCaption, @@ -342,10 +342,10 @@ class ExportLatex extends ExportPlugin } } - if (! $this->export->outputHandler($buffer . '\\endhead \\endfoot' . "\n")) { + if (! ($this->export->outputHandler)($buffer . '\\endhead \\endfoot' . "\n")) { return false; } - } elseif (! $this->export->outputHandler('\\\\ \hline')) { + } elseif (! ($this->export->outputHandler)('\\\\ \hline')) { return false; } @@ -370,14 +370,14 @@ class ExportLatex extends ExportPlugin } $buffer .= ' \\\\ \\hline ' . "\n"; - if (! $this->export->outputHandler($buffer)) { + if (! ($this->export->outputHandler)($buffer)) { return false; } } $buffer = ' \\end{longtable}' . "\n"; - return $this->export->outputHandler($buffer); + return ($this->export->outputHandler)($buffer); } /** @@ -443,7 +443,7 @@ class ExportLatex extends ExportPlugin */ $buffer = "\n" . '%' . "\n" . '% ' . __('Structure:') . ' ' . $tableAlias . "\n" . '%' . "\n" . ' \\begin{longtable}{'; - if (! $this->export->outputHandler($buffer)) { + if (! ($this->export->outputHandler)($buffer)) { return false; } @@ -513,7 +513,7 @@ class ExportLatex extends ExportPlugin $buffer .= $header . ' \\\\ \\hline \\hline \\endhead \\endfoot ' . "\n"; - if (! $this->export->outputHandler($buffer)) { + if (! ($this->export->outputHandler)($buffer)) { return false; } @@ -565,14 +565,14 @@ class ExportLatex extends ExportPlugin $buffer = str_replace("\000", ' & ', $localBuffer); $buffer .= ' \\\\ \\hline ' . "\n"; - if (! $this->export->outputHandler($buffer)) { + if (! ($this->export->outputHandler)($buffer)) { return false; } } $buffer = ' \\end{longtable}' . "\n"; - return $this->export->outputHandler($buffer); + return ($this->export->outputHandler)($buffer); } /** diff --git a/src/Plugins/Export/ExportMediawiki.php b/src/Plugins/Export/ExportMediawiki.php index 38709bd7ef..75be7b74e0 100644 --- a/src/Plugins/Export/ExportMediawiki.php +++ b/src/Plugins/Export/ExportMediawiki.php @@ -166,7 +166,7 @@ class ExportMediawiki extends ExportPlugin $output .= '|}' . str_repeat($this->exportCRLF(), 2); } - return $this->export->outputHandler($output); + return ($this->export->outputHandler)($output); } /** @@ -240,7 +240,7 @@ class ExportMediawiki extends ExportPlugin // End table construction $output .= '|}' . str_repeat($this->exportCRLF(), 2); - return $this->export->outputHandler($output); + return ($this->export->outputHandler)($output); } /** diff --git a/src/Plugins/Export/ExportOds.php b/src/Plugins/Export/ExportOds.php index b51b68f69d..d8dc2c45c1 100644 --- a/src/Plugins/Export/ExportOds.php +++ b/src/Plugins/Export/ExportOds.php @@ -142,11 +142,8 @@ class ExportOds extends ExportPlugin { $this->buffer .= ''; - return $this->export->outputHandler( - OpenDocument::create( - 'application/vnd.oasis.opendocument.spreadsheet', - $this->buffer, - ), + return ($this->export->outputHandler)( + OpenDocument::create('application/vnd.oasis.opendocument.spreadsheet', $this->buffer), ); } diff --git a/src/Plugins/Export/ExportOdt.php b/src/Plugins/Export/ExportOdt.php index e1842b1e18..f67377fc89 100644 --- a/src/Plugins/Export/ExportOdt.php +++ b/src/Plugins/Export/ExportOdt.php @@ -163,7 +163,7 @@ class ExportOdt extends ExportPlugin { $this->buffer .= ''; - return $this->export->outputHandler(OpenDocument::create( + return ($this->export->outputHandler)(OpenDocument::create( 'application/vnd.oasis.opendocument.text', $this->buffer, )); diff --git a/src/Plugins/Export/ExportPdf.php b/src/Plugins/Export/ExportPdf.php index 55fefca1a8..7da6bf7be9 100644 --- a/src/Plugins/Export/ExportPdf.php +++ b/src/Plugins/Export/ExportPdf.php @@ -104,7 +104,7 @@ class ExportPdf extends ExportPlugin public function exportFooter(): bool { // instead of $pdf->Output(): - return $this->export->outputHandler($this->pdf->getPDFData()); + return ($this->export->outputHandler)($this->pdf->getPDFData()); } /** diff --git a/src/Plugins/Export/ExportPhparray.php b/src/Plugins/Export/ExportPhparray.php index 7078187c19..2e010ad2c9 100644 --- a/src/Plugins/Export/ExportPhparray.php +++ b/src/Plugins/Export/ExportPhparray.php @@ -78,7 +78,7 @@ class ExportPhparray extends ExportPlugin */ public function exportHeader(): bool { - $this->export->outputHandler( + ($this->export->outputHandler)( 'export->outputHandler( + ($this->export->outputHandler)( '/**' . "\n" . ' * Database ' . $this->commentString(Util::backquote($dbAlias)) . "\n" . ' */' . "\n", @@ -160,7 +160,7 @@ class ExportPhparray extends ExportPlugin . $this->commentString(Util::backquote($dbAlias)) . '.' . $this->commentString(Util::backquote($tableAlias)) . ' */' . "\n"; $buffer .= '$' . $tableFixed . ' = array('; - if (! $this->export->outputHandler($buffer)) { + if (! ($this->export->outputHandler)($buffer)) { return false; } @@ -183,7 +183,7 @@ class ExportPhparray extends ExportPlugin } $buffer .= ')'; - if (! $this->export->outputHandler($buffer)) { + if (! ($this->export->outputHandler)($buffer)) { return false; } @@ -193,7 +193,7 @@ class ExportPhparray extends ExportPlugin $buffer .= "\n" . ');' . "\n"; - return $this->export->outputHandler($buffer); + return ($this->export->outputHandler)($buffer); } /** diff --git a/src/Plugins/Export/ExportSql.php b/src/Plugins/Export/ExportSql.php index 50711070f3..003ad3869f 100644 --- a/src/Plugins/Export/ExportSql.php +++ b/src/Plugins/Export/ExportSql.php @@ -19,6 +19,7 @@ use PhpMyAdmin\Dbal\ConnectionType; use PhpMyAdmin\Dbal\DatabaseInterface; use PhpMyAdmin\Exceptions\ExportException; use PhpMyAdmin\Export\Export; +use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Export\StructureOrData; use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Plugins\ExportPlugin; @@ -649,7 +650,7 @@ class ExportSql extends ExportPlugin } if ($text !== '') { - return $this->export->outputHandler($text); + return ($this->export->outputHandler)($text); } return false; @@ -732,7 +733,7 @@ class ExportSql extends ExportPlugin DatabaseInterface::getInstance()->query('SET time_zone = "' . self::$oldTimezone . '"'); } - return $this->export->outputHandler($foot); + return ($this->export->outputHandler)($foot); } /** @@ -801,7 +802,7 @@ class ExportSql extends ExportPlugin $head .= $this->possibleCRLF(); - if (Export::$asFile) { + if (OutputHandler::$asFile) { // we are saving as file, therefore we provide charset information // so that a utility like the mysql client can interpret // the file correctly @@ -828,7 +829,7 @@ class ExportSql extends ExportPlugin $this->sentCharset = true; } - return $this->export->outputHandler($head); + return ($this->export->outputHandler)($head); } /** @@ -845,13 +846,9 @@ class ExportSql extends ExportPlugin if ($this->structureOrData !== StructureOrData::Data && $this->dropDatabase) { if ( - ! $this->export->outputHandler( + ! ($this->export->outputHandler)( 'DROP DATABASE IF EXISTS ' - . Util::backquoteCompat( - $dbAlias, - $this->compatibility, - $this->useSqlBackquotes, - ) + . Util::backquoteCompat($dbAlias, $this->compatibility, $this->useSqlBackquotes) . ';' . "\n", ) ) { @@ -879,7 +876,7 @@ class ExportSql extends ExportPlugin } $createQuery .= ';' . "\n"; - if (! $this->export->outputHandler($createQuery)) { + if (! ($this->export->outputHandler)($createQuery)) { return false; } @@ -895,18 +892,14 @@ class ExportSql extends ExportPlugin private function exportUseStatement(string $db, string $compat): bool { if ($compat === 'NONE') { - return $this->export->outputHandler( + return ($this->export->outputHandler)( 'USE ' - . Util::backquoteCompat( - $db, - $compat, - $this->useSqlBackquotes, - ) + . Util::backquoteCompat($db, $compat, $this->useSqlBackquotes) . ';' . "\n", ); } - return $this->export->outputHandler('USE ' . $db . ';' . "\n"); + return ($this->export->outputHandler)('USE ' . $db . ';' . "\n"); } /** @@ -932,7 +925,7 @@ class ExportSql extends ExportPlugin ) . $this->exportComment(); - return $this->export->outputHandler($head); + return ($this->export->outputHandler)($head); } /** @@ -946,25 +939,25 @@ class ExportSql extends ExportPlugin //add indexes to the sql dump file if ($this->sqlIndexes !== null) { - $result = $this->export->outputHandler($this->sqlIndexes); + $result = ($this->export->outputHandler)($this->sqlIndexes); $this->sqlIndexes = null; } //add auto increments to the sql dump file if ($this->sqlAutoIncrements !== null) { - $result = $this->export->outputHandler($this->sqlAutoIncrements); + $result = ($this->export->outputHandler)($this->sqlAutoIncrements); $this->sqlAutoIncrements = null; } //add views to the sql dump file if ($this->sqlViews !== '') { - $result = $this->export->outputHandler($this->sqlViews); + $result = ($this->export->outputHandler)($this->sqlViews); $this->sqlViews = ''; } //add constraints to the sql dump file if ($this->sqlConstraints !== null) { - $result = $this->export->outputHandler($this->sqlConstraints); + $result = ($this->export->outputHandler)($this->sqlConstraints); $this->sqlConstraints = null; } @@ -1022,7 +1015,7 @@ class ExportSql extends ExportPlugin } if ($text !== '') { - return $this->export->outputHandler($text); + return ($this->export->outputHandler)($text); } return false; @@ -1050,7 +1043,7 @@ class ExportSql extends ExportPlugin . $this->exportComment() . $this->exportComment(__('Metadata')) . $this->exportComment(); - if (! $this->export->outputHandler($comment)) { + if (! ($this->export->outputHandler)($comment)) { return false; } @@ -1128,7 +1121,7 @@ class ExportSql extends ExportPlugin $comment .= $this->exportComment(); - if (! $this->export->outputHandler($comment)) { + if (! ($this->export->outputHandler)($comment)) { return false; } @@ -1173,7 +1166,7 @@ class ExportSql extends ExportPlugin $lastPage = "\n" . 'SET @LAST_PAGE = LAST_INSERT_ID();' . "\n"; - if (! $this->export->outputHandler($lastPage)) { + if (! ($this->export->outputHandler)($lastPage)) { return false; } @@ -1982,7 +1975,7 @@ class ExportSql extends ExportPlugin // but not in the case of export $this->sqlConstraintsQuery = ''; - return $this->export->outputHandler($dump); + return ($this->export->outputHandler)($dump); } /** @@ -2019,7 +2012,7 @@ class ExportSql extends ExportPlugin . $this->exportComment() . $this->possibleCRLF(); - return $this->export->outputHandler($head); + return ($this->export->outputHandler)($head); } $result = $dbi->tryQuery($sqlQuery, ConnectionType::User, DatabaseInterface::QUERY_UNBUFFERED); @@ -2090,8 +2083,8 @@ class ExportSql extends ExportPlugin ) . $this->exportComment() . "\n"; - $this->export->outputHandler($truncatehead); - $this->export->outputHandler($truncate); + ($this->export->outputHandler)($truncatehead); + ($this->export->outputHandler)($truncate); } // scheme for inserting fields @@ -2127,7 +2120,7 @@ class ExportSql extends ExportPlugin ) . $this->exportComment() . "\n"; - if (! $this->export->outputHandler($head)) { + if (! ($this->export->outputHandler)($head)) { return false; } } @@ -2135,13 +2128,9 @@ class ExportSql extends ExportPlugin // We need to SET IDENTITY_INSERT ON for MSSQL if ($currentRow === 0 && $this->compatibility === 'MSSQL') { if ( - ! $this->export->outputHandler( + ! ($this->export->outputHandler)( 'SET IDENTITY_INSERT ' - . Util::backquoteCompat( - $tableAlias, - $this->compatibility, - $this->useSqlBackquotes, - ) + . Util::backquoteCompat($tableAlias, $this->compatibility, $this->useSqlBackquotes) . ' ON ;' . "\n", ) ) { @@ -2218,7 +2207,7 @@ class ExportSql extends ExportPlugin $insertLine = '(' . implode(', ', $values) . ')'; $insertLineSize = mb_strlen($insertLine); if ($this->maxQuerySize > 0 && $querySize + $insertLineSize > $this->maxQuerySize) { - if (! $this->export->outputHandler(';' . "\n")) { + if (! ($this->export->outputHandler)(';' . "\n")) { return false; } @@ -2234,26 +2223,22 @@ class ExportSql extends ExportPlugin $insertLine = $schemaInsert . '(' . implode(', ', $values) . ')'; } - if (! $this->export->outputHandler(($currentRow === 1 ? '' : $separator . "\n") . $insertLine)) { + if (! ($this->export->outputHandler)(($currentRow === 1 ? '' : $separator . "\n") . $insertLine)) { return false; } } if ($currentRow > 0) { - if (! $this->export->outputHandler(';' . "\n")) { + if (! ($this->export->outputHandler)(';' . "\n")) { return false; } } // We need to SET IDENTITY_INSERT OFF for MSSQL if ($this->compatibility === 'MSSQL' && $currentRow > 0) { - $outputSucceeded = $this->export->outputHandler( + $outputSucceeded = ($this->export->outputHandler)( "\n" . 'SET IDENTITY_INSERT ' - . Util::backquoteCompat( - $tableAlias, - $this->compatibility, - $this->useSqlBackquotes, - ) + . Util::backquoteCompat($tableAlias, $this->compatibility, $this->useSqlBackquotes) . ' OFF;' . "\n", ); if (! $outputSucceeded) { diff --git a/src/Plugins/Export/ExportTexytext.php b/src/Plugins/Export/ExportTexytext.php index 276bf7471e..684583989b 100644 --- a/src/Plugins/Export/ExportTexytext.php +++ b/src/Plugins/Export/ExportTexytext.php @@ -111,7 +111,7 @@ class ExportTexytext extends ExportPlugin $dbAlias = $db; } - return $this->export->outputHandler( + return ($this->export->outputHandler)( '===' . __('Database') . ' ' . $dbAlias . "\n\n", ); } @@ -133,7 +133,7 @@ class ExportTexytext extends ExportPlugin $tableAlias = $this->getTableAlias($aliases, $db, $table); if ( - ! $this->export->outputHandler( + ! ($this->export->outputHandler)( $tableAlias !== '' ? '== ' . __('Dumping data for table') . ' ' . $tableAlias . "\n\n" : '==' . __('Dumping data for query result') . "\n\n", @@ -158,7 +158,7 @@ class ExportTexytext extends ExportPlugin } $textOutput .= "\n|------\n"; - if (! $this->export->outputHandler($textOutput)) { + if (! ($this->export->outputHandler)($textOutput)) { return false; } } @@ -184,7 +184,7 @@ class ExportTexytext extends ExportPlugin } $textOutput .= "\n"; - if (! $this->export->outputHandler($textOutput)) { + if (! ($this->export->outputHandler)($textOutput)) { return false; } } @@ -429,7 +429,7 @@ class ExportTexytext extends ExportPlugin $dump .= $this->getTableDefStandIn($db, $table, $aliases); } - return $this->export->outputHandler($dump); + return ($this->export->outputHandler)($dump); } /** diff --git a/src/Plugins/Export/ExportXml.php b/src/Plugins/Export/ExportXml.php index c4ab0b5a84..d9cf47d748 100644 --- a/src/Plugins/Export/ExportXml.php +++ b/src/Plugins/Export/ExportXml.php @@ -12,7 +12,6 @@ use PhpMyAdmin\Database\Routines; use PhpMyAdmin\Database\RoutineType; use PhpMyAdmin\Dbal\ConnectionType; use PhpMyAdmin\Dbal\DatabaseInterface; -use PhpMyAdmin\Export\Export; use PhpMyAdmin\Export\StructureOrData; use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Plugins\ExportPlugin; @@ -195,7 +194,7 @@ class ExportXml extends ExportPlugin || $this->exportTriggers || $this->exportViews; - $charset = Export::$outputCharsetConversion ? Current::$charset : 'utf-8'; + $charset = $this->export->outputHandler->outputCharsetConversion ? Current::$charset : 'utf-8'; $config = Config::getInstance(); $head = '' . "\n" @@ -337,7 +336,7 @@ class ExportXml extends ExportPlugin } } - return $this->export->outputHandler($head); + return ($this->export->outputHandler)($head); } /** @@ -347,7 +346,7 @@ class ExportXml extends ExportPlugin { $foot = ''; - return $this->export->outputHandler($foot); + return ($this->export->outputHandler)($foot); } /** @@ -369,7 +368,7 @@ class ExportXml extends ExportPlugin . ' -->' . "\n" . ' ' . "\n"; - return $this->export->outputHandler($head); + return ($this->export->outputHandler)($head); } return true; @@ -383,7 +382,7 @@ class ExportXml extends ExportPlugin public function exportDBFooter(string $db): bool { if ($this->exportContents) { - return $this->export->outputHandler(' ' . "\n"); + return ($this->export->outputHandler)(' ' . "\n"); } return true; @@ -418,7 +417,7 @@ class ExportXml extends ExportPlugin $buffer = ' ' . "\n"; - if (! $this->export->outputHandler($buffer)) { + if (! ($this->export->outputHandler)($buffer)) { return false; } @@ -442,7 +441,7 @@ class ExportXml extends ExportPlugin $buffer .= ' ' . "\n"; - if (! $this->export->outputHandler($buffer)) { + if (! ($this->export->outputHandler)($buffer)) { return false; } } diff --git a/src/Plugins/Export/ExportYaml.php b/src/Plugins/Export/ExportYaml.php index 8ae7dda0be..dfe7292ed3 100644 --- a/src/Plugins/Export/ExportYaml.php +++ b/src/Plugins/Export/ExportYaml.php @@ -67,7 +67,7 @@ class ExportYaml extends ExportPlugin */ public function exportHeader(): bool { - $this->export->outputHandler('%YAML 1.1' . "\n" . '---' . "\n"); + ($this->export->outputHandler)('%YAML 1.1' . "\n" . '---' . "\n"); return true; } @@ -77,7 +77,7 @@ class ExportYaml extends ExportPlugin */ public function exportFooter(): bool { - $this->export->outputHandler('...' . "\n"); + ($this->export->outputHandler)('...' . "\n"); return true; } @@ -148,7 +148,7 @@ class ExportYaml extends ExportPlugin $buffer .= ' ' . $columns[$i] . ': "' . $record[$i] . '"' . "\n"; } - if (! $this->export->outputHandler($buffer)) { + if (! ($this->export->outputHandler)($buffer)) { return false; } } diff --git a/src/Table/TableMover.php b/src/Table/TableMover.php index 2a613c9584..2081350a67 100644 --- a/src/Table/TableMover.php +++ b/src/Table/TableMover.php @@ -9,7 +9,7 @@ use PhpMyAdmin\ConfigStorage\RelationParameters; use PhpMyAdmin\Current; use PhpMyAdmin\Dbal\ConnectionType; use PhpMyAdmin\Dbal\DatabaseInterface; -use PhpMyAdmin\Export\Export; +use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Message; use PhpMyAdmin\Plugins; use PhpMyAdmin\Plugins\Export\ExportSql; @@ -66,9 +66,6 @@ class TableMover return false; } - // Setting required export settings. - Export::$asFile = true; - // Selecting the database could avoid some problems with replicated // databases, when moving table from replicated one to not replicated one. $this->dbi->selectDb($targetDb); @@ -484,6 +481,8 @@ class TableMover * @var ExportSql $exportSqlPlugin */ $exportSqlPlugin = Plugins::getPlugin('export', 'sql', ExportType::Table); + // Setting required export settings. + OutputHandler::$asFile = true; // It is better that all identifiers are quoted $exportSqlPlugin->useSqlBackquotes(true); diff --git a/tests/unit/Export/ExportTest.php b/tests/unit/Export/ExportTest.php index dc54bd1398..1875a36f14 100644 --- a/tests/unit/Export/ExportTest.php +++ b/tests/unit/Export/ExportTest.php @@ -9,6 +9,7 @@ use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Current; use PhpMyAdmin\Dbal\DatabaseInterface; use PhpMyAdmin\Export\Export; +use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\FlashMessenger; use PhpMyAdmin\Identifiers\DatabaseName; use PhpMyAdmin\Message; @@ -92,9 +93,7 @@ class ExportTest extends AbstractTestCase public function testExportDatabase(): void { - Export::$outputKanjiConversion = false; - Export::$bufferNeeded = false; - Export::$asFile = false; + OutputHandler::$asFile = false; Config::getInstance()->selectedServer['DisableIS'] = false; // phpcs:disable Generic.Files.LineLength.TooLong @@ -150,9 +149,7 @@ class ExportTest extends AbstractTestCase public function testExportServer(): void { - Export::$outputKanjiConversion = false; - Export::$bufferNeeded = false; - Export::$asFile = false; + OutputHandler::$asFile = false; $config = Config::getInstance(); $config->selectedServer['DisableIS'] = false; $config->selectedServer['only_db'] = ''; diff --git a/tests/unit/Plugins/Export/ExportCodegenTest.php b/tests/unit/Plugins/Export/ExportCodegenTest.php index d301e0633e..a2148531bb 100644 --- a/tests/unit/Plugins/Export/ExportCodegenTest.php +++ b/tests/unit/Plugins/Export/ExportCodegenTest.php @@ -7,6 +7,7 @@ namespace PhpMyAdmin\Tests\Plugins\Export; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Dbal\DatabaseInterface; use PhpMyAdmin\Export\Export; +use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Plugins\Export\ExportCodegen; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup; @@ -164,11 +165,7 @@ class ExportCodegenTest extends AbstractTestCase public function testExportData(): void { - Export::$outputKanjiConversion = false; - Export::$outputCharsetConversion = false; - Export::$bufferNeeded = false; - Export::$asFile = true; - Export::$saveOnServer = false; + OutputHandler::$asFile = true; $request = ServerRequestFactory::create()->createServerRequest('POST', 'https://example.com/') ->withParsedBody(['codegen_format' => '1']); diff --git a/tests/unit/Plugins/Export/ExportCsvTest.php b/tests/unit/Plugins/Export/ExportCsvTest.php index 9d99d4e079..3504de5343 100644 --- a/tests/unit/Plugins/Export/ExportCsvTest.php +++ b/tests/unit/Plugins/Export/ExportCsvTest.php @@ -8,6 +8,7 @@ use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Current; use PhpMyAdmin\Dbal\DatabaseInterface; use PhpMyAdmin\Export\Export; +use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Plugins\Export\ExportCsv; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup; @@ -44,7 +45,6 @@ class ExportCsvTest extends AbstractTestCase Current::$database = ''; Current::$table = ''; Current::$lang = ''; - Export::$saveFilename = ''; $relation = new Relation($dbi); $this->object = new ExportCsv($relation, new Export($dbi), new Transformations($dbi, $relation)); @@ -255,27 +255,7 @@ class ExportCsvTest extends AbstractTestCase public function testExportData(): void { // case 1 - Export::$outputKanjiConversion = false; - Export::$outputCharsetConversion = false; - Export::$bufferNeeded = false; - Export::$asFile = true; - Export::$saveOnServer = true; - Export::$fileHandle = null; - - ob_start(); - self::assertFalse($this->object->exportData( - 'test_db', - 'test_table', - 'SELECT * FROM `test_db`.`test_table`;', - )); - ob_get_clean(); - - // case 2 - Export::$outputKanjiConversion = false; - Export::$outputCharsetConversion = false; - Export::$bufferNeeded = false; - Export::$asFile = true; - Export::$saveOnServer = false; + OutputHandler::$asFile = true; $request = ServerRequestFactory::create()->createServerRequest('POST', 'https://example.com/') ->withParsedBody(['csv_terminated' => ';', 'csv_columns' => 'On']); diff --git a/tests/unit/Plugins/Export/ExportExcelTest.php b/tests/unit/Plugins/Export/ExportExcelTest.php index 22abec7a06..a2530482d0 100644 --- a/tests/unit/Plugins/Export/ExportExcelTest.php +++ b/tests/unit/Plugins/Export/ExportExcelTest.php @@ -7,6 +7,7 @@ namespace PhpMyAdmin\Tests\Plugins\Export; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Dbal\DatabaseInterface; use PhpMyAdmin\Export\Export; +use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Plugins\Export\ExportExcel; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup; @@ -216,27 +217,7 @@ class ExportExcelTest extends AbstractTestCase public function testExportData(): void { // case 1 - Export::$outputKanjiConversion = false; - Export::$outputCharsetConversion = false; - Export::$bufferNeeded = false; - Export::$asFile = true; - Export::$saveOnServer = true; - Export::$fileHandle = null; - - ob_start(); - self::assertFalse($this->object->exportData( - 'test_db', - 'test_table', - 'SELECT * FROM `test_db`.`test_table`;', - )); - ob_get_clean(); - - // case 2 - Export::$outputKanjiConversion = false; - Export::$outputCharsetConversion = false; - Export::$bufferNeeded = false; - Export::$asFile = true; - Export::$saveOnServer = false; + OutputHandler::$asFile = true; $request = ServerRequestFactory::create()->createServerRequest('POST', 'https://example.com/') ->withParsedBody(['excel_columns' => 'On']); diff --git a/tests/unit/Plugins/Export/ExportHtmlwordTest.php b/tests/unit/Plugins/Export/ExportHtmlwordTest.php index 984f32f9ee..b364f557ca 100644 --- a/tests/unit/Plugins/Export/ExportHtmlwordTest.php +++ b/tests/unit/Plugins/Export/ExportHtmlwordTest.php @@ -11,6 +11,7 @@ use PhpMyAdmin\ConfigStorage\RelationParameters; use PhpMyAdmin\Current; use PhpMyAdmin\Dbal\DatabaseInterface; use PhpMyAdmin\Export\Export; +use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Identifiers\TableName; use PhpMyAdmin\Identifiers\TriggerName; @@ -63,11 +64,7 @@ class ExportHtmlwordTest extends AbstractTestCase new Export($this->dbi), new Transformations($this->dbi, $relation), ); - Export::$outputKanjiConversion = false; - Export::$outputCharsetConversion = false; - Export::$bufferNeeded = false; - Export::$asFile = true; - Export::$saveOnServer = false; + OutputHandler::$asFile = true; Current::$database = ''; Current::$table = ''; Current::$lang = ''; @@ -293,11 +290,7 @@ class ExportHtmlwordTest extends AbstractTestCase public function testExportData(): void { // case 1 - Export::$outputKanjiConversion = false; - Export::$outputCharsetConversion = false; - Export::$bufferNeeded = false; - Export::$asFile = true; - Export::$saveOnServer = false; + OutputHandler::$asFile = true; $request = ServerRequestFactory::create()->createServerRequest('POST', 'https://example.com/') ->withParsedBody(['htmlword_columns' => 'On']); diff --git a/tests/unit/Plugins/Export/ExportJsonTest.php b/tests/unit/Plugins/Export/ExportJsonTest.php index 8126674b63..c18f88266b 100644 --- a/tests/unit/Plugins/Export/ExportJsonTest.php +++ b/tests/unit/Plugins/Export/ExportJsonTest.php @@ -7,6 +7,7 @@ namespace PhpMyAdmin\Tests\Plugins\Export; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Dbal\DatabaseInterface; use PhpMyAdmin\Export\Export; +use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Plugins\Export\ExportJson; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup; @@ -35,11 +36,7 @@ class ExportJsonTest extends AbstractTestCase $dbi = $this->createDatabaseInterface(); DatabaseInterface::$instance = $dbi; - Export::$outputKanjiConversion = false; - Export::$outputCharsetConversion = false; - Export::$bufferNeeded = false; - Export::$asFile = true; - Export::$saveOnServer = false; + OutputHandler::$asFile = true; $relation = new Relation($dbi); $this->object = new ExportJson($relation, new Export($dbi), new Transformations($dbi, $relation)); } diff --git a/tests/unit/Plugins/Export/ExportLatexTest.php b/tests/unit/Plugins/Export/ExportLatexTest.php index 829ea47e18..8a44353ec1 100644 --- a/tests/unit/Plugins/Export/ExportLatexTest.php +++ b/tests/unit/Plugins/Export/ExportLatexTest.php @@ -11,6 +11,7 @@ use PhpMyAdmin\ConfigStorage\RelationParameters; use PhpMyAdmin\Current; use PhpMyAdmin\Dbal\DatabaseInterface; use PhpMyAdmin\Export\Export; +use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Plugins\Export\ExportLatex; use PhpMyAdmin\Plugins\ExportPlugin; @@ -49,11 +50,7 @@ class ExportLatexTest extends AbstractTestCase $dbi = $this->createDatabaseInterface(); DatabaseInterface::$instance = $dbi; - Export::$outputKanjiConversion = false; - Export::$outputCharsetConversion = false; - Export::$bufferNeeded = false; - Export::$asFile = true; - Export::$saveOnServer = false; + OutputHandler::$asFile = true; ExportPlugin::$exportType = ExportType::Table; ExportPlugin::$singleTable = false; Current::$database = 'db'; diff --git a/tests/unit/Plugins/Export/ExportMediawikiTest.php b/tests/unit/Plugins/Export/ExportMediawikiTest.php index e3a7ca4c02..db78381b01 100644 --- a/tests/unit/Plugins/Export/ExportMediawikiTest.php +++ b/tests/unit/Plugins/Export/ExportMediawikiTest.php @@ -9,6 +9,7 @@ use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Current; use PhpMyAdmin\Dbal\DatabaseInterface; use PhpMyAdmin\Export\Export; +use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Plugins\Export\ExportMediawiki; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup; @@ -43,11 +44,7 @@ class ExportMediawikiTest extends AbstractTestCase $dbi = $this->createDatabaseInterface(); DatabaseInterface::$instance = $dbi; - Export::$outputKanjiConversion = false; - Export::$outputCharsetConversion = false; - Export::$bufferNeeded = false; - Export::$asFile = true; - Export::$saveOnServer = false; + OutputHandler::$asFile = true; Current::$database = ''; Current::$table = ''; Current::$lang = 'en'; diff --git a/tests/unit/Plugins/Export/ExportOdsTest.php b/tests/unit/Plugins/Export/ExportOdsTest.php index 48eb44e16b..030410849a 100644 --- a/tests/unit/Plugins/Export/ExportOdsTest.php +++ b/tests/unit/Plugins/Export/ExportOdsTest.php @@ -8,6 +8,7 @@ use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Dbal\ConnectionType; use PhpMyAdmin\Dbal\DatabaseInterface; use PhpMyAdmin\Export\Export; +use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Plugins\Export\ExportOds; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup; @@ -52,11 +53,7 @@ class ExportOdsTest extends AbstractTestCase $dbi = $this->createDatabaseInterface(); DatabaseInterface::$instance = $dbi; - Export::$outputKanjiConversion = false; - Export::$outputCharsetConversion = false; - Export::$bufferNeeded = false; - Export::$asFile = true; - Export::$saveOnServer = false; + OutputHandler::$asFile = true; $relation = new Relation($dbi); $this->object = new ExportOds($relation, new Export($dbi), new Transformations($dbi, $relation)); } diff --git a/tests/unit/Plugins/Export/ExportOdtTest.php b/tests/unit/Plugins/Export/ExportOdtTest.php index 61ce1512d6..49c668e552 100644 --- a/tests/unit/Plugins/Export/ExportOdtTest.php +++ b/tests/unit/Plugins/Export/ExportOdtTest.php @@ -11,6 +11,7 @@ use PhpMyAdmin\ConfigStorage\RelationParameters; use PhpMyAdmin\Dbal\ConnectionType; use PhpMyAdmin\Dbal\DatabaseInterface; use PhpMyAdmin\Export\Export; +use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Identifiers\TableName; use PhpMyAdmin\Identifiers\TriggerName; @@ -67,11 +68,7 @@ class ExportOdtTest extends AbstractTestCase $this->dummyDbi = $this->createDbiDummy(); $this->dbi = $this->createDatabaseInterface($this->dummyDbi); DatabaseInterface::$instance = $this->dbi; - Export::$outputKanjiConversion = false; - Export::$outputCharsetConversion = false; - Export::$bufferNeeded = false; - Export::$asFile = true; - Export::$saveOnServer = false; + OutputHandler::$asFile = true; ExportPlugin::$exportType = ExportType::Table; ExportPlugin::$singleTable = false; Config::getInstance()->selectedServer['DisableIS'] = true; diff --git a/tests/unit/Plugins/Export/ExportPdfTest.php b/tests/unit/Plugins/Export/ExportPdfTest.php index 4f2a80b2ba..2641ce7143 100644 --- a/tests/unit/Plugins/Export/ExportPdfTest.php +++ b/tests/unit/Plugins/Export/ExportPdfTest.php @@ -7,6 +7,7 @@ namespace PhpMyAdmin\Tests\Plugins\Export; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Dbal\DatabaseInterface; use PhpMyAdmin\Export\Export; +use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Plugins\Export\ExportPdf; use PhpMyAdmin\Plugins\Export\Helpers\Pdf; @@ -39,11 +40,7 @@ class ExportPdfTest extends AbstractTestCase $dbi = $this->createDatabaseInterface(); DatabaseInterface::$instance = $dbi; - Export::$outputKanjiConversion = false; - Export::$outputCharsetConversion = false; - Export::$bufferNeeded = false; - Export::$asFile = true; - Export::$saveOnServer = false; + OutputHandler::$asFile = true; $relation = new Relation($dbi); $this->object = new ExportPdf($relation, new Export($dbi), new Transformations($dbi, $relation)); } diff --git a/tests/unit/Plugins/Export/ExportPhparrayTest.php b/tests/unit/Plugins/Export/ExportPhparrayTest.php index 0b2c162444..974dda4c72 100644 --- a/tests/unit/Plugins/Export/ExportPhparrayTest.php +++ b/tests/unit/Plugins/Export/ExportPhparrayTest.php @@ -8,6 +8,7 @@ use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Current; use PhpMyAdmin\Dbal\DatabaseInterface; use PhpMyAdmin\Export\Export; +use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Plugins\Export\ExportPhparray; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup; @@ -38,11 +39,7 @@ class ExportPhparrayTest extends AbstractTestCase $dbi = $this->createDatabaseInterface(); DatabaseInterface::$instance = $dbi; - Export::$outputKanjiConversion = false; - Export::$outputCharsetConversion = false; - Export::$bufferNeeded = false; - Export::$asFile = true; - Export::$saveOnServer = false; + OutputHandler::$asFile = true; Current::$database = ''; Current::$table = ''; Current::$lang = 'en'; diff --git a/tests/unit/Plugins/Export/ExportSqlTest.php b/tests/unit/Plugins/Export/ExportSqlTest.php index 8409d8ac31..35bdf6d17b 100644 --- a/tests/unit/Plugins/Export/ExportSqlTest.php +++ b/tests/unit/Plugins/Export/ExportSqlTest.php @@ -13,6 +13,7 @@ use PhpMyAdmin\Dbal\ConnectionType; use PhpMyAdmin\Dbal\DatabaseInterface; use PhpMyAdmin\Exceptions\ExportException; use PhpMyAdmin\Export\Export; +use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Plugins\Export\ExportSql; use PhpMyAdmin\Plugins\ExportPlugin; @@ -67,10 +68,7 @@ class ExportSqlTest extends AbstractTestCase Current::$table = ''; Current::$lang = 'en'; Config::getInstance()->selectedServer['DisableIS'] = true; - Export::$outputKanjiConversion = false; - Export::$bufferNeeded = false; - Export::$asFile = false; - Export::$saveOnServer = false; + OutputHandler::$asFile = false; ExportPlugin::$exportType = ExportType::Table; ExportPlugin::$singleTable = false; @@ -385,8 +383,7 @@ class ExportSqlTest extends AbstractTestCase { Current::$charset = 'utf-8'; ExportSql::$oldTimezone = 'GMT'; - Export::$asFile = true; - Export::$outputCharsetConversion = true; + OutputHandler::$asFile = true; $dbi = $this->getMockBuilder(DatabaseInterface::class) ->disableOriginalConstructor() @@ -416,8 +413,7 @@ class ExportSqlTest extends AbstractTestCase $config->selectedServer['host'] = 'localhost'; $config->selectedServer['port'] = 80; ExportSql::$oldTimezone = 'GMT'; - Export::$asFile = true; - Export::$outputCharsetConversion = true; + OutputHandler::$asFile = true; Current::$charset = 'utf-8'; $dbi = $this->getMockBuilder(DatabaseInterface::class) diff --git a/tests/unit/Plugins/Export/ExportTexytextTest.php b/tests/unit/Plugins/Export/ExportTexytextTest.php index 9435752189..d480c20741 100644 --- a/tests/unit/Plugins/Export/ExportTexytextTest.php +++ b/tests/unit/Plugins/Export/ExportTexytextTest.php @@ -12,6 +12,7 @@ use PhpMyAdmin\Current; use PhpMyAdmin\Dbal\ConnectionType; use PhpMyAdmin\Dbal\DatabaseInterface; use PhpMyAdmin\Export\Export; +use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Identifiers\TableName; use PhpMyAdmin\Identifiers\TriggerName; @@ -58,10 +59,7 @@ class ExportTexytextTest extends AbstractTestCase $this->dummyDbi = $this->createDbiDummy(); $this->dbi = $this->createDatabaseInterface($this->dummyDbi); DatabaseInterface::$instance = $this->dbi; - Export::$outputKanjiConversion = false; - Export::$bufferNeeded = false; - Export::$asFile = false; - Export::$saveOnServer = false; + OutputHandler::$asFile = false; ExportPlugin::$exportType = ExportType::Table; ExportPlugin::$singleTable = false; Current::$database = ''; diff --git a/tests/unit/Plugins/Export/ExportXmlTest.php b/tests/unit/Plugins/Export/ExportXmlTest.php index 22aaf91605..e2de0ff5db 100644 --- a/tests/unit/Plugins/Export/ExportXmlTest.php +++ b/tests/unit/Plugins/Export/ExportXmlTest.php @@ -9,6 +9,7 @@ use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Current; use PhpMyAdmin\Dbal\DatabaseInterface; use PhpMyAdmin\Export\Export; +use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Plugins\Export\ExportXml; use PhpMyAdmin\Plugins\ExportPlugin; @@ -43,10 +44,7 @@ class ExportXmlTest extends AbstractTestCase $dbi = $this->createDatabaseInterface(); DatabaseInterface::$instance = $dbi; - Export::$outputKanjiConversion = false; - Export::$bufferNeeded = false; - Export::$asFile = false; - Export::$saveOnServer = false; + OutputHandler::$asFile = false; ExportPlugin::$exportType = ExportType::Table; ExportPlugin::$singleTable = false; Current::$database = 'db'; @@ -168,7 +166,6 @@ class ExportXmlTest extends AbstractTestCase public function testExportHeader(): void { - Export::$outputCharsetConversion = true; Current::$charset = 'iso-8859-1'; $config = Config::getInstance(); $config->selectedServer['port'] = 80; @@ -290,8 +287,6 @@ class ExportXmlTest extends AbstractTestCase // case 2 with isView as true and false - Export::$outputCharsetConversion = false; - $dbiDummy->addResult( 'SELECT `DEFAULT_CHARACTER_SET_NAME`, `DEFAULT_COLLATION_NAME`' . " FROM `information_schema`.`SCHEMATA` WHERE `SCHEMA_NAME` = 'd<\\\"b' LIMIT 1", @@ -408,8 +403,7 @@ class ExportXmlTest extends AbstractTestCase public function testExportData(): void { - Export::$asFile = true; - Export::$outputCharsetConversion = false; + OutputHandler::$asFile = true; $request = ServerRequestFactory::create()->createServerRequest('POST', 'https://example.com/') ->withParsedBody(['xml_export_contents' => 'On']); diff --git a/tests/unit/Plugins/Export/ExportYamlTest.php b/tests/unit/Plugins/Export/ExportYamlTest.php index 51f075b8fa..cf0256701d 100644 --- a/tests/unit/Plugins/Export/ExportYamlTest.php +++ b/tests/unit/Plugins/Export/ExportYamlTest.php @@ -8,6 +8,7 @@ use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Current; use PhpMyAdmin\Dbal\DatabaseInterface; use PhpMyAdmin\Export\Export; +use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Plugins\Export\ExportYaml; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup; @@ -38,10 +39,7 @@ class ExportYamlTest extends AbstractTestCase $dbi = $this->createDatabaseInterface(); DatabaseInterface::$instance = $dbi; - Export::$outputKanjiConversion = false; - Export::$bufferNeeded = false; - Export::$asFile = false; - Export::$saveOnServer = false; + OutputHandler::$asFile = false; Current::$database = ''; Current::$table = ''; Current::$lang = 'en'; From 0781ef6b35bce059908b353526054a4cc92a3cfd Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Sat, 22 Nov 2025 00:23:17 +0000 Subject: [PATCH 08/21] Remove $saveOnServer Signed-off-by: Kamil Tekiela --- src/Controllers/Export/ExportController.php | 11 ++++++----- src/Export/OutputHandler.php | 7 +++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Controllers/Export/ExportController.php b/src/Controllers/Export/ExportController.php index 24eaa90855..0befa5c493 100644 --- a/src/Controllers/Export/ExportController.php +++ b/src/Controllers/Export/ExportController.php @@ -141,6 +141,8 @@ final readonly class ExportController implements InvocableController // Is it a quick or custom export? $isQuickExport = $quickOrCustom === 'quick'; + $saveOnServer = false; + if ($outputFormat === 'astext') { OutputHandler::$asFile = false; } else { @@ -156,7 +158,7 @@ final readonly class ExportController implements InvocableController if (($isQuickExport && $quickExportOnServer) || (! $isQuickExport && $onServerParam)) { // Will we save dump on server? - $this->export->outputHandler->saveOnServer = $this->config->settings['SaveDir'] !== ''; + $saveOnServer = $this->config->settings['SaveDir'] !== ''; } } @@ -246,7 +248,7 @@ final readonly class ExportController implements InvocableController } // Open file on server if needed - if ($this->export->outputHandler->saveOnServer) { + if ($saveOnServer) { $message = $this->export->openFile($filename, $isQuickExport); // problem opening export file on server? @@ -389,7 +391,7 @@ final readonly class ExportController implements InvocableController // Ignore } - if ($this->export->outputHandler->saveOnServer && Current::$message !== null) { + if ($saveOnServer && Current::$message !== null) { $location = $this->export->getPageLocationAndSaveMessage($exportType, Current::$message); $this->response->redirect($location); @@ -411,8 +413,7 @@ final readonly class ExportController implements InvocableController // Compression needed? $this->export->outputHandler->compress($separateFiles !== '', $filename); - /* If we saved on server, we have to close file now */ - if ($this->export->outputHandler->saveOnServer) { + if ($saveOnServer) { $message = $this->export->outputHandler->closeFile(); $location = $this->export->getPageLocationAndSaveMessage($exportType, $message); $this->response->redirect($location); diff --git a/src/Export/OutputHandler.php b/src/Export/OutputHandler.php index 5ea6ddd323..1be043be2f 100644 --- a/src/Export/OutputHandler.php +++ b/src/Export/OutputHandler.php @@ -40,7 +40,6 @@ class OutputHandler public bool $outputKanjiConversion = false; public static bool $asFile = false; - public bool $saveOnServer = false; public string $saveFilename = ''; /** @var resource|null */ public mixed $fileHandle = null; @@ -81,7 +80,7 @@ class OutputHandler $this->dumpBuffer = (string) gzencode($this->dumpBuffer); } - if ($this->saveOnServer && $this->fileHandle !== null) { + if ($this->fileHandle !== null) { $writeResult = @fwrite($this->fileHandle, $this->dumpBuffer); // Here, use strlen rather than mb_strlen to get the length // in bytes to compare against the number of bytes written. @@ -112,7 +111,7 @@ class OutputHandler $line = Encoding::convertString('utf-8', Current::$charset ?? 'utf-8', $line); } - if ($this->saveOnServer && $this->fileHandle !== null && $line !== '') { + if ($this->fileHandle !== null && $line !== '') { $writeResult = @fwrite($this->fileHandle, $line); // Here, use strlen rather than mb_strlen to get the length // in bytes to compare against the number of bytes written. @@ -240,7 +239,7 @@ class OutputHandler return function_exists('gzencode') && ((! ini_get('zlib.output_compression') && ! $this->isGzHandlerEnabled()) - || $this->saveOnServer + || $this->fileHandle !== null || (new UserAgentParser(Core::getEnv('HTTP_USER_AGENT')))->getUserBrowserAgent() === 'CHROME'); } From 29f48465caea437dcacfe0ab1f1119d02abda642 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Sat, 22 Nov 2025 00:43:00 +0000 Subject: [PATCH 09/21] Clean up $compression Signed-off-by: Kamil Tekiela --- src/Controllers/Export/ExportController.php | 9 +++------ src/Export/Export.php | 9 ++++----- src/Export/OutputHandler.php | 20 +++++++++++++++++--- tests/unit/Export/ExportTest.php | 18 +++++++++++++----- 4 files changed, 37 insertions(+), 19 deletions(-) diff --git a/src/Controllers/Export/ExportController.php b/src/Controllers/Export/ExportController.php index 0befa5c493..bbf155e2da 100644 --- a/src/Controllers/Export/ExportController.php +++ b/src/Controllers/Export/ExportController.php @@ -152,8 +152,7 @@ final readonly class ExportController implements InvocableController } if (in_array($compressionParam, $compressionMethods, true)) { - $this->export->outputHandler->compression = $compressionParam; - $this->export->outputHandler->bufferNeeded = true; + $this->export->outputHandler->setCompression($compressionParam, $this->config->settings['CompressOnFly']); } if (($isQuickExport && $quickExportOnServer) || (! $isQuickExport && $onServerParam)) { @@ -219,7 +218,6 @@ final readonly class ExportController implements InvocableController && in_array(Current::$charset, Encoding::listEncodings(), true); // Use on the fly compression? - $this->export->outputHandler->onFlyCompression = $this->config->settings['CompressOnFly'] && ($this->export->outputHandler)->compression === 'gzip'; if ($this->export->outputHandler->onFlyCompression) { $this->export->outputHandler->memoryLimit = $this->export->getMemoryLimit(); } @@ -235,16 +233,15 @@ final readonly class ExportController implements InvocableController $filename = $this->export->getFinalFilename( $exportPlugin, - $this->export->outputHandler->compression, Sanitize::sanitizeFilename(Util::expandUserString($filenameTemplate), true), ); - $mimeType = $this->export->getMimeType($exportPlugin, $this->export->outputHandler->compression); + $mimeType = $this->export->getMimeType($exportPlugin); } // For raw query export, filename will be export.extension if ($exportType === ExportType::Raw) { - $filename = $this->export->getFinalFilename($exportPlugin, $this->export->outputHandler->compression, 'export'); + $filename = $this->export->getFinalFilename($exportPlugin, 'export'); } // Open file on server if needed diff --git a/src/Export/Export.php b/src/Export/Export.php index a232df8e67..720f903456 100644 --- a/src/Export/Export.php +++ b/src/Export/Export.php @@ -139,7 +139,6 @@ class Export public function getFinalFilename( ExportPlugin $exportPlugin, - string $compression, string $filename, ): string { // Grab basic dump extension and mime type @@ -153,18 +152,18 @@ class Export } // If dump is going to be compressed, add compression to extension - if ($compression === 'gzip') { + if ($this->outputHandler->compression === 'gzip') { $filename .= '.gz'; - } elseif ($compression === 'zip') { + } elseif ($this->outputHandler->compression === 'zip') { $filename .= '.zip'; } return $filename; } - public function getMimeType(ExportPlugin $exportPlugin, string $compression): string + public function getMimeType(ExportPlugin $exportPlugin): string { - return match ($compression) { + return match ($this->outputHandler->compression) { 'gzip' => 'application/x-gzip', 'zip' => 'application/zip', default => $exportPlugin->getProperties()->getMimeType(), diff --git a/src/Export/OutputHandler.php b/src/Export/OutputHandler.php index 1be043be2f..804811b505 100644 --- a/src/Export/OutputHandler.php +++ b/src/Export/OutputHandler.php @@ -43,14 +43,13 @@ class OutputHandler public string $saveFilename = ''; /** @var resource|null */ public mixed $fileHandle = null; - /** @var ''|'none'|'zip'|'gzip' */ + /** @var ''|'zip'|'gzip' */ public string $compression = ''; public string $kanjiEncoding = ''; public string $xkana = ''; public int $memoryLimit = 0; public bool $onFlyCompression = false; public int $timeStart = 0; - public bool $bufferNeeded = false; public function __invoke(string $line): bool { @@ -60,7 +59,7 @@ class OutputHandler } // If we have to buffer data, we will perform everything at once at the end - if ($this->bufferNeeded) { + if ($this->compression !== '') { $this->dumpBuffer .= $line; if ($this->onFlyCompression) { $this->dumpBufferLength += strlen($line); @@ -163,6 +162,21 @@ class OutputHandler $this->dumpBufferLength = 0; } + /** + * Sets the compression method + * + * @param 'zip'|'gzip' $compression + */ + public function setCompression(string $compression, bool $compressOnFly = false): void + { + $this->compression = $compression; + if ($compression !== 'gzip' || ! $compressOnFly) { + return; + } + + $this->onFlyCompression = true; + } + public function compress(bool $separateFiles, string $filename): void { $dumpBuffer = $separateFiles diff --git a/tests/unit/Export/ExportTest.php b/tests/unit/Export/ExportTest.php index 1875a36f14..cbc6293acb 100644 --- a/tests/unit/Export/ExportTest.php +++ b/tests/unit/Export/ExportTest.php @@ -70,11 +70,15 @@ class ExportTest extends AbstractTestCase $export = new Export($dbi); $relation = new Relation($dbi); $exportPlugin = new ExportPhparray($relation, new Export($dbi), new Transformations($dbi, $relation)); - $finalFileName = $export->getFinalFilename($exportPlugin, 'zip', 'myfilename'); + + $export->outputHandler->setCompression('zip'); + $finalFileName = $export->getFinalFilename($exportPlugin, 'myfilename'); self::assertSame('myfilename.php.zip', $finalFileName); - $finalFileName = $export->getFinalFilename($exportPlugin, 'gzip', 'myfilename'); + + $export->outputHandler->setCompression('gzip'); + $finalFileName = $export->getFinalFilename($exportPlugin, 'myfilename'); self::assertSame('myfilename.php.gz', $finalFileName); - $finalFileName = $export->getFinalFilename($exportPlugin, 'gzip', 'export.db1.table1.file'); + $finalFileName = $export->getFinalFilename($exportPlugin, 'export.db1.table1.file'); self::assertSame('export.db1.table1.file.php.gz', $finalFileName); } @@ -85,9 +89,13 @@ class ExportTest extends AbstractTestCase $export = new Export($dbi); $relation = new Relation($dbi); $exportPlugin = new ExportPhparray($relation, new Export($dbi), new Transformations($dbi, $relation)); - $mimeType = $export->getMimeType($exportPlugin, 'zip'); + + $export->outputHandler->setCompression('zip'); + $mimeType = $export->getMimeType($exportPlugin); self::assertSame('application/zip', $mimeType); - $mimeType = $export->getMimeType($exportPlugin, 'gzip'); + + $export->outputHandler->setCompression('gzip'); + $mimeType = $export->getMimeType($exportPlugin); self::assertSame('application/x-gzip', $mimeType); } From 75ee3e84162da7031f6a4ca1db8de65c0d86487c Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Sat, 22 Nov 2025 00:48:27 +0000 Subject: [PATCH 10/21] Clean up the code Signed-off-by: Kamil Tekiela --- src/Controllers/Export/ExportController.php | 2 +- src/Export/OutputHandler.php | 20 +++----------------- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/src/Controllers/Export/ExportController.php b/src/Controllers/Export/ExportController.php index bbf155e2da..54c0168627 100644 --- a/src/Controllers/Export/ExportController.php +++ b/src/Controllers/Export/ExportController.php @@ -405,7 +405,7 @@ final readonly class ExportController implements InvocableController } // Convert the charset if required. - ($this->export->outputHandler)->convertBufferCharset(); + $this->export->outputHandler->convertBufferCharset(); // Compression needed? $this->export->outputHandler->compress($separateFiles !== '', $filename); diff --git a/src/Export/OutputHandler.php b/src/Export/OutputHandler.php index 804811b505..8cd4c72534 100644 --- a/src/Export/OutputHandler.php +++ b/src/Export/OutputHandler.php @@ -65,13 +65,7 @@ class OutputHandler $this->dumpBufferLength += strlen($line); if ($this->dumpBufferLength > $this->memoryLimit) { - if ($this->outputCharsetConversion) { - $this->dumpBuffer = Encoding::convertString( - 'utf-8', - Current::$charset ?? 'utf-8', - $this->dumpBuffer, - ); - } + $this->convertBufferCharset(); if ($this->compression === 'gzip' && $this->gzencodeNeeded()) { // as a gzipped file @@ -81,12 +75,8 @@ class OutputHandler if ($this->fileHandle !== null) { $writeResult = @fwrite($this->fileHandle, $this->dumpBuffer); - // Here, use strlen rather than mb_strlen to get the length - // in bytes to compare against the number of bytes written. if ($writeResult !== strlen($this->dumpBuffer)) { - Current::$message = Message::error( - __('Insufficient space to save the file %s.'), - ); + Current::$message = Message::error(__('Insufficient space to save the file %s.')); Current::$message->addParam($this->saveFilename); return false; @@ -112,12 +102,8 @@ class OutputHandler if ($this->fileHandle !== null && $line !== '') { $writeResult = @fwrite($this->fileHandle, $line); - // Here, use strlen rather than mb_strlen to get the length - // in bytes to compare against the number of bytes written. if ($writeResult !== strlen($line)) { - Current::$message = Message::error( - __('Insufficient space to save the file %s.'), - ); + Current::$message = Message::error(__('Insufficient space to save the file %s.')); Current::$message->addParam($this->saveFilename); return false; From f89bfd594acf6f715fce1201caa42dee8686a34a Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Sat, 22 Nov 2025 15:55:01 +0000 Subject: [PATCH 11/21] Replace Export with OutputHandler Signed-off-by: Kamil Tekiela --- phpstan-baseline.neon | 2 +- src/Export/OutputHandler.php | 2 +- src/Plugins.php | 4 +- src/Plugins/Export/ExportCodegen.php | 4 +- src/Plugins/Export/ExportCsv.php | 4 +- src/Plugins/Export/ExportExcel.php | 4 +- src/Plugins/Export/ExportHtmlword.php | 18 +++---- src/Plugins/Export/ExportJson.php | 16 +++--- src/Plugins/Export/ExportLatex.php | 26 +++++----- src/Plugins/Export/ExportMediawiki.php | 4 +- src/Plugins/Export/ExportOds.php | 2 +- src/Plugins/Export/ExportOdt.php | 2 +- src/Plugins/Export/ExportPdf.php | 2 +- src/Plugins/Export/ExportPhparray.php | 10 ++-- src/Plugins/Export/ExportSql.php | 52 +++++++++---------- src/Plugins/Export/ExportTexytext.php | 10 ++-- src/Plugins/Export/ExportXml.php | 14 ++--- src/Plugins/Export/ExportYaml.php | 6 +-- src/Plugins/ExportPlugin.php | 4 +- tests/unit/Export/ExportTest.php | 8 +-- .../unit/Plugins/Export/ExportCodegenTest.php | 3 +- tests/unit/Plugins/Export/ExportCsvTest.php | 3 +- tests/unit/Plugins/Export/ExportExcelTest.php | 3 +- .../Plugins/Export/ExportHtmlwordTest.php | 5 +- tests/unit/Plugins/Export/ExportJsonTest.php | 3 +- tests/unit/Plugins/Export/ExportLatexTest.php | 3 +- .../Plugins/Export/ExportMediawikiTest.php | 3 +- tests/unit/Plugins/Export/ExportOdsTest.php | 3 +- tests/unit/Plugins/Export/ExportOdtTest.php | 5 +- tests/unit/Plugins/Export/ExportPdfTest.php | 3 +- .../Plugins/Export/ExportPhparrayTest.php | 3 +- tests/unit/Plugins/Export/ExportSqlTest.php | 5 +- .../Plugins/Export/ExportTexytextTest.php | 5 +- tests/unit/Plugins/Export/ExportXmlTest.php | 3 +- tests/unit/Plugins/Export/ExportYamlTest.php | 3 +- tests/unit/PluginsTest.php | 12 ++--- 36 files changed, 122 insertions(+), 137 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index c2ae2c35c4..c0f631456c 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -9436,7 +9436,7 @@ parameters: path: src/Plugins/Export/ExportPdf.php - - message: '#^Parameter \#1 \$line of callable PhpMyAdmin\\Export\\OutputHandler expects string, mixed given\.$#' + message: '#^Parameter \#1 \$line of method PhpMyAdmin\\Export\\OutputHandler\:\:addLine\(\) expects string, mixed given\.$#' identifier: argument.type count: 1 path: src/Plugins/Export/ExportPdf.php diff --git a/src/Export/OutputHandler.php b/src/Export/OutputHandler.php index 8cd4c72534..7f4c47482d 100644 --- a/src/Export/OutputHandler.php +++ b/src/Export/OutputHandler.php @@ -51,7 +51,7 @@ class OutputHandler public bool $onFlyCompression = false; public int $timeStart = 0; - public function __invoke(string $line): bool + public function addLine(string $line): bool { // Kanji encoding convert feature if ($this->outputKanjiConversion) { diff --git a/src/Plugins.php b/src/Plugins.php index 1579b905d3..b63accb756 100644 --- a/src/Plugins.php +++ b/src/Plugins.php @@ -78,7 +78,7 @@ class Plugins /** @psalm-suppress MixedMethodCall */ return new $class( $container->get(Relation::class), - $container->get(Export::class), + $container->get(Export::class)->outputHandler, $container->get(Transformations::class), ); } @@ -158,7 +158,7 @@ class Plugins $container = ContainerBuilder::getContainer(); $plugins[] = new $class( $container->get(Relation::class), - $container->get(Export::class), + $container->get(Export::class)->outputHandler, $container->get(Transformations::class), ); } elseif ($type === 'Import' && is_subclass_of($class, ImportPlugin::class)) { diff --git a/src/Plugins/Export/ExportCodegen.php b/src/Plugins/Export/ExportCodegen.php index c5f5898c33..8ae0d7182a 100644 --- a/src/Plugins/Export/ExportCodegen.php +++ b/src/Plugins/Export/ExportCodegen.php @@ -97,10 +97,10 @@ class ExportCodegen extends ExportPlugin array $aliases = [], ): bool { if ($this->format === self::HANDLER_NHIBERNATE_XML) { - return ($this->export->outputHandler)($this->handleNHibernateXMLBody($db, $table, $aliases)); + return $this->outputHandler->addLine($this->handleNHibernateXMLBody($db, $table, $aliases)); } - return ($this->export->outputHandler)($this->handleNHibernateCSBody($db, $table, $aliases)); + return $this->outputHandler->addLine($this->handleNHibernateCSBody($db, $table, $aliases)); } /** diff --git a/src/Plugins/Export/ExportCsv.php b/src/Plugins/Export/ExportCsv.php index 89309c314f..9c6c10d5f7 100644 --- a/src/Plugins/Export/ExportCsv.php +++ b/src/Plugins/Export/ExportCsv.php @@ -164,7 +164,7 @@ class ExportCsv extends ExportPlugin } $schemaInsert = implode($this->separator, $insertFields); - if (! ($this->export->outputHandler)($schemaInsert . $this->terminated)) { + if (! $this->outputHandler->addLine($schemaInsert . $this->terminated)) { return false; } } @@ -218,7 +218,7 @@ class ExportCsv extends ExportPlugin } $schemaInsert = implode($this->separator, $insertValues); - if (! ($this->export->outputHandler)($schemaInsert . $this->terminated)) { + if (! $this->outputHandler->addLine($schemaInsert . $this->terminated)) { return false; } } diff --git a/src/Plugins/Export/ExportExcel.php b/src/Plugins/Export/ExportExcel.php index 7ae97d3e10..9821527ca4 100644 --- a/src/Plugins/Export/ExportExcel.php +++ b/src/Plugins/Export/ExportExcel.php @@ -155,7 +155,7 @@ class ExportExcel extends ExportPlugin } $schemaInsert = implode($this->separator, $insertFields); - if (! ($this->export->outputHandler)($schemaInsert . $this->terminated)) { + if (! $this->outputHandler->addLine($schemaInsert . $this->terminated)) { return false; } } @@ -206,7 +206,7 @@ class ExportExcel extends ExportPlugin } $schemaInsert = implode($this->separator, $insertValues); - if (! ($this->export->outputHandler)($schemaInsert . $this->terminated)) { + if (! $this->outputHandler->addLine($schemaInsert . $this->terminated)) { return false; } } diff --git a/src/Plugins/Export/ExportHtmlword.php b/src/Plugins/Export/ExportHtmlword.php index 311bfb9fe8..bf5466f3ea 100644 --- a/src/Plugins/Export/ExportHtmlword.php +++ b/src/Plugins/Export/ExportHtmlword.php @@ -106,7 +106,7 @@ class ExportHtmlword extends ExportPlugin */ public function exportHeader(): bool { - return ($this->export->outputHandler)( + return $this->outputHandler->addLine( ' @@ -127,7 +127,7 @@ class ExportHtmlword extends ExportPlugin */ public function exportFooter(): bool { - return ($this->export->outputHandler)(''); + return $this->outputHandler->addLine(''); } /** @@ -142,7 +142,7 @@ class ExportHtmlword extends ExportPlugin $dbAlias = $db; } - return ($this->export->outputHandler)( + return $this->outputHandler->addLine( '

' . __('Database') . ' ' . htmlspecialchars($dbAlias) . '

', ); } @@ -164,7 +164,7 @@ class ExportHtmlword extends ExportPlugin $tableAlias = $this->getTableAlias($aliases, $db, $table); if ( - ! ($this->export->outputHandler)( + ! $this->outputHandler->addLine( '

' . __('Dumping data for table') . ' ' . htmlspecialchars($tableAlias) . '

', @@ -173,7 +173,7 @@ class ExportHtmlword extends ExportPlugin return false; } - if (! ($this->export->outputHandler)('')) { + if (! $this->outputHandler->addLine('
')) { return false; } @@ -195,7 +195,7 @@ class ExportHtmlword extends ExportPlugin } $schemaInsert .= ''; - if (! ($this->export->outputHandler)($schemaInsert)) { + if (! $this->outputHandler->addLine($schemaInsert)) { return false; } } @@ -210,12 +210,12 @@ class ExportHtmlword extends ExportPlugin } $schemaInsert .= ''; - if (! ($this->export->outputHandler)($schemaInsert)) { + if (! $this->outputHandler->addLine($schemaInsert)) { return false; } } - return ($this->export->outputHandler)('
'); + return $this->outputHandler->addLine(''); } /** @@ -480,7 +480,7 @@ class ExportHtmlword extends ExportPlugin $dump .= $this->getTableDefStandIn($db, $table, $aliases); } - return ($this->export->outputHandler)($dump); + return $this->outputHandler->addLine($dump); } /** diff --git a/src/Plugins/Export/ExportJson.php b/src/Plugins/Export/ExportJson.php index 16b821fda7..06ef02a770 100644 --- a/src/Plugins/Export/ExportJson.php +++ b/src/Plugins/Export/ExportJson.php @@ -116,7 +116,7 @@ class ExportJson extends ExportPlugin return false; } - return ($this->export->outputHandler)('[' . "\n" . $data . ',' . "\n"); + return $this->outputHandler->addLine('[' . "\n" . $data . ',' . "\n"); } /** @@ -124,7 +124,7 @@ class ExportJson extends ExportPlugin */ public function exportFooter(): bool { - return ($this->export->outputHandler)(']' . "\n"); + return $this->outputHandler->addLine(']' . "\n"); } /** @@ -144,7 +144,7 @@ class ExportJson extends ExportPlugin return false; } - return ($this->export->outputHandler)($data . ',' . "\n"); + return $this->outputHandler->addLine($data . ',' . "\n"); } /** @@ -165,7 +165,7 @@ class ExportJson extends ExportPlugin $tableAlias = $this->getTableAlias($aliases, $db, $table); if (! $this->first) { - if (! ($this->export->outputHandler)(',')) { + if (! $this->outputHandler->addLine(',')) { return false; } } else { @@ -208,7 +208,7 @@ class ExportJson extends ExportPlugin ): bool { [$header, $footer] = explode('"@@DATA@@"', $buffer); - if (! ($this->export->outputHandler)($header . "\n" . '[' . "\n")) { + if (! $this->outputHandler->addLine($header . "\n" . '[' . "\n")) { return false; } @@ -234,7 +234,7 @@ class ExportJson extends ExportPlugin // Output table name as comment if this is the first record of the table if ($recordCnt > 1) { - if (! ($this->export->outputHandler)(',' . "\n")) { + if (! $this->outputHandler->addLine(',' . "\n")) { return false; } } @@ -272,12 +272,12 @@ class ExportJson extends ExportPlugin return false; } - if (! ($this->export->outputHandler)($encodedData)) { + if (! $this->outputHandler->addLine($encodedData)) { return false; } } - return ($this->export->outputHandler)("\n" . ']' . "\n" . $footer . "\n"); + return $this->outputHandler->addLine("\n" . ']' . "\n" . $footer . "\n"); } /** diff --git a/src/Plugins/Export/ExportLatex.php b/src/Plugins/Export/ExportLatex.php index cb76cd0a51..7db719e11c 100644 --- a/src/Plugins/Export/ExportLatex.php +++ b/src/Plugins/Export/ExportLatex.php @@ -233,7 +233,7 @@ class ExportLatex extends ExportPlugin . '% ' . __('Server version:') . ' ' . DatabaseInterface::getInstance()->getVersionString() . "\n" . '% ' . __('PHP Version:') . ' ' . PHP_VERSION . "\n"; - return ($this->export->outputHandler)($head); + return $this->outputHandler->addLine($head); } /** @@ -252,7 +252,7 @@ class ExportLatex extends ExportPlugin . '% ' . __('Database:') . ' \'' . $dbAlias . '\'' . "\n" . '% ' . "\n"; - return ($this->export->outputHandler)($head); + return $this->outputHandler->addLine($head); } /** @@ -309,7 +309,7 @@ class ExportLatex extends ExportPlugin . '} \\\\'; } - if (! ($this->export->outputHandler)($buffer)) { + if (! $this->outputHandler->addLine($buffer)) { return false; } @@ -322,13 +322,13 @@ class ExportLatex extends ExportPlugin } $buffer = mb_substr($buffer, 0, -2) . '\\\\ \\hline \hline '; - if (! ($this->export->outputHandler)($buffer . ' \\endfirsthead ' . "\n")) { + if (! $this->outputHandler->addLine($buffer . ' \\endfirsthead ' . "\n")) { return false; } if ($this->caption) { if ( - ! ($this->export->outputHandler)( + ! $this->outputHandler->addLine( '\\caption{' . Util::expandUserString( $this->dataContinuedCaption, @@ -342,10 +342,10 @@ class ExportLatex extends ExportPlugin } } - if (! ($this->export->outputHandler)($buffer . '\\endhead \\endfoot' . "\n")) { + if (! $this->outputHandler->addLine($buffer . '\\endhead \\endfoot' . "\n")) { return false; } - } elseif (! ($this->export->outputHandler)('\\\\ \hline')) { + } elseif (! $this->outputHandler->addLine('\\\\ \hline')) { return false; } @@ -370,14 +370,14 @@ class ExportLatex extends ExportPlugin } $buffer .= ' \\\\ \\hline ' . "\n"; - if (! ($this->export->outputHandler)($buffer)) { + if (! $this->outputHandler->addLine($buffer)) { return false; } } $buffer = ' \\end{longtable}' . "\n"; - return ($this->export->outputHandler)($buffer); + return $this->outputHandler->addLine($buffer); } /** @@ -443,7 +443,7 @@ class ExportLatex extends ExportPlugin */ $buffer = "\n" . '%' . "\n" . '% ' . __('Structure:') . ' ' . $tableAlias . "\n" . '%' . "\n" . ' \\begin{longtable}{'; - if (! ($this->export->outputHandler)($buffer)) { + if (! $this->outputHandler->addLine($buffer)) { return false; } @@ -513,7 +513,7 @@ class ExportLatex extends ExportPlugin $buffer .= $header . ' \\\\ \\hline \\hline \\endhead \\endfoot ' . "\n"; - if (! ($this->export->outputHandler)($buffer)) { + if (! $this->outputHandler->addLine($buffer)) { return false; } @@ -565,14 +565,14 @@ class ExportLatex extends ExportPlugin $buffer = str_replace("\000", ' & ', $localBuffer); $buffer .= ' \\\\ \\hline ' . "\n"; - if (! ($this->export->outputHandler)($buffer)) { + if (! $this->outputHandler->addLine($buffer)) { return false; } } $buffer = ' \\end{longtable}' . "\n"; - return ($this->export->outputHandler)($buffer); + return $this->outputHandler->addLine($buffer); } /** diff --git a/src/Plugins/Export/ExportMediawiki.php b/src/Plugins/Export/ExportMediawiki.php index 75be7b74e0..6bc5abb086 100644 --- a/src/Plugins/Export/ExportMediawiki.php +++ b/src/Plugins/Export/ExportMediawiki.php @@ -166,7 +166,7 @@ class ExportMediawiki extends ExportPlugin $output .= '|}' . str_repeat($this->exportCRLF(), 2); } - return ($this->export->outputHandler)($output); + return $this->outputHandler->addLine($output); } /** @@ -240,7 +240,7 @@ class ExportMediawiki extends ExportPlugin // End table construction $output .= '|}' . str_repeat($this->exportCRLF(), 2); - return ($this->export->outputHandler)($output); + return $this->outputHandler->addLine($output); } /** diff --git a/src/Plugins/Export/ExportOds.php b/src/Plugins/Export/ExportOds.php index d8dc2c45c1..ada82672b5 100644 --- a/src/Plugins/Export/ExportOds.php +++ b/src/Plugins/Export/ExportOds.php @@ -142,7 +142,7 @@ class ExportOds extends ExportPlugin { $this->buffer .= ''; - return ($this->export->outputHandler)( + return $this->outputHandler->addLine( OpenDocument::create('application/vnd.oasis.opendocument.spreadsheet', $this->buffer), ); } diff --git a/src/Plugins/Export/ExportOdt.php b/src/Plugins/Export/ExportOdt.php index f67377fc89..b5db5fae69 100644 --- a/src/Plugins/Export/ExportOdt.php +++ b/src/Plugins/Export/ExportOdt.php @@ -163,7 +163,7 @@ class ExportOdt extends ExportPlugin { $this->buffer .= ''; - return ($this->export->outputHandler)(OpenDocument::create( + return $this->outputHandler->addLine(OpenDocument::create( 'application/vnd.oasis.opendocument.text', $this->buffer, )); diff --git a/src/Plugins/Export/ExportPdf.php b/src/Plugins/Export/ExportPdf.php index 7da6bf7be9..a834652401 100644 --- a/src/Plugins/Export/ExportPdf.php +++ b/src/Plugins/Export/ExportPdf.php @@ -104,7 +104,7 @@ class ExportPdf extends ExportPlugin public function exportFooter(): bool { // instead of $pdf->Output(): - return ($this->export->outputHandler)($this->pdf->getPDFData()); + return $this->outputHandler->addLine($this->pdf->getPDFData()); } /** diff --git a/src/Plugins/Export/ExportPhparray.php b/src/Plugins/Export/ExportPhparray.php index 2e010ad2c9..255b435b01 100644 --- a/src/Plugins/Export/ExportPhparray.php +++ b/src/Plugins/Export/ExportPhparray.php @@ -78,7 +78,7 @@ class ExportPhparray extends ExportPlugin */ public function exportHeader(): bool { - ($this->export->outputHandler)( + $this->outputHandler->addLine( 'export->outputHandler)( + $this->outputHandler->addLine( '/**' . "\n" . ' * Database ' . $this->commentString(Util::backquote($dbAlias)) . "\n" . ' */' . "\n", @@ -160,7 +160,7 @@ class ExportPhparray extends ExportPlugin . $this->commentString(Util::backquote($dbAlias)) . '.' . $this->commentString(Util::backquote($tableAlias)) . ' */' . "\n"; $buffer .= '$' . $tableFixed . ' = array('; - if (! ($this->export->outputHandler)($buffer)) { + if (! $this->outputHandler->addLine($buffer)) { return false; } @@ -183,7 +183,7 @@ class ExportPhparray extends ExportPlugin } $buffer .= ')'; - if (! ($this->export->outputHandler)($buffer)) { + if (! $this->outputHandler->addLine($buffer)) { return false; } @@ -193,7 +193,7 @@ class ExportPhparray extends ExportPlugin $buffer .= "\n" . ');' . "\n"; - return ($this->export->outputHandler)($buffer); + return $this->outputHandler->addLine($buffer); } /** diff --git a/src/Plugins/Export/ExportSql.php b/src/Plugins/Export/ExportSql.php index 003ad3869f..b0d070e90f 100644 --- a/src/Plugins/Export/ExportSql.php +++ b/src/Plugins/Export/ExportSql.php @@ -650,7 +650,7 @@ class ExportSql extends ExportPlugin } if ($text !== '') { - return ($this->export->outputHandler)($text); + return $this->outputHandler->addLine($text); } return false; @@ -733,7 +733,7 @@ class ExportSql extends ExportPlugin DatabaseInterface::getInstance()->query('SET time_zone = "' . self::$oldTimezone . '"'); } - return ($this->export->outputHandler)($foot); + return $this->outputHandler->addLine($foot); } /** @@ -829,7 +829,7 @@ class ExportSql extends ExportPlugin $this->sentCharset = true; } - return ($this->export->outputHandler)($head); + return $this->outputHandler->addLine($head); } /** @@ -846,7 +846,7 @@ class ExportSql extends ExportPlugin if ($this->structureOrData !== StructureOrData::Data && $this->dropDatabase) { if ( - ! ($this->export->outputHandler)( + ! $this->outputHandler->addLine( 'DROP DATABASE IF EXISTS ' . Util::backquoteCompat($dbAlias, $this->compatibility, $this->useSqlBackquotes) . ';' . "\n", @@ -876,7 +876,7 @@ class ExportSql extends ExportPlugin } $createQuery .= ';' . "\n"; - if (! ($this->export->outputHandler)($createQuery)) { + if (! $this->outputHandler->addLine($createQuery)) { return false; } @@ -892,14 +892,14 @@ class ExportSql extends ExportPlugin private function exportUseStatement(string $db, string $compat): bool { if ($compat === 'NONE') { - return ($this->export->outputHandler)( + return $this->outputHandler->addLine( 'USE ' . Util::backquoteCompat($db, $compat, $this->useSqlBackquotes) . ';' . "\n", ); } - return ($this->export->outputHandler)('USE ' . $db . ';' . "\n"); + return $this->outputHandler->addLine('USE ' . $db . ';' . "\n"); } /** @@ -925,7 +925,7 @@ class ExportSql extends ExportPlugin ) . $this->exportComment(); - return ($this->export->outputHandler)($head); + return $this->outputHandler->addLine($head); } /** @@ -939,25 +939,25 @@ class ExportSql extends ExportPlugin //add indexes to the sql dump file if ($this->sqlIndexes !== null) { - $result = ($this->export->outputHandler)($this->sqlIndexes); + $result = $this->outputHandler->addLine($this->sqlIndexes); $this->sqlIndexes = null; } //add auto increments to the sql dump file if ($this->sqlAutoIncrements !== null) { - $result = ($this->export->outputHandler)($this->sqlAutoIncrements); + $result = $this->outputHandler->addLine($this->sqlAutoIncrements); $this->sqlAutoIncrements = null; } //add views to the sql dump file if ($this->sqlViews !== '') { - $result = ($this->export->outputHandler)($this->sqlViews); + $result = $this->outputHandler->addLine($this->sqlViews); $this->sqlViews = ''; } //add constraints to the sql dump file if ($this->sqlConstraints !== null) { - $result = ($this->export->outputHandler)($this->sqlConstraints); + $result = $this->outputHandler->addLine($this->sqlConstraints); $this->sqlConstraints = null; } @@ -1015,7 +1015,7 @@ class ExportSql extends ExportPlugin } if ($text !== '') { - return ($this->export->outputHandler)($text); + return $this->outputHandler->addLine($text); } return false; @@ -1043,7 +1043,7 @@ class ExportSql extends ExportPlugin . $this->exportComment() . $this->exportComment(__('Metadata')) . $this->exportComment(); - if (! ($this->export->outputHandler)($comment)) { + if (! $this->outputHandler->addLine($comment)) { return false; } @@ -1121,7 +1121,7 @@ class ExportSql extends ExportPlugin $comment .= $this->exportComment(); - if (! ($this->export->outputHandler)($comment)) { + if (! $this->outputHandler->addLine($comment)) { return false; } @@ -1166,7 +1166,7 @@ class ExportSql extends ExportPlugin $lastPage = "\n" . 'SET @LAST_PAGE = LAST_INSERT_ID();' . "\n"; - if (! ($this->export->outputHandler)($lastPage)) { + if (! $this->outputHandler->addLine($lastPage)) { return false; } @@ -1975,7 +1975,7 @@ class ExportSql extends ExportPlugin // but not in the case of export $this->sqlConstraintsQuery = ''; - return ($this->export->outputHandler)($dump); + return $this->outputHandler->addLine($dump); } /** @@ -2012,7 +2012,7 @@ class ExportSql extends ExportPlugin . $this->exportComment() . $this->possibleCRLF(); - return ($this->export->outputHandler)($head); + return $this->outputHandler->addLine($head); } $result = $dbi->tryQuery($sqlQuery, ConnectionType::User, DatabaseInterface::QUERY_UNBUFFERED); @@ -2083,8 +2083,8 @@ class ExportSql extends ExportPlugin ) . $this->exportComment() . "\n"; - ($this->export->outputHandler)($truncatehead); - ($this->export->outputHandler)($truncate); + $this->outputHandler->addLine($truncatehead); + $this->outputHandler->addLine($truncate); } // scheme for inserting fields @@ -2120,7 +2120,7 @@ class ExportSql extends ExportPlugin ) . $this->exportComment() . "\n"; - if (! ($this->export->outputHandler)($head)) { + if (! $this->outputHandler->addLine($head)) { return false; } } @@ -2128,7 +2128,7 @@ class ExportSql extends ExportPlugin // We need to SET IDENTITY_INSERT ON for MSSQL if ($currentRow === 0 && $this->compatibility === 'MSSQL') { if ( - ! ($this->export->outputHandler)( + ! $this->outputHandler->addLine( 'SET IDENTITY_INSERT ' . Util::backquoteCompat($tableAlias, $this->compatibility, $this->useSqlBackquotes) . ' ON ;' . "\n", @@ -2207,7 +2207,7 @@ class ExportSql extends ExportPlugin $insertLine = '(' . implode(', ', $values) . ')'; $insertLineSize = mb_strlen($insertLine); if ($this->maxQuerySize > 0 && $querySize + $insertLineSize > $this->maxQuerySize) { - if (! ($this->export->outputHandler)(';' . "\n")) { + if (! $this->outputHandler->addLine(';' . "\n")) { return false; } @@ -2223,20 +2223,20 @@ class ExportSql extends ExportPlugin $insertLine = $schemaInsert . '(' . implode(', ', $values) . ')'; } - if (! ($this->export->outputHandler)(($currentRow === 1 ? '' : $separator . "\n") . $insertLine)) { + if (! $this->outputHandler->addLine(($currentRow === 1 ? '' : $separator . "\n") . $insertLine)) { return false; } } if ($currentRow > 0) { - if (! ($this->export->outputHandler)(';' . "\n")) { + if (! $this->outputHandler->addLine(';' . "\n")) { return false; } } // We need to SET IDENTITY_INSERT OFF for MSSQL if ($this->compatibility === 'MSSQL' && $currentRow > 0) { - $outputSucceeded = ($this->export->outputHandler)( + $outputSucceeded = $this->outputHandler->addLine( "\n" . 'SET IDENTITY_INSERT ' . Util::backquoteCompat($tableAlias, $this->compatibility, $this->useSqlBackquotes) . ' OFF;' . "\n", diff --git a/src/Plugins/Export/ExportTexytext.php b/src/Plugins/Export/ExportTexytext.php index 684583989b..2751ebd7d6 100644 --- a/src/Plugins/Export/ExportTexytext.php +++ b/src/Plugins/Export/ExportTexytext.php @@ -111,7 +111,7 @@ class ExportTexytext extends ExportPlugin $dbAlias = $db; } - return ($this->export->outputHandler)( + return $this->outputHandler->addLine( '===' . __('Database') . ' ' . $dbAlias . "\n\n", ); } @@ -133,7 +133,7 @@ class ExportTexytext extends ExportPlugin $tableAlias = $this->getTableAlias($aliases, $db, $table); if ( - ! ($this->export->outputHandler)( + ! $this->outputHandler->addLine( $tableAlias !== '' ? '== ' . __('Dumping data for table') . ' ' . $tableAlias . "\n\n" : '==' . __('Dumping data for query result') . "\n\n", @@ -158,7 +158,7 @@ class ExportTexytext extends ExportPlugin } $textOutput .= "\n|------\n"; - if (! ($this->export->outputHandler)($textOutput)) { + if (! $this->outputHandler->addLine($textOutput)) { return false; } } @@ -184,7 +184,7 @@ class ExportTexytext extends ExportPlugin } $textOutput .= "\n"; - if (! ($this->export->outputHandler)($textOutput)) { + if (! $this->outputHandler->addLine($textOutput)) { return false; } } @@ -429,7 +429,7 @@ class ExportTexytext extends ExportPlugin $dump .= $this->getTableDefStandIn($db, $table, $aliases); } - return ($this->export->outputHandler)($dump); + return $this->outputHandler->addLine($dump); } /** diff --git a/src/Plugins/Export/ExportXml.php b/src/Plugins/Export/ExportXml.php index d9cf47d748..fd502ba4f5 100644 --- a/src/Plugins/Export/ExportXml.php +++ b/src/Plugins/Export/ExportXml.php @@ -194,7 +194,7 @@ class ExportXml extends ExportPlugin || $this->exportTriggers || $this->exportViews; - $charset = $this->export->outputHandler->outputCharsetConversion ? Current::$charset : 'utf-8'; + $charset = $this->outputHandler->outputCharsetConversion ? Current::$charset : 'utf-8'; $config = Config::getInstance(); $head = '' . "\n" @@ -336,7 +336,7 @@ class ExportXml extends ExportPlugin } } - return ($this->export->outputHandler)($head); + return $this->outputHandler->addLine($head); } /** @@ -346,7 +346,7 @@ class ExportXml extends ExportPlugin { $foot = ''; - return ($this->export->outputHandler)($foot); + return $this->outputHandler->addLine($foot); } /** @@ -368,7 +368,7 @@ class ExportXml extends ExportPlugin . ' -->' . "\n" . ' ' . "\n"; - return ($this->export->outputHandler)($head); + return $this->outputHandler->addLine($head); } return true; @@ -382,7 +382,7 @@ class ExportXml extends ExportPlugin public function exportDBFooter(string $db): bool { if ($this->exportContents) { - return ($this->export->outputHandler)(' ' . "\n"); + return $this->outputHandler->addLine(' ' . "\n"); } return true; @@ -417,7 +417,7 @@ class ExportXml extends ExportPlugin $buffer = ' ' . "\n"; - if (! ($this->export->outputHandler)($buffer)) { + if (! $this->outputHandler->addLine($buffer)) { return false; } @@ -441,7 +441,7 @@ class ExportXml extends ExportPlugin $buffer .= ' ' . "\n"; - if (! ($this->export->outputHandler)($buffer)) { + if (! $this->outputHandler->addLine($buffer)) { return false; } } diff --git a/src/Plugins/Export/ExportYaml.php b/src/Plugins/Export/ExportYaml.php index dfe7292ed3..fd46f87d6a 100644 --- a/src/Plugins/Export/ExportYaml.php +++ b/src/Plugins/Export/ExportYaml.php @@ -67,7 +67,7 @@ class ExportYaml extends ExportPlugin */ public function exportHeader(): bool { - ($this->export->outputHandler)('%YAML 1.1' . "\n" . '---' . "\n"); + $this->outputHandler->addLine('%YAML 1.1' . "\n" . '---' . "\n"); return true; } @@ -77,7 +77,7 @@ class ExportYaml extends ExportPlugin */ public function exportFooter(): bool { - ($this->export->outputHandler)('...' . "\n"); + $this->outputHandler->addLine('...' . "\n"); return true; } @@ -148,7 +148,7 @@ class ExportYaml extends ExportPlugin $buffer .= ' ' . $columns[$i] . ': "' . $record[$i] . '"' . "\n"; } - if (! ($this->export->outputHandler)($buffer)) { + if (! $this->outputHandler->addLine($buffer)) { return false; } } diff --git a/src/Plugins/ExportPlugin.php b/src/Plugins/ExportPlugin.php index 853a2824a9..487666c431 100644 --- a/src/Plugins/ExportPlugin.php +++ b/src/Plugins/ExportPlugin.php @@ -8,7 +8,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Plugins; use PhpMyAdmin\ConfigStorage\Relation; -use PhpMyAdmin\Export\Export; +use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Export\StructureOrData; use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\Properties\Plugins\ExportPluginProperties; @@ -37,7 +37,7 @@ abstract class ExportPlugin implements Plugin final public function __construct( public Relation $relation, - protected Export $export, + protected OutputHandler $outputHandler, public Transformations $transformations, ) { $this->properties = $this->setProperties(); diff --git a/tests/unit/Export/ExportTest.php b/tests/unit/Export/ExportTest.php index cbc6293acb..37566e4764 100644 --- a/tests/unit/Export/ExportTest.php +++ b/tests/unit/Export/ExportTest.php @@ -69,7 +69,7 @@ class ExportTest extends AbstractTestCase DatabaseInterface::$instance = $dbi; $export = new Export($dbi); $relation = new Relation($dbi); - $exportPlugin = new ExportPhparray($relation, new Export($dbi), new Transformations($dbi, $relation)); + $exportPlugin = new ExportPhparray($relation, $export->outputHandler, new Transformations($dbi, $relation)); $export->outputHandler->setCompression('zip'); $finalFileName = $export->getFinalFilename($exportPlugin, 'myfilename'); @@ -88,7 +88,7 @@ class ExportTest extends AbstractTestCase DatabaseInterface::$instance = $dbi; $export = new Export($dbi); $relation = new Relation($dbi); - $exportPlugin = new ExportPhparray($relation, new Export($dbi), new Transformations($dbi, $relation)); + $exportPlugin = new ExportPhparray($relation, $export->outputHandler, new Transformations($dbi, $relation)); $export->outputHandler->setCompression('zip'); $mimeType = $export->getMimeType($exportPlugin); @@ -138,7 +138,7 @@ class ExportTest extends AbstractTestCase ['test_table'], ['test_table'], ['test_table'], - new ExportSql($relation, $export, new Transformations($dbi, $relation)), + new ExportSql($relation, $export->outputHandler, new Transformations($dbi, $relation)), [], '', ); @@ -208,7 +208,7 @@ class ExportTest extends AbstractTestCase $relation = new Relation($dbi); $export->exportServer( ['test_db'], - new ExportSql($relation, $export, new Transformations($dbi, $relation)), + new ExportSql($relation, $export->outputHandler, new Transformations($dbi, $relation)), [], '', ); diff --git a/tests/unit/Plugins/Export/ExportCodegenTest.php b/tests/unit/Plugins/Export/ExportCodegenTest.php index a2148531bb..d1f06bf011 100644 --- a/tests/unit/Plugins/Export/ExportCodegenTest.php +++ b/tests/unit/Plugins/Export/ExportCodegenTest.php @@ -6,7 +6,6 @@ namespace PhpMyAdmin\Tests\Plugins\Export; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Dbal\DatabaseInterface; -use PhpMyAdmin\Export\Export; use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Plugins\Export\ExportCodegen; @@ -41,7 +40,7 @@ class ExportCodegenTest extends AbstractTestCase $dbi = $this->createDatabaseInterface(); DatabaseInterface::$instance = $dbi; $relation = new Relation($dbi); - $this->object = new ExportCodegen($relation, new Export($dbi), new Transformations($dbi, $relation)); + $this->object = new ExportCodegen($relation, new OutputHandler(), new Transformations($dbi, $relation)); } /** diff --git a/tests/unit/Plugins/Export/ExportCsvTest.php b/tests/unit/Plugins/Export/ExportCsvTest.php index 3504de5343..187fd70920 100644 --- a/tests/unit/Plugins/Export/ExportCsvTest.php +++ b/tests/unit/Plugins/Export/ExportCsvTest.php @@ -7,7 +7,6 @@ namespace PhpMyAdmin\Tests\Plugins\Export; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Current; use PhpMyAdmin\Dbal\DatabaseInterface; -use PhpMyAdmin\Export\Export; use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Plugins\Export\ExportCsv; @@ -47,7 +46,7 @@ class ExportCsvTest extends AbstractTestCase Current::$lang = ''; $relation = new Relation($dbi); - $this->object = new ExportCsv($relation, new Export($dbi), new Transformations($dbi, $relation)); + $this->object = new ExportCsv($relation, new OutputHandler(), new Transformations($dbi, $relation)); } /** diff --git a/tests/unit/Plugins/Export/ExportExcelTest.php b/tests/unit/Plugins/Export/ExportExcelTest.php index a2530482d0..2024943c8f 100644 --- a/tests/unit/Plugins/Export/ExportExcelTest.php +++ b/tests/unit/Plugins/Export/ExportExcelTest.php @@ -6,7 +6,6 @@ namespace PhpMyAdmin\Tests\Plugins\Export; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Dbal\DatabaseInterface; -use PhpMyAdmin\Export\Export; use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Plugins\Export\ExportExcel; @@ -43,7 +42,7 @@ class ExportExcelTest extends AbstractTestCase $dbi = $this->createDatabaseInterface(); DatabaseInterface::$instance = $dbi; $relation = new Relation($dbi); - $this->object = new ExportExcel($relation, new Export($dbi), new Transformations($dbi, $relation)); + $this->object = new ExportExcel($relation, new OutputHandler(), new Transformations($dbi, $relation)); } /** diff --git a/tests/unit/Plugins/Export/ExportHtmlwordTest.php b/tests/unit/Plugins/Export/ExportHtmlwordTest.php index b364f557ca..529ddebfa7 100644 --- a/tests/unit/Plugins/Export/ExportHtmlwordTest.php +++ b/tests/unit/Plugins/Export/ExportHtmlwordTest.php @@ -10,7 +10,6 @@ use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\ConfigStorage\RelationParameters; use PhpMyAdmin\Current; use PhpMyAdmin\Dbal\DatabaseInterface; -use PhpMyAdmin\Export\Export; use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Identifiers\TableName; @@ -61,7 +60,7 @@ class ExportHtmlwordTest extends AbstractTestCase $relation = new Relation($this->dbi); $this->object = new ExportHtmlword( $relation, - new Export($this->dbi), + new OutputHandler(), new Transformations($this->dbi, $relation), ); OutputHandler::$asFile = true; @@ -372,7 +371,7 @@ class ExportHtmlwordTest extends AbstractTestCase $relation = new Relation($this->dbi); $this->object = $this->getMockBuilder(ExportHtmlword::class) ->onlyMethods(['formatOneColumnDefinition']) - ->setConstructorArgs([$relation, new Export($this->dbi), new Transformations($this->dbi, $relation)]) + ->setConstructorArgs([$relation, new OutputHandler(), new Transformations($this->dbi, $relation)]) ->getMock(); $keys = [['Non_unique' => 0, 'Column_name' => 'name1'], ['Non_unique' => 1, 'Column_name' => 'name2']]; diff --git a/tests/unit/Plugins/Export/ExportJsonTest.php b/tests/unit/Plugins/Export/ExportJsonTest.php index c18f88266b..5184e6911c 100644 --- a/tests/unit/Plugins/Export/ExportJsonTest.php +++ b/tests/unit/Plugins/Export/ExportJsonTest.php @@ -6,7 +6,6 @@ namespace PhpMyAdmin\Tests\Plugins\Export; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Dbal\DatabaseInterface; -use PhpMyAdmin\Export\Export; use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Plugins\Export\ExportJson; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup; @@ -38,7 +37,7 @@ class ExportJsonTest extends AbstractTestCase DatabaseInterface::$instance = $dbi; OutputHandler::$asFile = true; $relation = new Relation($dbi); - $this->object = new ExportJson($relation, new Export($dbi), new Transformations($dbi, $relation)); + $this->object = new ExportJson($relation, new OutputHandler(), new Transformations($dbi, $relation)); } /** diff --git a/tests/unit/Plugins/Export/ExportLatexTest.php b/tests/unit/Plugins/Export/ExportLatexTest.php index 8a44353ec1..6656d2f341 100644 --- a/tests/unit/Plugins/Export/ExportLatexTest.php +++ b/tests/unit/Plugins/Export/ExportLatexTest.php @@ -10,7 +10,6 @@ use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\ConfigStorage\RelationParameters; use PhpMyAdmin\Current; use PhpMyAdmin\Dbal\DatabaseInterface; -use PhpMyAdmin\Export\Export; use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Plugins\Export\ExportLatex; @@ -56,7 +55,7 @@ class ExportLatexTest extends AbstractTestCase Current::$database = 'db'; Current::$table = 'table'; $relation = new Relation($dbi); - $this->object = new ExportLatex($relation, new Export($dbi), new Transformations($dbi, $relation)); + $this->object = new ExportLatex($relation, new OutputHandler(), new Transformations($dbi, $relation)); } /** diff --git a/tests/unit/Plugins/Export/ExportMediawikiTest.php b/tests/unit/Plugins/Export/ExportMediawikiTest.php index db78381b01..bec7303ca9 100644 --- a/tests/unit/Plugins/Export/ExportMediawikiTest.php +++ b/tests/unit/Plugins/Export/ExportMediawikiTest.php @@ -8,7 +8,6 @@ use PhpMyAdmin\Column; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Current; use PhpMyAdmin\Dbal\DatabaseInterface; -use PhpMyAdmin\Export\Export; use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Plugins\Export\ExportMediawiki; @@ -49,7 +48,7 @@ class ExportMediawikiTest extends AbstractTestCase Current::$table = ''; Current::$lang = 'en'; $relation = new Relation($dbi); - $this->object = new ExportMediawiki($relation, new Export($dbi), new Transformations($dbi, $relation)); + $this->object = new ExportMediawiki($relation, new OutputHandler(), new Transformations($dbi, $relation)); } /** diff --git a/tests/unit/Plugins/Export/ExportOdsTest.php b/tests/unit/Plugins/Export/ExportOdsTest.php index 030410849a..8c66794bad 100644 --- a/tests/unit/Plugins/Export/ExportOdsTest.php +++ b/tests/unit/Plugins/Export/ExportOdsTest.php @@ -7,7 +7,6 @@ namespace PhpMyAdmin\Tests\Plugins\Export; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Dbal\ConnectionType; use PhpMyAdmin\Dbal\DatabaseInterface; -use PhpMyAdmin\Export\Export; use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Plugins\Export\ExportOds; @@ -55,7 +54,7 @@ class ExportOdsTest extends AbstractTestCase DatabaseInterface::$instance = $dbi; OutputHandler::$asFile = true; $relation = new Relation($dbi); - $this->object = new ExportOds($relation, new Export($dbi), new Transformations($dbi, $relation)); + $this->object = new ExportOds($relation, new OutputHandler(), new Transformations($dbi, $relation)); } /** diff --git a/tests/unit/Plugins/Export/ExportOdtTest.php b/tests/unit/Plugins/Export/ExportOdtTest.php index 49c668e552..76adf29f23 100644 --- a/tests/unit/Plugins/Export/ExportOdtTest.php +++ b/tests/unit/Plugins/Export/ExportOdtTest.php @@ -10,7 +10,6 @@ use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\ConfigStorage\RelationParameters; use PhpMyAdmin\Dbal\ConnectionType; use PhpMyAdmin\Dbal\DatabaseInterface; -use PhpMyAdmin\Export\Export; use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Identifiers\TableName; @@ -73,7 +72,7 @@ class ExportOdtTest extends AbstractTestCase ExportPlugin::$singleTable = false; Config::getInstance()->selectedServer['DisableIS'] = true; $relation = new Relation($this->dbi); - $this->object = new ExportOdt($relation, new Export($this->dbi), new Transformations($this->dbi, $relation)); + $this->object = new ExportOdt($relation, new OutputHandler(), new Transformations($this->dbi, $relation)); } /** @@ -571,7 +570,7 @@ class ExportOdtTest extends AbstractTestCase $relation = new Relation($this->dbi); $this->object = $this->getMockBuilder(ExportOdt::class) ->onlyMethods(['formatOneColumnDefinition']) - ->setConstructorArgs([$relation, new Export($this->dbi), new Transformations($this->dbi, $relation)]) + ->setConstructorArgs([$relation, new OutputHandler(), new Transformations($this->dbi, $relation)]) ->getMock(); // case 1 diff --git a/tests/unit/Plugins/Export/ExportPdfTest.php b/tests/unit/Plugins/Export/ExportPdfTest.php index 2641ce7143..9efbdf47de 100644 --- a/tests/unit/Plugins/Export/ExportPdfTest.php +++ b/tests/unit/Plugins/Export/ExportPdfTest.php @@ -6,7 +6,6 @@ namespace PhpMyAdmin\Tests\Plugins\Export; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Dbal\DatabaseInterface; -use PhpMyAdmin\Export\Export; use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Plugins\Export\ExportPdf; @@ -42,7 +41,7 @@ class ExportPdfTest extends AbstractTestCase DatabaseInterface::$instance = $dbi; OutputHandler::$asFile = true; $relation = new Relation($dbi); - $this->object = new ExportPdf($relation, new Export($dbi), new Transformations($dbi, $relation)); + $this->object = new ExportPdf($relation, new OutputHandler(), new Transformations($dbi, $relation)); } /** diff --git a/tests/unit/Plugins/Export/ExportPhparrayTest.php b/tests/unit/Plugins/Export/ExportPhparrayTest.php index 974dda4c72..671854ad49 100644 --- a/tests/unit/Plugins/Export/ExportPhparrayTest.php +++ b/tests/unit/Plugins/Export/ExportPhparrayTest.php @@ -7,7 +7,6 @@ namespace PhpMyAdmin\Tests\Plugins\Export; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Current; use PhpMyAdmin\Dbal\DatabaseInterface; -use PhpMyAdmin\Export\Export; use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Plugins\Export\ExportPhparray; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup; @@ -44,7 +43,7 @@ class ExportPhparrayTest extends AbstractTestCase Current::$table = ''; Current::$lang = 'en'; $relation = new Relation($dbi); - $this->object = new ExportPhparray($relation, new Export($dbi), new Transformations($dbi, $relation)); + $this->object = new ExportPhparray($relation, new OutputHandler(), new Transformations($dbi, $relation)); } /** diff --git a/tests/unit/Plugins/Export/ExportSqlTest.php b/tests/unit/Plugins/Export/ExportSqlTest.php index 35bdf6d17b..01e1767245 100644 --- a/tests/unit/Plugins/Export/ExportSqlTest.php +++ b/tests/unit/Plugins/Export/ExportSqlTest.php @@ -12,7 +12,6 @@ use PhpMyAdmin\Current; use PhpMyAdmin\Dbal\ConnectionType; use PhpMyAdmin\Dbal\DatabaseInterface; use PhpMyAdmin\Exceptions\ExportException; -use PhpMyAdmin\Export\Export; use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Plugins\Export\ExportSql; @@ -73,7 +72,7 @@ class ExportSqlTest extends AbstractTestCase ExportPlugin::$singleTable = false; $relation = new Relation($dbi); - $this->object = new ExportSql($relation, new Export($dbi), new Transformations($dbi, $relation)); + $this->object = new ExportSql($relation, new OutputHandler(), new Transformations($dbi, $relation)); $this->object->useSqlBackquotes(false); } @@ -883,7 +882,7 @@ class ExportSqlTest extends AbstractTestCase DatabaseInterface::$instance = $dbi; $relation = new Relation($dbi); - $this->object = new ExportSql($relation, new Export($dbi), new Transformations($dbi, $relation)); + $this->object = new ExportSql($relation, new OutputHandler(), new Transformations($dbi, $relation)); $this->object->useSqlBackquotes(false); $request = ServerRequestFactory::create()->createServerRequest('POST', 'https://example.com/') diff --git a/tests/unit/Plugins/Export/ExportTexytextTest.php b/tests/unit/Plugins/Export/ExportTexytextTest.php index d480c20741..a9b4452baa 100644 --- a/tests/unit/Plugins/Export/ExportTexytextTest.php +++ b/tests/unit/Plugins/Export/ExportTexytextTest.php @@ -11,7 +11,6 @@ use PhpMyAdmin\ConfigStorage\RelationParameters; use PhpMyAdmin\Current; use PhpMyAdmin\Dbal\ConnectionType; use PhpMyAdmin\Dbal\DatabaseInterface; -use PhpMyAdmin\Export\Export; use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Identifiers\TableName; @@ -69,7 +68,7 @@ class ExportTexytextTest extends AbstractTestCase $relation = new Relation($this->dbi); $this->object = new ExportTexytext( $relation, - new Export($this->dbi), + new OutputHandler(), new Transformations($this->dbi, $relation), ); } @@ -261,7 +260,7 @@ class ExportTexytextTest extends AbstractTestCase $relation = new Relation($this->dbi); $this->object = $this->getMockBuilder(ExportTexytext::class) ->onlyMethods(['formatOneColumnDefinition']) - ->setConstructorArgs([$relation, new Export($this->dbi), new Transformations($this->dbi, $relation)]) + ->setConstructorArgs([$relation, new OutputHandler(), new Transformations($this->dbi, $relation)]) ->getMock(); // case 1 diff --git a/tests/unit/Plugins/Export/ExportXmlTest.php b/tests/unit/Plugins/Export/ExportXmlTest.php index e2de0ff5db..e7ae76342e 100644 --- a/tests/unit/Plugins/Export/ExportXmlTest.php +++ b/tests/unit/Plugins/Export/ExportXmlTest.php @@ -8,7 +8,6 @@ use PhpMyAdmin\Config; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Current; use PhpMyAdmin\Dbal\DatabaseInterface; -use PhpMyAdmin\Export\Export; use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Plugins\Export\ExportXml; @@ -50,7 +49,7 @@ class ExportXmlTest extends AbstractTestCase Current::$database = 'db'; Config::getInstance()->selectedServer['DisableIS'] = true; $relation = new Relation($dbi); - $this->object = new ExportXml($relation, new Export($dbi), new Transformations($dbi, $relation)); + $this->object = new ExportXml($relation, new OutputHandler(), new Transformations($dbi, $relation)); } /** diff --git a/tests/unit/Plugins/Export/ExportYamlTest.php b/tests/unit/Plugins/Export/ExportYamlTest.php index cf0256701d..e0623776a9 100644 --- a/tests/unit/Plugins/Export/ExportYamlTest.php +++ b/tests/unit/Plugins/Export/ExportYamlTest.php @@ -7,7 +7,6 @@ namespace PhpMyAdmin\Tests\Plugins\Export; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Current; use PhpMyAdmin\Dbal\DatabaseInterface; -use PhpMyAdmin\Export\Export; use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Plugins\Export\ExportYaml; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup; @@ -44,7 +43,7 @@ class ExportYamlTest extends AbstractTestCase Current::$table = ''; Current::$lang = 'en'; $relation = new Relation($dbi); - $this->object = new ExportYaml($relation, new Export($dbi), new Transformations($dbi, $relation)); + $this->object = new ExportYaml($relation, new OutputHandler(), new Transformations($dbi, $relation)); } /** diff --git a/tests/unit/PluginsTest.php b/tests/unit/PluginsTest.php index 452782d696..6076ba453d 100644 --- a/tests/unit/PluginsTest.php +++ b/tests/unit/PluginsTest.php @@ -7,7 +7,7 @@ namespace PhpMyAdmin\Tests; use PhpMyAdmin\Config; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Dbal\DatabaseInterface; -use PhpMyAdmin\Export\Export; +use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Import\ImportSettings; use PhpMyAdmin\Plugins; use PhpMyAdmin\Plugins\ExportPlugin; @@ -105,12 +105,12 @@ class PluginsTest extends AbstractTestCase $dbi = DatabaseInterface::getInstance(); $relation = new Relation($dbi); $transformations = new Transformations($dbi, $relation); - $export = new Export($dbi); + $outputHandler = new OutputHandler(); $exportList = [ - new Plugins\Export\ExportJson($relation, $export, $transformations), - new Plugins\Export\ExportOds($relation, $export, $transformations), - new Plugins\Export\ExportSql($relation, $export, $transformations), - new Plugins\Export\ExportXml($relation, $export, $transformations), + new Plugins\Export\ExportJson($relation, $outputHandler, $transformations), + new Plugins\Export\ExportOds($relation, $outputHandler, $transformations), + new Plugins\Export\ExportSql($relation, $outputHandler, $transformations), + new Plugins\Export\ExportXml($relation, $outputHandler, $transformations), ]; $actual = Plugins::getChoice($exportList, 'xml'); $expected = [ From 59aed69062651d7b738a3e6d35711e4b2a9c4bc4 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Sat, 22 Nov 2025 20:08:57 +0000 Subject: [PATCH 12/21] Split up long lines Signed-off-by: Kamil Tekiela --- src/Controllers/Export/ExportController.php | 5 ++++- tests/unit/Plugins/Export/ExportCsvTest.php | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Controllers/Export/ExportController.php b/src/Controllers/Export/ExportController.php index 54c0168627..e4fcc77ce6 100644 --- a/src/Controllers/Export/ExportController.php +++ b/src/Controllers/Export/ExportController.php @@ -152,7 +152,10 @@ final readonly class ExportController implements InvocableController } if (in_array($compressionParam, $compressionMethods, true)) { - $this->export->outputHandler->setCompression($compressionParam, $this->config->settings['CompressOnFly']); + $this->export->outputHandler->setCompression( + $compressionParam, + $this->config->settings['CompressOnFly'], + ); } if (($isQuickExport && $quickExportOnServer) || (! $isQuickExport && $onServerParam)) { diff --git a/tests/unit/Plugins/Export/ExportCsvTest.php b/tests/unit/Plugins/Export/ExportCsvTest.php index 187fd70920..807200195d 100644 --- a/tests/unit/Plugins/Export/ExportCsvTest.php +++ b/tests/unit/Plugins/Export/ExportCsvTest.php @@ -299,7 +299,12 @@ class ExportCsvTest extends AbstractTestCase // case 4 $request = ServerRequestFactory::create()->createServerRequest('POST', 'https://example.com/') - ->withParsedBody(['csv_enclosed' => '|', 'csv_terminated' => "\n", 'csv_escaped' => '\\', 'csv_columns' => 'On']); + ->withParsedBody([ + 'csv_enclosed' => '|', + 'csv_terminated' => "\n", + 'csv_escaped' => '\\', + 'csv_columns' => 'On', + ]); $this->object->setExportOptions($request, []); $this->object->exportHeader(); From 0833498c0e42351363641abdbb013175a8a7c284 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Sat, 22 Nov 2025 20:19:24 +0000 Subject: [PATCH 13/21] Use DI for the new class Signed-off-by: Kamil Tekiela --- app/services.php | 4 +++- src/Export/Export.php | 5 +---- src/Plugins.php | 6 ++--- .../Export/ExportControllerTest.php | 5 +++-- tests/unit/Export/ExportTest.php | 22 +++++++++---------- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/app/services.php b/app/services.php index 26a0d961c9..57491a6504 100644 --- a/app/services.php +++ b/app/services.php @@ -23,6 +23,7 @@ use PhpMyAdmin\Error\ErrorHandler; use PhpMyAdmin\Error\ErrorReport; use PhpMyAdmin\Export\Export; use PhpMyAdmin\Export\Options; +use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Export\TemplateModel; use PhpMyAdmin\FileListing; use PhpMyAdmin\FlashMessenger; @@ -99,7 +100,7 @@ return [ 'arguments' => ['@http_request', '@relation', '@template', '@config'], ], 'events' => ['class' => Events::class, 'arguments' => ['@dbi']], - Export::class => ['class' => Export::class, 'arguments' => ['@dbi']], + Export::class => ['class' => Export::class, 'arguments' => ['@dbi', '@' . OutputHandler::class]], 'export' => Export::class, 'export_options' => [ 'class' => Options::class, @@ -235,6 +236,7 @@ return [ 'class' => Operations::class, 'arguments' => ['$dbi' => '@dbi', '$relation' => '@relation', '$tableMover' => '@table_mover'], ], + OutputHandler::class => ['class' => OutputHandler::class], 'partitioning_maintenance' => [ 'class' => Maintenance::class, 'arguments' => ['$dbi' => '@dbi'], diff --git a/src/Export/Export.php b/src/Export/Export.php index 720f903456..599192026c 100644 --- a/src/Export/Export.php +++ b/src/Export/Export.php @@ -58,11 +58,8 @@ class Export /** @var array */ public static array $tableData = []; - public OutputHandler $outputHandler; - - public function __construct(private DatabaseInterface $dbi) + public function __construct(private DatabaseInterface $dbi, public OutputHandler $outputHandler) { - $this->outputHandler = new OutputHandler(); } /** diff --git a/src/Plugins.php b/src/Plugins.php index b63accb756..821e639bbd 100644 --- a/src/Plugins.php +++ b/src/Plugins.php @@ -7,7 +7,7 @@ namespace PhpMyAdmin; use FilesystemIterator; use PhpMyAdmin\ConfigStorage\Relation; use PhpMyAdmin\Container\ContainerBuilder; -use PhpMyAdmin\Export\Export; +use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Html\MySQLDocumentation; use PhpMyAdmin\Import\ImportSettings; use PhpMyAdmin\Plugins\ExportPlugin; @@ -78,7 +78,7 @@ class Plugins /** @psalm-suppress MixedMethodCall */ return new $class( $container->get(Relation::class), - $container->get(Export::class)->outputHandler, + $container->get(OutputHandler::class), $container->get(Transformations::class), ); } @@ -158,7 +158,7 @@ class Plugins $container = ContainerBuilder::getContainer(); $plugins[] = new $class( $container->get(Relation::class), - $container->get(Export::class)->outputHandler, + $container->get(OutputHandler::class), $container->get(Transformations::class), ); } elseif ($type === 'Import' && is_subclass_of($class, ImportPlugin::class)) { diff --git a/tests/unit/Controllers/Export/ExportControllerTest.php b/tests/unit/Controllers/Export/ExportControllerTest.php index dfe5201e7f..b9c433a4dc 100644 --- a/tests/unit/Controllers/Export/ExportControllerTest.php +++ b/tests/unit/Controllers/Export/ExportControllerTest.php @@ -11,6 +11,7 @@ use PhpMyAdmin\Controllers\Export\ExportController; use PhpMyAdmin\Current; use PhpMyAdmin\Dbal\DatabaseInterface; use PhpMyAdmin\Export\Export; +use PhpMyAdmin\Export\OutputHandler; use PhpMyAdmin\Http\Factory\ResponseFactory; use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Http\ServerRequest; @@ -190,7 +191,7 @@ final class ExportControllerTest extends AbstractTestCase $exportController = new ExportController( new ResponseRenderer(), - new Export($dbi), + new Export($dbi, new OutputHandler()), ResponseFactory::create(), $config, ); @@ -355,7 +356,7 @@ final class ExportControllerTest extends AbstractTestCase $exportController = new ExportController( new ResponseRenderer(), - new Export($dbi), + new Export($dbi, new OutputHandler()), ResponseFactory::create(), $config, ); diff --git a/tests/unit/Export/ExportTest.php b/tests/unit/Export/ExportTest.php index 37566e4764..c09534b874 100644 --- a/tests/unit/Export/ExportTest.php +++ b/tests/unit/Export/ExportTest.php @@ -33,7 +33,7 @@ class ExportTest extends AbstractTestCase public function testMergeAliases(): void { DatabaseInterface::$instance = $this->createDatabaseInterface(); - $export = new Export(DatabaseInterface::getInstance()); + $export = new Export(DatabaseInterface::getInstance(), new OutputHandler()); $aliases1 = [ 'test_db' => [ 'alias' => 'aliastest', @@ -67,7 +67,7 @@ class ExportTest extends AbstractTestCase { $dbi = $this->createDatabaseInterface(); DatabaseInterface::$instance = $dbi; - $export = new Export($dbi); + $export = new Export($dbi, new OutputHandler()); $relation = new Relation($dbi); $exportPlugin = new ExportPhparray($relation, $export->outputHandler, new Transformations($dbi, $relation)); @@ -86,7 +86,7 @@ class ExportTest extends AbstractTestCase { $dbi = $this->createDatabaseInterface(); DatabaseInterface::$instance = $dbi; - $export = new Export($dbi); + $export = new Export($dbi, new OutputHandler()); $relation = new Relation($dbi); $exportPlugin = new ExportPhparray($relation, $export->outputHandler, new Transformations($dbi, $relation)); @@ -129,7 +129,7 @@ class ExportTest extends AbstractTestCase $dbi = $this->createDatabaseInterface($dbiDummy); DatabaseInterface::$instance = $dbi; - $export = new Export($dbi); + $export = new Export($dbi, new OutputHandler()); ExportPlugin::$exportType = ExportType::Database; $relation = new Relation($dbi); @@ -203,7 +203,7 @@ class ExportTest extends AbstractTestCase $dbi = $this->createDatabaseInterface($dbiDummy); DatabaseInterface::$instance = $dbi; - $export = new Export($dbi); + $export = new Export($dbi, new OutputHandler()); $relation = new Relation($dbi); $export->exportServer( @@ -233,7 +233,7 @@ class ExportTest extends AbstractTestCase Current::$server = 2; $_SESSION = []; $dbi = $this->createDatabaseInterface(); - $export = new Export($dbi); + $export = new Export($dbi, new OutputHandler()); $location = $export->getPageLocationAndSaveMessage(ExportType::Server, Message::error('Error message!')); self::assertSame('index.php?route=/server/export&server=2&lang=en', $location); self::assertSame( @@ -248,7 +248,7 @@ class ExportTest extends AbstractTestCase Current::$server = 2; $_SESSION = []; $dbi = $this->createDatabaseInterface(); - $export = new Export($dbi); + $export = new Export($dbi, new OutputHandler()); $location = $export->getPageLocationAndSaveMessage(ExportType::Server, Message::success('Success message!')); self::assertSame('index.php?route=/server/export&server=2&lang=en', $location); self::assertSame( @@ -264,7 +264,7 @@ class ExportTest extends AbstractTestCase Current::$database = 'test_db'; $_SESSION = []; $dbi = $this->createDatabaseInterface(); - $export = new Export($dbi); + $export = new Export($dbi, new OutputHandler()); $location = $export->getPageLocationAndSaveMessage(ExportType::Database, Message::error('Error message!')); self::assertSame('index.php?route=/database/export&db=test_db&server=2&lang=en', $location); self::assertSame( @@ -280,7 +280,7 @@ class ExportTest extends AbstractTestCase Current::$database = 'test_db'; $_SESSION = []; $dbi = $this->createDatabaseInterface(); - $export = new Export($dbi); + $export = new Export($dbi, new OutputHandler()); $location = $export->getPageLocationAndSaveMessage(ExportType::Database, Message::success('Success message!')); self::assertSame('index.php?route=/database/export&db=test_db&server=2&lang=en', $location); self::assertSame( @@ -297,7 +297,7 @@ class ExportTest extends AbstractTestCase Current::$table = 'test_table'; $_SESSION = []; $dbi = $this->createDatabaseInterface(); - $export = new Export($dbi); + $export = new Export($dbi, new OutputHandler()); $location = $export->getPageLocationAndSaveMessage(ExportType::Table, Message::error('Error message!')); self::assertSame( 'index.php?route=/table/export&db=test_db&table=test_table&single_table=true&server=2&lang=en', @@ -317,7 +317,7 @@ class ExportTest extends AbstractTestCase Current::$table = 'test_table'; $_SESSION = []; $dbi = $this->createDatabaseInterface(); - $export = new Export($dbi); + $export = new Export($dbi, new OutputHandler()); $location = $export->getPageLocationAndSaveMessage(ExportType::Table, Message::success('Success message!')); self::assertSame( 'index.php?route=/table/export&db=test_db&table=test_table&single_table=true&server=2&lang=en', From a513eb45df65f9bdecd598090e847cee99f37093 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Sat, 22 Nov 2025 20:38:19 +0000 Subject: [PATCH 14/21] Remove $_POST from openFile Signed-off-by: Kamil Tekiela --- phpstan-baseline.neon | 2 +- psalm-baseline.xml | 1 - src/Controllers/Export/ExportController.php | 7 ++++++- src/Export/Export.php | 18 +++--------------- 4 files changed, 10 insertions(+), 18 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index c0f631456c..47dcf9e734 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -6144,7 +6144,7 @@ parameters: - message: '#^Construct empty\(\) is not allowed\. Use more strict comparison\.$#' identifier: empty.notAllowed - count: 4 + count: 3 path: src/Export/Export.php - diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 2ae66f41a5..608b963aa0 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -4164,7 +4164,6 @@ -
diff --git a/src/Controllers/Export/ExportController.php b/src/Controllers/Export/ExportController.php index e4fcc77ce6..3e52abbfb4 100644 --- a/src/Controllers/Export/ExportController.php +++ b/src/Controllers/Export/ExportController.php @@ -249,7 +249,12 @@ final readonly class ExportController implements InvocableController // Open file on server if needed if ($saveOnServer) { - $message = $this->export->openFile($filename, $isQuickExport); + $message = $this->export->openFile( + $filename, + $isQuickExport, + $request->getParsedBodyParam('quick_export_onserver_overwrite') === 'saveitover', + $request->getParsedBodyParam('onserver_overwrite') === 'saveitover', + ); // problem opening export file on server? if ($message !== null) { diff --git a/src/Export/Export.php b/src/Export/Export.php index 599192026c..6d7f731f51 100644 --- a/src/Export/Export.php +++ b/src/Export/Export.php @@ -183,30 +183,18 @@ class Export } } - /** - * Open the export file - * - * @param string $filename the export filename - * @param bool $quickExport whether it's a quick export or not - */ - public function openFile(string $filename, bool $quickExport): Message|null + public function openFile(string $filename, bool $quickExport, bool $quickOverwriteFile, bool $overwriteFile): Message|null { $fileHandle = null; $message = null; - $doNotSaveItOver = true; - - if (isset($_POST['quick_export_onserver_overwrite'])) { - $doNotSaveItOver = $_POST['quick_export_onserver_overwrite'] !== 'saveitover'; - } $saveFilename = Util::userDir(Config::getInstance()->settings['SaveDir'] ?? '') . preg_replace('@[/\\\\]@', '_', $filename); if ( @file_exists($saveFilename) - && ((! $quickExport && empty($_POST['onserver_overwrite'])) - || ($quickExport - && $doNotSaveItOver)) + && ((! $quickExport && ! $overwriteFile) + || ($quickExport && ! $quickOverwriteFile)) ) { $message = Message::error( __( From 79987b5b49cc6f9fd9f71b21f4aa4ce39f1e2aff Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Sat, 22 Nov 2025 20:43:40 +0000 Subject: [PATCH 15/21] Move openFile to the new class Signed-off-by: Kamil Tekiela --- phpstan-baseline.neon | 18 +++---- psalm-baseline.xml | 6 +-- src/Controllers/Export/ExportController.php | 2 +- src/Export/Export.php | 49 ------------------- src/Export/OutputHandler.php | 52 +++++++++++++++++++++ 5 files changed, 65 insertions(+), 62 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 47dcf9e734..584d2054d8 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -6090,15 +6090,6 @@ parameters: count: 2 path: src/Export/Export.php - - - message: ''' - #^Call to deprecated method getInstance\(\) of class PhpMyAdmin\\Config\: - Use dependency injection instead\.$# - ''' - identifier: staticMethod.deprecated - count: 1 - path: src/Export/Export.php - - message: '#^Call to function in_array\(\) requires parameter \#3 to be set\.$#' identifier: function.strict @@ -6225,6 +6216,15 @@ parameters: count: 1 path: src/Export/Options.php + - + message: ''' + #^Call to deprecated method getInstance\(\) of class PhpMyAdmin\\Config\: + Use dependency injection instead\.$# + ''' + identifier: staticMethod.deprecated + count: 1 + path: src/Export/OutputHandler.php + - message: '#^Only booleans are allowed in a negated boolean, string\|false given\.$#' identifier: booleanNot.exprNotBoolean diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 608b963aa0..db92818d98 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -4108,9 +4108,6 @@ - - - @@ -4191,6 +4188,9 @@ + + + fileHandle]]> diff --git a/src/Controllers/Export/ExportController.php b/src/Controllers/Export/ExportController.php index 3e52abbfb4..8c77158666 100644 --- a/src/Controllers/Export/ExportController.php +++ b/src/Controllers/Export/ExportController.php @@ -249,7 +249,7 @@ final readonly class ExportController implements InvocableController // Open file on server if needed if ($saveOnServer) { - $message = $this->export->openFile( + $message = $this->export->outputHandler->openFile( $filename, $isQuickExport, $request->getParsedBodyParam('quick_export_onserver_overwrite') === 'saveitover', diff --git a/src/Export/Export.php b/src/Export/Export.php index 6d7f731f51..18395cc38c 100644 --- a/src/Export/Export.php +++ b/src/Export/Export.php @@ -28,8 +28,6 @@ use function __; use function array_filter; use function array_merge_recursive; use function error_get_last; -use function file_exists; -use function fopen; use function htmlentities; use function http_build_query; use function implode; @@ -37,9 +35,7 @@ use function in_array; use function ini_get; use function ini_parse_quantity; use function is_array; -use function is_file; use function is_numeric; -use function is_writable; use function mb_strlen; use function mb_strtolower; use function mb_substr; @@ -183,51 +179,6 @@ class Export } } - public function openFile(string $filename, bool $quickExport, bool $quickOverwriteFile, bool $overwriteFile): Message|null - { - $fileHandle = null; - $message = null; - - $saveFilename = Util::userDir(Config::getInstance()->settings['SaveDir'] ?? '') - . preg_replace('@[/\\\\]@', '_', $filename); - - if ( - @file_exists($saveFilename) - && ((! $quickExport && ! $overwriteFile) - || ($quickExport && ! $quickOverwriteFile)) - ) { - $message = Message::error( - __( - 'File %s already exists on server, change filename or check overwrite option.', - ), - ); - $message->addParam($saveFilename); - } elseif (@is_file($saveFilename) && ! @is_writable($saveFilename)) { - $message = Message::error( - __( - 'The web server does not have permission to save the file %s.', - ), - ); - $message->addParam($saveFilename); - } else { - $fileHandle = @fopen($saveFilename, 'w'); - if ($fileHandle === false) { - $fileHandle = null; - $message = Message::error( - __( - 'The web server does not have permission to save the file %s.', - ), - ); - $message->addParam($saveFilename); - } - } - - $this->outputHandler->saveFilename = $saveFilename; - $this->outputHandler->fileHandle = $fileHandle; - - return $message; - } - /** * Returns HTML containing the header for a displayed export * diff --git a/src/Export/OutputHandler.php b/src/Export/OutputHandler.php index 7f4c47482d..f146e18fb7 100644 --- a/src/Export/OutputHandler.php +++ b/src/Export/OutputHandler.php @@ -4,16 +4,20 @@ declare(strict_types=1); namespace PhpMyAdmin\Export; +use PhpMyAdmin\Config; use PhpMyAdmin\Core; use PhpMyAdmin\Current; use PhpMyAdmin\Encoding; use PhpMyAdmin\Message; use PhpMyAdmin\MessageType; +use PhpMyAdmin\Util; use PhpMyAdmin\Utils\UserAgentParser; use PhpMyAdmin\ZipExtension; use function __; use function fclose; +use function file_exists; +use function fopen; use function function_exists; use function fwrite; use function gzencode; @@ -21,8 +25,11 @@ use function header; use function htmlspecialchars; use function in_array; use function ini_get; +use function is_file; use function is_string; +use function is_writable; use function ob_list_handlers; +use function preg_replace; use function strlen; use function substr; use function time; @@ -178,6 +185,51 @@ class OutputHandler } } + public function openFile(string $filename, bool $quickExport, bool $quickOverwriteFile, bool $overwriteFile): Message|null + { + $fileHandle = null; + $message = null; + + $saveFilename = Util::userDir(Config::getInstance()->settings['SaveDir'] ?? '') + . preg_replace('@[/\\\\]@', '_', $filename); + + if ( + @file_exists($saveFilename) + && ((! $quickExport && ! $overwriteFile) + || ($quickExport && ! $quickOverwriteFile)) + ) { + $message = Message::error( + __( + 'File %s already exists on server, change filename or check overwrite option.', + ), + ); + $message->addParam($saveFilename); + } elseif (@is_file($saveFilename) && ! @is_writable($saveFilename)) { + $message = Message::error( + __( + 'The web server does not have permission to save the file %s.', + ), + ); + $message->addParam($saveFilename); + } else { + $fileHandle = @fopen($saveFilename, 'w'); + if ($fileHandle === false) { + $fileHandle = null; + $message = Message::error( + __( + 'The web server does not have permission to save the file %s.', + ), + ); + $message->addParam($saveFilename); + } + } + + $this->saveFilename = $saveFilename; + $this->fileHandle = $fileHandle; + + return $message; + } + public function closeFile(): Message { $writeResult = false; From 1519d2bda70f36c060d7747bf4a4908780a12b36 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Sat, 22 Nov 2025 20:59:00 +0000 Subject: [PATCH 16/21] Refactor closeFile Signed-off-by: Kamil Tekiela --- psalm-baseline.xml | 3 --- src/Export/OutputHandler.php | 22 ++++++++++------------ 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/psalm-baseline.xml b/psalm-baseline.xml index db92818d98..5242756e83 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -4191,9 +4191,6 @@ - - fileHandle]]> - createFile($dumpBuffer, $filename)]]> diff --git a/src/Export/OutputHandler.php b/src/Export/OutputHandler.php index f146e18fb7..c4c2088358 100644 --- a/src/Export/OutputHandler.php +++ b/src/Export/OutputHandler.php @@ -232,21 +232,19 @@ class OutputHandler public function closeFile(): Message { - $writeResult = false; if ($this->fileHandle !== null) { - $writeResult = @fwrite($this->fileHandle, $this->dumpBuffer); - fclose($this->fileHandle); + $fileHandle = $this->fileHandle; $this->fileHandle = null; - } + $writeResult = @fwrite($fileHandle, $this->dumpBuffer); + fclose($fileHandle); - // Here, use strlen rather than mb_strlen to get the length - // in bytes to compare against the number of bytes written. - if ($this->dumpBuffer !== '' && $writeResult !== strlen($this->dumpBuffer)) { - return new Message( - __('Insufficient space to save the file %s.'), - MessageType::Error, - [$this->saveFilename], - ); + if ($this->dumpBuffer !== '' && $writeResult !== strlen($this->dumpBuffer)) { + return new Message( + __('Insufficient space to save the file %s.'), + MessageType::Error, + [$this->saveFilename], + ); + } } return new Message( From 69a2a313db4ffba743b5c5ab55064d675eb64c01 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Sat, 22 Nov 2025 21:07:51 +0000 Subject: [PATCH 17/21] Refactor openFile Signed-off-by: Kamil Tekiela --- phpstan-baseline.neon | 9 ---- psalm-baseline.xml | 3 -- src/Controllers/Export/ExportController.php | 1 + src/Export/OutputHandler.php | 60 +++++++++++---------- 4 files changed, 34 insertions(+), 39 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 584d2054d8..c03f2434d9 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -6216,15 +6216,6 @@ parameters: count: 1 path: src/Export/Options.php - - - message: ''' - #^Call to deprecated method getInstance\(\) of class PhpMyAdmin\\Config\: - Use dependency injection instead\.$# - ''' - identifier: staticMethod.deprecated - count: 1 - path: src/Export/OutputHandler.php - - message: '#^Only booleans are allowed in a negated boolean, string\|false given\.$#' identifier: booleanNot.exprNotBoolean diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 5242756e83..c971133510 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -4188,9 +4188,6 @@ - - - createFile($dumpBuffer, $filename)]]> diff --git a/src/Controllers/Export/ExportController.php b/src/Controllers/Export/ExportController.php index 8c77158666..85cd3e37a9 100644 --- a/src/Controllers/Export/ExportController.php +++ b/src/Controllers/Export/ExportController.php @@ -250,6 +250,7 @@ final readonly class ExportController implements InvocableController // Open file on server if needed if ($saveOnServer) { $message = $this->export->outputHandler->openFile( + $this->config->settings['SaveDir'] ?? '', $filename, $isQuickExport, $request->getParsedBodyParam('quick_export_onserver_overwrite') === 'saveitover', diff --git a/src/Export/OutputHandler.php b/src/Export/OutputHandler.php index c4c2088358..681254ee4a 100644 --- a/src/Export/OutputHandler.php +++ b/src/Export/OutputHandler.php @@ -4,7 +4,6 @@ declare(strict_types=1); namespace PhpMyAdmin\Export; -use PhpMyAdmin\Config; use PhpMyAdmin\Core; use PhpMyAdmin\Current; use PhpMyAdmin\Encoding; @@ -47,9 +46,9 @@ class OutputHandler public bool $outputKanjiConversion = false; public static bool $asFile = false; - public string $saveFilename = ''; + private string $saveFilename = ''; /** @var resource|null */ - public mixed $fileHandle = null; + private mixed $fileHandle = null; /** @var ''|'zip'|'gzip' */ public string $compression = ''; public string $kanjiEncoding = ''; @@ -185,16 +184,17 @@ class OutputHandler } } - public function openFile(string $filename, bool $quickExport, bool $quickOverwriteFile, bool $overwriteFile): Message|null - { - $fileHandle = null; - $message = null; - - $saveFilename = Util::userDir(Config::getInstance()->settings['SaveDir'] ?? '') - . preg_replace('@[/\\\\]@', '_', $filename); + public function openFile( + string $saveDirectory, + string $filename, + bool $quickExport, + bool $quickOverwriteFile, + bool $overwriteFile, + ): Message|null { + $this->saveFilename = Util::userDir($saveDirectory) . preg_replace('@[/\\\\]@', '_', $filename); if ( - @file_exists($saveFilename) + @file_exists($this->saveFilename) && ((! $quickExport && ! $overwriteFile) || ($quickExport && ! $quickOverwriteFile)) ) { @@ -203,31 +203,37 @@ class OutputHandler 'File %s already exists on server, change filename or check overwrite option.', ), ); - $message->addParam($saveFilename); - } elseif (@is_file($saveFilename) && ! @is_writable($saveFilename)) { + $message->addParam($this->saveFilename); + + return $message; + } + + if (@is_file($this->saveFilename) && ! @is_writable($this->saveFilename)) { $message = Message::error( __( 'The web server does not have permission to save the file %s.', ), ); - $message->addParam($saveFilename); - } else { - $fileHandle = @fopen($saveFilename, 'w'); - if ($fileHandle === false) { - $fileHandle = null; - $message = Message::error( - __( - 'The web server does not have permission to save the file %s.', - ), - ); - $message->addParam($saveFilename); - } + $message->addParam($this->saveFilename); + + return $message; + } + + $fileHandle = @fopen($this->saveFilename, 'w'); + if ($fileHandle === false) { + $message = Message::error( + __( + 'The web server does not have permission to save the file %s.', + ), + ); + $message->addParam($this->saveFilename); + + return $message; } - $this->saveFilename = $saveFilename; $this->fileHandle = $fileHandle; - return $message; + return null; } public function closeFile(): Message From 3d8f0ae747dc136ecc381add4bcd93f95cd74bbb Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Sat, 22 Nov 2025 22:49:49 +0000 Subject: [PATCH 18/21] Refactor ExportCsv Signed-off-by: Kamil Tekiela --- src/Plugins/Export/ExportCsv.php | 100 ++++++++++++++----------------- 1 file changed, 45 insertions(+), 55 deletions(-) diff --git a/src/Plugins/Export/ExportCsv.php b/src/Plugins/Export/ExportCsv.php index 9c6c10d5f7..6d03e05fb3 100644 --- a/src/Plugins/Export/ExportCsv.php +++ b/src/Plugins/Export/ExportCsv.php @@ -22,8 +22,9 @@ use PhpMyAdmin\Properties\Plugins\ExportPluginProperties; use function __; use function implode; use function is_string; -use function str_contains; use function str_replace; +use function strcspn; +use function strlen; use function strtolower; /** @@ -137,30 +138,24 @@ class ExportCsv extends ExportPlugin array $aliases = [], ): bool { $dbi = DatabaseInterface::getInstance(); - /** - * Gets the data from the database - */ $result = $dbi->query($sqlQuery, ConnectionType::User, DatabaseInterface::QUERY_UNBUFFERED); + $charsNeedingEnclosure = $this->separator . $this->enclosed . $this->terminated; + // If required, get fields name at the first line if ($this->columns) { $insertFields = []; foreach ($result->getFieldNames() as $colAs) { $colAs = $this->getColumnAlias($aliases, $db, $table, $colAs); - - if ( - $this->enclosed === '' - || (! str_contains($colAs, $this->separator) - && ! str_contains($colAs, $this->enclosed) - && ! str_contains($colAs, $this->terminated) - ) - ) { + $needsEnclosing = strcspn($colAs, $charsNeedingEnclosure) !== strlen($colAs); + if ($this->enclosed === '' || ! $needsEnclosing) { $insertFields[] = $colAs; - } else { - $insertFields[] = $this->enclosed - . str_replace($this->enclosed, $this->escaped . $this->enclosed, $colAs) - . $this->enclosed; + continue; } + + $insertFields[] = $this->enclosed + . str_replace($this->enclosed, $this->escaped . $this->enclosed, $colAs) + . $this->enclosed; } $schemaInsert = implode($this->separator, $insertFields); @@ -175,46 +170,41 @@ class ExportCsv extends ExportPlugin foreach ($row as $field) { if ($field === null) { $insertValues[] = $this->null; - } elseif ($field !== '') { - // remove CRLF characters within field - if ($this->removeCrLf) { - $field = str_replace( - ["\r", "\n"], - '', - $field, - ); - } - - if ( - $this->enclosed === '' - || (! str_contains($field, $this->separator) - && ! str_contains($field, $this->enclosed) - && ! str_contains($field, $this->terminated) - ) - ) { - $insertValues[] = $field; - } elseif ($this->escaped !== $this->enclosed) { - // also double the escape string if found in the data - $insertValues[] = $this->enclosed - . str_replace( - $this->enclosed, - $this->escaped . $this->enclosed, - str_replace( - $this->escaped, - $this->escaped . $this->escaped, - $field, - ), - ) - . $this->enclosed; - } else { - // avoid a problem when escape string equals enclose - $insertValues[] = $this->enclosed - . str_replace($this->enclosed, $this->escaped . $this->enclosed, $field) - . $this->enclosed; - } - } else { - $insertValues[] = ''; + continue; } + + if ($field === '') { + $insertValues[] = ''; + continue; + } + + // remove CRLF characters within field + if ($this->removeCrLf) { + $field = str_replace(["\r", "\n"], '', $field); + } + + if ($this->enclosed === '') { + $insertValues[] = $field; + continue; + } + + $needsEnclosing = strcspn($field, $charsNeedingEnclosure) !== strlen($field); + + if (! $needsEnclosing) { + $insertValues[] = $field; + continue; + } + + if ($this->escaped !== $this->enclosed) { + // also double the escape string if found in the data + $field = str_replace($this->escaped, $this->escaped . $this->escaped, $field); + $field = str_replace($this->enclosed, $this->escaped . $this->enclosed, $field); + } else { + // avoid a problem when escape string equals enclose + $field = str_replace($this->enclosed, $this->escaped . $this->enclosed, $field); + } + + $insertValues[] = $this->enclosed . $field . $this->enclosed; } $schemaInsert = implode($this->separator, $insertValues); From 89d3769f0ab4af9048c886453b672ed2457ddb84 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Sat, 22 Nov 2025 23:24:43 +0000 Subject: [PATCH 19/21] Reducing nesting level in addLine Signed-off-by: Kamil Tekiela --- src/Export/OutputHandler.php | 50 ++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/src/Export/OutputHandler.php b/src/Export/OutputHandler.php index 681254ee4a..86817a7ba1 100644 --- a/src/Export/OutputHandler.php +++ b/src/Export/OutputHandler.php @@ -101,32 +101,38 @@ class OutputHandler header('X-pmaPing: Pong'); } } - } elseif (self::$asFile) { - if ($this->outputCharsetConversion) { - $line = Encoding::convertString('utf-8', Current::$charset ?? 'utf-8', $line); - } - if ($this->fileHandle !== null && $line !== '') { - $writeResult = @fwrite($this->fileHandle, $line); - if ($writeResult !== strlen($line)) { - Current::$message = Message::error(__('Insufficient space to save the file %s.')); - Current::$message->addParam($this->saveFilename); + return true; + } - return false; - } - - $timeNow = time(); - if ($this->timeStart >= $timeNow + 30) { - $this->timeStart = $timeNow; - header('X-pmaPing: Pong'); - } - } else { - // We export as file - output normally - echo $line; - } - } else { + if (! self::$asFile) { // We export as html - replace special chars echo htmlspecialchars($line, ENT_COMPAT); + + return true; + } + + if ($this->outputCharsetConversion) { + $line = Encoding::convertString('utf-8', Current::$charset ?? 'utf-8', $line); + } + + if ($this->fileHandle !== null && $line !== '') { + $writeResult = @fwrite($this->fileHandle, $line); + if ($writeResult !== strlen($line)) { + Current::$message = Message::error(__('Insufficient space to save the file %s.')); + Current::$message->addParam($this->saveFilename); + + return false; + } + + $timeNow = time(); + if ($this->timeStart >= $timeNow + 30) { + $this->timeStart = $timeNow; + header('X-pmaPing: Pong'); + } + } else { + // We export as file - output normally + echo $line; } return true; From 928ad061f0bc4040f70b40479db69efdf9c8a03e Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Sat, 22 Nov 2025 23:42:08 +0000 Subject: [PATCH 20/21] Remove dead code There is no way this has ever worked. The conditions are inverted and the logic doesn't make sense. Signed-off-by: Kamil Tekiela --- src/Controllers/Export/ExportController.php | 4 ---- src/Export/OutputHandler.php | 15 --------------- 2 files changed, 19 deletions(-) diff --git a/src/Controllers/Export/ExportController.php b/src/Controllers/Export/ExportController.php index 85cd3e37a9..8deecf7266 100644 --- a/src/Controllers/Export/ExportController.php +++ b/src/Controllers/Export/ExportController.php @@ -38,7 +38,6 @@ use function in_array; use function ini_set; use function is_array; use function register_shutdown_function; -use function time; #[Route('/export', ['GET', 'POST'])] final readonly class ExportController implements InvocableController @@ -209,9 +208,6 @@ final readonly class ExportController implements InvocableController register_shutdown_function([$this->export, 'shutdown']); - // We send fake headers to avoid browser timeout when buffering - $this->export->outputHandler->timeStart = time(); - $this->export->outputHandler->outputKanjiConversion = Encoding::canConvertKanji(); // Do we need to convert charset? diff --git a/src/Export/OutputHandler.php b/src/Export/OutputHandler.php index 86817a7ba1..c6d2895ccf 100644 --- a/src/Export/OutputHandler.php +++ b/src/Export/OutputHandler.php @@ -20,7 +20,6 @@ use function fopen; use function function_exists; use function fwrite; use function gzencode; -use function header; use function htmlspecialchars; use function in_array; use function ini_get; @@ -31,7 +30,6 @@ use function ob_list_handlers; use function preg_replace; use function strlen; use function substr; -use function time; use const ENT_COMPAT; @@ -55,7 +53,6 @@ class OutputHandler public string $xkana = ''; public int $memoryLimit = 0; public bool $onFlyCompression = false; - public int $timeStart = 0; public function addLine(string $line): bool { @@ -94,12 +91,6 @@ class OutputHandler $this->dumpBuffer = ''; $this->dumpBufferLength = 0; } - } else { - $timeNow = time(); - if ($this->timeStart >= $timeNow + 30) { - $this->timeStart = $timeNow; - header('X-pmaPing: Pong'); - } } return true; @@ -124,12 +115,6 @@ class OutputHandler return false; } - - $timeNow = time(); - if ($this->timeStart >= $timeNow + 30) { - $this->timeStart = $timeNow; - header('X-pmaPing: Pong'); - } } else { // We export as file - output normally echo $line; From 58b4fc74fa781e0c4766473f0909c8e5db0034f1 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Sun, 23 Nov 2025 00:12:11 +0000 Subject: [PATCH 21/21] Fix ExportTest Signed-off-by: Kamil Tekiela --- tests/end-to-end/ExportTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/end-to-end/ExportTest.php b/tests/end-to-end/ExportTest.php index 28d47b8ce3..b7f7442fea 100644 --- a/tests/end-to-end/ExportTest.php +++ b/tests/end-to-end/ExportTest.php @@ -95,7 +95,7 @@ class ExportTest extends TestBase public static function exportDataProvider(): array { return [ - ['CSV', ['"1","2"']], + ['CSV', ['1,2']], [ 'SQL', ['CREATE TABLE IF NOT EXISTS `test_table`', 'INSERT INTO `test_table` (`id`, `val`) VALUES', '(1, 2)'],