3 declare(strict_types
=1);
5 namespace PhpMyAdmin\Tests
;
9 use PhpMyAdmin\ConfigStorage\Relation
;
11 use PhpMyAdmin\Current
;
12 use PhpMyAdmin\Dbal\DatabaseInterface
;
13 use PhpMyAdmin\Dbal\Warning
;
14 use PhpMyAdmin\EditField
;
15 use PhpMyAdmin\FileListing
;
16 use PhpMyAdmin\InsertEdit
;
17 use PhpMyAdmin\InsertEditColumn
;
18 use PhpMyAdmin\ResponseRenderer
;
19 use PhpMyAdmin\Table\Table
;
20 use PhpMyAdmin\Template
;
21 use PhpMyAdmin\Tests\Stubs\DbiDummy
;
22 use PhpMyAdmin\Tests\Stubs\DummyResult
;
23 use PhpMyAdmin\Transformations
;
24 use PhpMyAdmin\TypeClass
;
26 use PhpMyAdmin\UrlParams
;
27 use PHPUnit\Framework\Attributes\CoversClass
;
28 use PHPUnit\Framework\Attributes\DataProvider
;
29 use PHPUnit\Framework\Attributes\Medium
;
30 use ReflectionProperty
;
33 use function is_object
;
34 use function is_scalar
;
35 use function is_string
;
36 use function mb_substr
;
38 use function password_verify
;
41 use const MYSQLI_PRI_KEY_FLAG
;
42 use const MYSQLI_TYPE_DECIMAL
;
43 use const MYSQLI_TYPE_TIMESTAMP
;
44 use const MYSQLI_TYPE_TINY
;
46 #[CoversClass(InsertEdit::class)]
47 #[CoversClass(EditField::class)]
48 #[CoversClass(InsertEditColumn::class)]
50 class InsertEditTest
extends AbstractTestCase
52 protected DatabaseInterface
$dbi;
54 protected DbiDummy
$dummyDbi;
56 private InsertEdit
$insertEdit;
59 * Setup for test cases
61 protected function setUp(): void
67 $this->setGlobalConfig();
69 $this->dummyDbi
= $this->createDbiDummy();
70 $this->dbi
= $this->createDatabaseInterface($this->dummyDbi
);
71 DatabaseInterface
::$instance = $this->dbi
;
72 $config = Config
::getInstance();
73 $config->settings
['ServerDefault'] = 1;
74 Current
::$database = 'db';
75 Current
::$table = 'table';
76 $config->settings
['LimitChars'] = 50;
77 $config->settings
['LongtextDoubleTextarea'] = false;
78 $config->settings
['ShowFieldTypesInDataEditView'] = true;
79 $config->settings
['ShowFunctionFields'] = true;
80 $config->settings
['ProtectBinary'] = 'blob';
81 $config->settings
['MaxSizeForInputField'] = 10;
82 $config->settings
['MinSizeForInputField'] = 2;
83 $config->settings
['TextareaRows'] = 5;
84 $config->settings
['TextareaCols'] = 4;
85 $config->settings
['CharTextareaRows'] = 5;
86 $config->settings
['CharTextareaCols'] = 6;
87 $config->settings
['AllowThirdPartyFraming'] = false;
88 $config->set('SendErrorReports', 'ask');
89 $config->settings
['DefaultTabDatabase'] = '/database/structure';
90 $config->settings
['ShowDatabasesNavigationAsTree'] = true;
91 $config->settings
['DefaultTabTable'] = '/sql';
92 $config->settings
['NavigationTreeDefaultTabTable'] = '/table/structure';
93 $config->settings
['NavigationTreeDefaultTabTable2'] = '';
94 $config->settings
['Confirm'] = true;
95 $config->settings
['LoginCookieValidity'] = 1440;
96 $config->settings
['enable_drag_drop_import'] = true;
97 $this->insertEdit
= new InsertEdit(
99 new Relation($this->dbi
),
100 new Transformations(),
106 $this->dbi
->setVersion([
107 '@@version' => '10.9.3-MariaDB-1:10.9.3+maria~ubu2204',
108 '@@version_comment' => 'mariadb.org binary distribution',
113 * Teardown all objects
115 protected function tearDown(): void
119 $response = new ReflectionProperty(ResponseRenderer
::class, 'instance');
120 $response->setValue(null, null);
121 DatabaseInterface
::$instance = null;
125 * Test for getFormParametersForInsertForm
127 public function testGetFormParametersForInsertForm(): void
129 $whereClause = ['foo' => 'bar ', '1' => ' test'];
130 $_POST['clause_is_unique'] = false;
131 $_POST['sql_query'] = 'SELECT a';
132 UrlParams
::$goto = 'index.php';
134 $result = $this->insertEdit
->getFormParametersForInsertForm('dbname', 'tablename', $whereClause, 'localhost');
139 'table' => 'tablename',
140 'goto' => 'index.php',
141 'err_url' => 'localhost',
142 'sql_query' => 'SELECT a',
143 'where_clause[foo]' => 'bar',
144 'where_clause[1]' => 'test',
145 'clause_is_unique' => false,
152 * Test for getFormParametersForInsertForm
154 public function testGetFormParametersForInsertFormGet(): void
156 $whereClause = ['foo' => 'bar ', '1' => ' test'];
157 $_GET['clause_is_unique'] = false;
158 $_GET['sql_query'] = 'SELECT a';
159 $_GET['sql_signature'] = Core
::signSqlQuery($_GET['sql_query']);
160 UrlParams
::$goto = 'index.php';
162 $result = $this->insertEdit
->getFormParametersForInsertForm('dbname', 'tablename', $whereClause, 'localhost');
167 'table' => 'tablename',
168 'goto' => 'index.php',
169 'err_url' => 'localhost',
170 'sql_query' => 'SELECT a',
171 'where_clause[foo]' => 'bar',
172 'where_clause[1]' => 'test',
173 'clause_is_unique' => false,
180 * Test for analyzeWhereClauses
182 public function testAnalyzeWhereClause(): void
184 $clauses = ['a=1', 'b="fo\o"'];
186 $resultStub1 = self
::createMock(DummyResult
::class);
187 $resultStub2 = self
::createMock(DummyResult
::class);
189 $dbi = $this->getMockBuilder(DatabaseInterface
::class)
190 ->disableOriginalConstructor()
193 $dbi->expects(self
::exactly(2))
195 ->willReturn($resultStub1, $resultStub2);
197 $resultStub1->expects(self
::once())
198 ->method('fetchAssoc')
199 ->willReturn(['assoc1']);
201 $resultStub2->expects(self
::once())
202 ->method('fetchAssoc')
203 ->willReturn(['assoc2']);
205 $dbi->expects(self
::exactly(2))
206 ->method('getFieldsMeta')
207 ->willReturn([], []);
209 DatabaseInterface
::$instance = $dbi;
210 $this->insertEdit
= new InsertEdit(
213 new Transformations(),
216 Config
::getInstance(),
218 $result = $this->callFunction(
221 'analyzeWhereClauses',
222 [$clauses, 'table', 'db'],
226 [[$resultStub1, $resultStub2], [['assoc1'], ['assoc2']], false],
232 * Test for hasUniqueCondition
234 public function testHasUniqueCondition(): void
236 $meta = FieldHelper
::fromArray([
237 'type' => MYSQLI_TYPE_DECIMAL
,
238 'flags' => MYSQLI_PRI_KEY_FLAG
,
240 'orgname' => 'orgname',
243 $resultStub = self
::createMock(DummyResult
::class);
245 $dbi = $this->getMockBuilder(DatabaseInterface
::class)
246 ->disableOriginalConstructor()
249 $dbi->expects(self
::once())
250 ->method('getFieldsMeta')
252 ->willReturn([$meta]);
254 DatabaseInterface
::$instance = $dbi;
255 $this->insertEdit
= new InsertEdit(
258 new Transformations(),
261 Config
::getInstance(),
264 $result = $this->callFunction(
267 'hasUniqueCondition',
268 [['1' => 1], $resultStub],
271 self
::assertTrue($result);
273 // TODO: Add test for false case
276 public function testLoadFirstRow(): void
278 $resultStub = self
::createMock(DummyResult
::class);
280 $dbi = $this->getMockBuilder(DatabaseInterface
::class)
281 ->disableOriginalConstructor()
284 $dbi->expects(self
::once())
286 ->with('SELECT * FROM `db`.`table` LIMIT 1;')
287 ->willReturn($resultStub);
289 DatabaseInterface
::$instance = $dbi;
290 $this->insertEdit
= new InsertEdit(
293 new Transformations(),
296 Config
::getInstance(),
299 $result = $this->callFunction(
306 self
::assertSame($resultStub, $result);
309 /** @return list<array{int, array<array<never>>}> */
310 public static function dataProviderConfigValueInsertRows(): array
312 return [[2, [[], []]], [3, [[], [], []]]];
316 * Test for loadFirstRow
318 * @param array<array<never>> $rowsValue
320 #[DataProvider('dataProviderConfigValueInsertRows')]
321 public function testGetInsertRows(int $configValue, array $rowsValue): void
323 Config
::getInstance()->settings
['InsertRows'] = $configValue;
325 $result = $this->callFunction(
332 self
::assertSame($rowsValue, $result);
336 * Test for showTypeOrFunction
338 public function testShowTypeOrFunction(): void
340 $config = Config
::getInstance();
341 $config->settings
['ShowFieldTypesInDataEditView'] = true;
342 $config->settings
['ServerDefault'] = 1;
343 $urlParams = ['ShowFunctionFields' => 2];
345 $result = $this->insertEdit
->showTypeOrFunction('function', $urlParams, false);
347 self
::assertStringContainsString('index.php?route=/table/change', $result);
348 self
::assertStringContainsString(
349 'ShowFunctionFields=1&ShowFieldTypesInDataEditView=1&goto=index.php%3Froute%3D%2Fsql',
352 self
::assertStringContainsString('Function', $result);
355 $result = $this->insertEdit
->showTypeOrFunction('function', $urlParams, true);
357 self
::assertStringContainsString('index.php?route=/table/change', $result);
358 self
::assertStringContainsString(
359 'ShowFunctionFields=0&ShowFieldTypesInDataEditView=1&goto=index.php%3Froute%3D%2Fsql',
362 self
::assertStringContainsString('Function', $result);
365 $result = $this->insertEdit
->showTypeOrFunction('type', $urlParams, false);
367 self
::assertStringContainsString('index.php?route=/table/change', $result);
368 self
::assertStringContainsString(
369 'ShowFunctionFields=1&ShowFieldTypesInDataEditView=1&goto=index.php%3Froute%3D%2Fsql',
372 self
::assertStringContainsString('Type', $result);
375 $result = $this->insertEdit
->showTypeOrFunction('type', $urlParams, true);
377 self
::assertStringContainsString('index.php?route=/table/change', $result);
378 self
::assertStringContainsString(
379 'ShowFunctionFields=1&ShowFieldTypesInDataEditView=0&goto=index.php%3Froute%3D%2Fsql',
382 self
::assertStringContainsString('Type', $result);
386 * Test for getColumnTitle
388 public function testGetColumnTitle(): void
403 $comments['f1<'] = 'comment>';
405 $result = $this->callFunction(
409 [$fieldName, $comments],
412 $result = $this->parseString($result);
414 self
::assertStringContainsString('title="comment>"', $result);
416 self
::assertStringContainsString('f1<', $result);
422 public function testIsColumn(): void
424 $types = ['binary', 'varbinary'];
426 $columnType = 'binaryfoo';
427 self
::assertTrue($this->insertEdit
->isColumn($columnType, $types));
429 $columnType = 'Binaryfoo';
430 self
::assertTrue($this->insertEdit
->isColumn($columnType, $types));
432 $columnType = 'varbinaryfoo';
433 self
::assertTrue($this->insertEdit
->isColumn($columnType, $types));
435 $columnType = 'barbinaryfoo';
436 self
::assertFalse($this->insertEdit
->isColumn($columnType, $types));
438 $types = ['char', 'varchar'];
440 $columnType = 'char(10)';
441 self
::assertTrue($this->insertEdit
->isColumn($columnType, $types));
443 $columnType = 'VarChar(20)';
444 self
::assertTrue($this->insertEdit
->isColumn($columnType, $types));
446 $columnType = 'foochar';
447 self
::assertFalse($this->insertEdit
->isColumn($columnType, $types));
449 $types = ['blob', 'tinyblob', 'mediumblob', 'longblob'];
451 $columnType = 'blob';
452 self
::assertTrue($this->insertEdit
->isColumn($columnType, $types));
454 $columnType = 'bloB';
455 self
::assertTrue($this->insertEdit
->isColumn($columnType, $types));
457 $columnType = 'mediumBloB';
458 self
::assertTrue($this->insertEdit
->isColumn($columnType, $types));
460 $columnType = 'tinyblobabc';
461 self
::assertTrue($this->insertEdit
->isColumn($columnType, $types));
463 $columnType = 'longblob';
464 self
::assertTrue($this->insertEdit
->isColumn($columnType, $types));
466 $columnType = 'foolongblobbar';
467 self
::assertFalse($this->insertEdit
->isColumn($columnType, $types));
471 * Test for getNullifyCodeForNullColumn
473 public function testGetNullifyCodeForNullColumn(): void
475 $foreigners = ['foreign_keys_data' => []];
476 $column = new InsertEditColumn(
478 'enum(ababababababababababa)',
494 'getNullifyCodeForNullColumn',
495 [$column, $foreigners, false],
499 $column = new InsertEditColumn(
501 'enum(abababababab20)',
517 'getNullifyCodeForNullColumn',
518 [$column, $foreigners, false],
522 $column = new InsertEditColumn('f', 'set', false, '', null, '', -1, false, false, false, false);
528 'getNullifyCodeForNullColumn',
529 [$column, $foreigners, false],
533 $column = new InsertEditColumn('f', '', false, '', null, '', -1, false, false, false, false);
534 $foreigners['f'] = ['something'/* What should the mocked value actually be? */];
540 'getNullifyCodeForNullColumn',
541 [$column, $foreigners, false],
547 * Test for getTextarea
549 public function testGetTextarea(): void
551 $config = Config
::getInstance();
552 $config->settings
['TextareaRows'] = 20;
553 $config->settings
['TextareaCols'] = 10;
554 $config->settings
['CharTextareaRows'] = 7;
555 $config->settings
['CharTextareaCols'] = 1;
556 $config->settings
['LimitChars'] = 20;
558 $column = new InsertEditColumn(
571 (new ReflectionProperty(InsertEdit
::class, 'fieldIndex'))->setValue($this->insertEdit
, 2);
572 $result = $this->callFunction(
576 [$column, 'a', 'b', '', 'foobar', TypeClass
::Char
],
579 $result = $this->parseString($result);
581 self
::assertStringContainsString(
582 '<textarea name="fieldsb" class="charField" '
583 . 'data-maxlength="10" rows="7" cols="1" dir="ltr" '
584 . 'id="field_2_3" tabindex="2" data-type="CHAR">',
590 * Test for getHtmlInput
592 public function testGetHTMLinput(): void
594 Config
::getInstance()->settings
['ShowFunctionFields'] = true;
595 $column = new InsertEditColumn('f', 'date', false, 'PRI', null, '', -1, false, false, false, false);
596 (new ReflectionProperty(InsertEdit
::class, 'fieldIndex'))->setValue($this->insertEdit
, 23);
597 $result = $this->callFunction(
601 [$column, 'a', 'b', 30, 'c', 'DATE'],
605 '<input type="text" name="fieldsa" value="b" size="30" data-type="DATE"'
606 . ' class="textfield datefield" onchange="c" tabindex="23" id="field_23_3">',
611 $column = new InsertEditColumn('f', 'datetime', false, 'PRI', null, '', -1, false, false, false, false);
612 $result = $this->callFunction(
616 [$column, 'a', 'b', 30, 'c', 'DATE'],
619 '<input type="text" name="fieldsa" value="b" size="30" data-type="DATE"'
620 . ' class="textfield datetimefield" onchange="c" tabindex="23" id="field_23_3">',
625 $column = new InsertEditColumn('f', 'timestamp', false, 'PRI', null, '', -1, false, false, false, false);
626 $result = $this->callFunction(
630 [$column, 'a', 'b', 30, 'c', 'DATE'],
633 '<input type="text" name="fieldsa" value="b" size="30" data-type="DATE"'
634 . ' class="textfield datetimefield" onchange="c" tabindex="23" id="field_23_3">',
639 $column = new InsertEditColumn('f', 'int(11)', false, 'PRI', null, '', -1, false, false, false, false);
640 $result = $this->callFunction(
644 [$column, 'a', 'b', 11, 'c', 'INT'],
647 '<input type="text" name="fieldsa" value="b" size="11" min="-2147483648" max="2147483647" data-type="INT"'
648 . ' class="textfield" onchange="c" tabindex="23" inputmode="numeric" id="field_23_3">',
654 * Test for getMaxUploadSize
656 public function testGetMaxUploadSize(): void
659 $result = $this->callFunction(
666 self
::assertSame("(Max: 256B)\n", $result);
669 // this should stub Util::getUploadSizeInBytes() but it's not possible
671 $result = $this->callFunction(
678 self
::assertSame("(Max: 64KiB)\n", $result);
682 * Test for getValueColumnForOtherDatatypes
684 public function testGetValueColumnForOtherDatatypes(): void
686 $column = new InsertEditColumn('f', 'char(25)', false, '', null, '', 20, false, false, true, false);
687 $config = Config
::getInstance();
688 $config->settings
['CharEditing'] = '';
689 $config->settings
['MaxSizeForInputField'] = 30;
690 $config->settings
['MinSizeForInputField'] = 10;
691 $config->settings
['TextareaRows'] = 20;
692 $config->settings
['TextareaCols'] = 10;
693 $config->settings
['CharTextareaRows'] = 7;
694 $config->settings
['CharTextareaCols'] = 1;
695 $config->settings
['LimitChars'] = 50;
696 $config->settings
['ShowFunctionFields'] = true;
698 $extractedColumnSpec = '25';
699 (new ReflectionProperty(InsertEdit
::class, 'fieldIndex'))->setValue($this->insertEdit
, 22);
700 $result = $this->callFunction(
703 'getValueColumnForOtherDatatypes',
713 $extractedColumnSpec,
719 . '<textarea name="fieldsb" class="charField" '
720 . 'data-maxlength="25" rows="7" cols="1" dir="ltr" '
721 . 'id="field_22_3" onchange="c" tabindex="22" data-type="CHAR">'
727 $column = new InsertEditColumn(
740 $result = $this->callFunction(
743 'getValueColumnForOtherDatatypes',
753 $extractedColumnSpec,
759 . '<input type="text" name="fieldsb" value="<" size="20" data-type="'
760 . 'DATE" class="textfield datetimefield" onchange="c" tabindex="22" id="field_22_3"'
761 . '><input type="hidden" name="auto_incrementb" value="1">'
762 . '<input type="hidden" name="fields_typeb" value="timestamp">',
766 // case 3: (else -> datetime)
767 $column = new InsertEditColumn(
780 $result = $this->callFunction(
783 'getValueColumnForOtherDatatypes',
793 $extractedColumnSpec,
797 $result = $this->parseString($result);
799 self
::assertStringContainsString('<input type="hidden" name="fields_typeb" value="datetime">', $result);
801 // case 4: (else -> date)
802 $column = new InsertEditColumn('f', 'date', false, '', null, 'auto_increment', 20, false, false, false, false);
803 $result = $this->callFunction(
806 'getValueColumnForOtherDatatypes',
816 $extractedColumnSpec,
820 $result = $this->parseString($result);
822 self
::assertStringContainsString('<input type="hidden" name="fields_typeb" value="date">', $result);
824 // case 5: (else -> bit)
825 $column = new InsertEditColumn('f', 'bit', false, '', null, 'auto_increment', 20, false, false, false, false);
826 $result = $this->callFunction(
829 'getValueColumnForOtherDatatypes',
839 $extractedColumnSpec,
843 $result = $this->parseString($result);
845 self
::assertStringContainsString('<input type="hidden" name="fields_typeb" value="bit">', $result);
847 // case 6: (else -> uuid)
848 $column = new InsertEditColumn('f', 'uuid', false, '', null, 'auto_increment', 20, false, false, false, false);
849 $result = $this->callFunction(
852 'getValueColumnForOtherDatatypes',
862 $extractedColumnSpec,
866 $result = $this->parseString($result);
868 self
::assertStringContainsString('<input type="hidden" name="fields_typeb" value="uuid">', $result);
872 * Test for getColumnSize
874 public function testGetColumnSize(): void
876 $column = new InsertEditColumn(
889 $specInBrackets = '45';
890 $config = Config
::getInstance();
891 $config->settings
['MinSizeForInputField'] = 30;
892 $config->settings
['MaxSizeForInputField'] = 40;
900 [$column, $specInBrackets],
904 self
::assertSame('textarea', $config->settings
['CharEditing']);
907 $column = new InsertEditColumn(
926 [$column, $specInBrackets],
932 * Test for getContinueInsertionForm
934 public function testGetContinueInsertionForm(): void
936 $whereClauseArray = ['a<b'];
937 $config = Config
::getInstance();
938 $config->settings
['InsertRows'] = 1;
939 $config->settings
['ServerDefault'] = 1;
940 UrlParams
::$goto = 'index.php';
941 $_POST['where_clause'] = true;
942 $_POST['sql_query'] = 'SELECT 1';
944 $result = $this->insertEdit
->getContinueInsertionForm('tbl', 'db', $whereClauseArray, 'localhost');
946 self
::assertStringContainsString(
947 '<form id="continueForm" method="post" action="' . Url
::getFromRoute('/table/change')
948 . '" name="continueForm" class="row g-3">',
952 self
::assertStringContainsString('<input type="hidden" name="db" value="db">', $result);
954 self
::assertStringContainsString('<input type="hidden" name="table" value="tbl">', $result);
956 self
::assertStringContainsString('<input type="hidden" name="goto" value="index.php">', $result);
958 self
::assertStringContainsString('<input type="hidden" name="err_url" value="localhost">', $result);
960 self
::assertStringContainsString('<input type="hidden" name="sql_query" value="SELECT 1">', $result);
962 self
::assertStringContainsString('<input type="hidden" name="where_clause[0]" value="a<b">', $result);
965 public function testIsWhereClauseNumeric(): void
967 self
::assertFalse(InsertEdit
::isWhereClauseNumeric(null));
968 self
::assertFalse(InsertEdit
::isWhereClauseNumeric(''));
969 self
::assertFalse(InsertEdit
::isWhereClauseNumeric([]));
970 self
::assertTrue(InsertEdit
::isWhereClauseNumeric('`actor`.`actor_id` = 1'));
971 self
::assertTrue(InsertEdit
::isWhereClauseNumeric(['`actor`.`actor_id` = 1']));
972 self
::assertFalse(InsertEdit
::isWhereClauseNumeric('`actor`.`first_name` = \'value\''));
973 self
::assertFalse(InsertEdit
::isWhereClauseNumeric(['`actor`.`first_name` = \'value\'']));
977 * Test for getHeadAndFootOfInsertRowTable
979 public function testGetHeadAndFootOfInsertRowTable(): void
981 $config = Config
::getInstance();
982 $config->settings
['ShowFieldTypesInDataEditView'] = true;
983 $config->settings
['ShowFunctionFields'] = true;
984 $config->settings
['ServerDefault'] = 1;
985 $urlParams = ['ShowFunctionFields' => 2];
987 $result = $this->callFunction(
990 'getHeadAndFootOfInsertRowTable',
994 $result = $this->parseString($result);
996 self
::assertStringContainsString('index.php?route=/table/change', $result);
998 self
::assertStringContainsString('ShowFunctionFields=1&ShowFieldTypesInDataEditView=0', $result);
1000 self
::assertStringContainsString('ShowFunctionFields=0&ShowFieldTypesInDataEditView=1', $result);
1004 * Test for getSpecialCharsAndBackupFieldForExistingRow
1006 public function testGetSpecialCharsAndBackupFieldForExistingRow(): void
1009 $currentRow['f'] = null;
1010 $_POST['default_action'] = 'insert';
1011 $column = new InsertEditColumn(
1017 'fooauto_increment',
1025 $result = $this->callFunction(
1028 'getSpecialCharsAndBackupFieldForExistingRow',
1029 [$currentRow, $column, '', 'a', false],
1033 [true, null, null, null, '<input type="hidden" name="fields_preva" value="">'],
1038 unset($_POST['default_action']);
1040 $currentRow['f'] = '123';
1041 $extractedColumnSpec = '20';
1042 $column = new InsertEditColumn(
1048 'fooauto_increment',
1056 $result = $this->callFunction(
1059 'getSpecialCharsAndBackupFieldForExistingRow',
1060 [$currentRow, $column, $extractedColumnSpec, 'a', false],
1064 [false, '', '00000000000001111011', null, '<input type="hidden" name="fields_preva" value="123">'],
1068 $currentRow['f'] = 'abcd';
1069 $result = $this->callFunction(
1072 'getSpecialCharsAndBackupFieldForExistingRow',
1073 [$currentRow, $column, $extractedColumnSpec, 'a', true],
1077 [false, '', 'abcd', null, '<input type="hidden" name="fields_preva" value="abcd">'],
1082 $dbi = $this->getMockBuilder(DatabaseInterface
::class)
1083 ->disableOriginalConstructor()
1086 DatabaseInterface
::$instance = $dbi;
1087 $this->insertEdit
= new InsertEdit(
1090 new Transformations(),
1093 Config
::getInstance(),
1096 $currentRow['f'] = '123';
1097 $extractedColumnSpec = '20';
1098 $column = new InsertEditColumn(
1104 'fooauto_increment',
1112 $result = $this->callFunction(
1115 'getSpecialCharsAndBackupFieldForExistingRow',
1116 [$currentRow, $column, $extractedColumnSpec, 'a', false],
1120 [false, '', "'',", null, '<input type="hidden" name="fields_preva" value="\'\',">'],
1125 $column = new InsertEditColumn(
1131 'fooauto_increment',
1138 $config = Config
::getInstance();
1139 $config->settings
['ProtectBinary'] = false;
1140 $currentRow['f'] = '11001';
1141 $extractedColumnSpec = '20';
1142 $config->settings
['ShowFunctionFields'] = true;
1144 $result = $this->callFunction(
1147 'getSpecialCharsAndBackupFieldForExistingRow',
1148 [$currentRow, $column, $extractedColumnSpec, 'a', false],
1157 '<input type="hidden" name="fields_preva" value="3131303031">',
1163 $currentRow['f'] = "11001\x00";
1165 $result = $this->callFunction(
1168 'getSpecialCharsAndBackupFieldForExistingRow',
1169 [$currentRow, $column, $extractedColumnSpec, 'a', false],
1178 '<input type="hidden" name="fields_preva" value="313130303100">',
1185 * Test for getDefaultValue
1187 #[DataProvider('providerForTestGetSpecialCharsForInsertingMode')]
1188 public function testGetDefaultValue(
1189 string|
null $defaultValue,
1193 $config = Config
::getInstance();
1194 $config->settings
['ProtectBinary'] = false;
1195 $config->settings
['ShowFunctionFields'] = true;
1197 /** @var string $result */
1198 $result = $this->callFunction(
1202 [$defaultValue, $trueType],
1205 self
::assertSame($expected, $result);
1209 * Data provider for test getDefaultValue()
1211 * @return array<string, array{string|null, string, string}>
1213 public static function providerForTestGetSpecialCharsForInsertingMode(): array
1226 'time with CURRENT_TIMESTAMP value' => [
1227 'CURRENT_TIMESTAMP',
1229 'CURRENT_TIMESTAMP',
1231 'time with current_timestamp() value' => [
1232 'current_timestamp()',
1234 'current_timestamp()',
1236 'time with no dot value' => [
1241 'time with dot value' => [
1246 'any text with escape text default' => [
1251 'varchar with html special chars' => [
1252 'hello world<br><b>lorem</b> ipsem',
1254 'hello world<br><b>lorem</b> ipsem',
1256 'text with html special chars' => [
1257 '\'</textarea><script>alert(1)</script>\'',
1259 '\'</textarea><script>alert(1)</script>\'',
1265 * Test for setSessionForEditNext
1267 public function testSetSessionForEditNext(): void
1269 $meta = FieldHelper
::fromArray([
1270 'type' => MYSQLI_TYPE_DECIMAL
,
1271 'flags' => MYSQLI_PRI_KEY_FLAG
,
1272 'orgname' => 'orgname',
1274 'orgtable' => 'table',
1279 $resultStub = self
::createMock(DummyResult
::class);
1281 $dbi = $this->getMockBuilder(DatabaseInterface
::class)
1282 ->disableOriginalConstructor()
1285 $dbi->expects(self
::once())
1287 ->with('SELECT * FROM `db`.`table` WHERE `a` > 2 LIMIT 1;')
1288 ->willReturn($resultStub);
1290 $resultStub->expects(self
::once())
1291 ->method('fetchRow')
1294 $dbi->expects(self
::once())
1295 ->method('getFieldsMeta')
1297 ->willReturn([$meta]);
1299 DatabaseInterface
::$instance = $dbi;
1300 Current
::$database = 'db';
1301 Current
::$table = 'table';
1302 $this->insertEdit
= new InsertEdit(
1305 new Transformations(),
1308 Config
::getInstance(),
1310 $this->insertEdit
->setSessionForEditNext('`a` = 2');
1312 self
::assertSame('CONCAT(`table`.`orgname`) IS NULL', $_SESSION['edit_next']);
1316 * Test for getGotoInclude
1318 public function testGetGotoInclude(): void
1320 UrlParams
::$goto = '123.php';
1321 Current
::$table = '';
1325 $this->insertEdit
->getGotoInclude('index'),
1328 Current
::$table = 'tbl';
1331 $this->insertEdit
->getGotoInclude('index'),
1334 UrlParams
::$goto = 'index.php?route=/database/sql';
1338 $this->insertEdit
->getGotoInclude('index'),
1341 self
::assertSame('', Current
::$table);
1343 UrlParams
::$goto = 'index.php?route=/sql&server=2';
1347 $this->insertEdit
->getGotoInclude('index'),
1350 $_POST['after_insert'] = 'new_insert';
1353 $this->insertEdit
->getGotoInclude('index'),
1358 * Test for getErrorUrl
1360 public function testGetErrorUrl(): void
1362 Config
::getInstance()->settings
['ServerDefault'] = 1;
1364 'index.php?route=/table/change&lang=en',
1365 $this->insertEdit
->getErrorUrl([]),
1368 $_POST['err_url'] = 'localhost';
1371 $this->insertEdit
->getErrorUrl([]),
1376 * Test for executeSqlQuery
1378 public function testExecuteSqlQuery(): void
1380 $query = ['SELECT * FROM `test_db`.`test_table`;', 'SELECT * FROM `test_db`.`test_table_yaml`;'];
1381 Config
::getInstance()->settings
['IgnoreMultiSubmitErrors'] = false;
1382 $_POST['submit_type'] = '';
1384 $dbi = DatabaseInterface
::getInstance();
1385 $this->insertEdit
= new InsertEdit(
1388 new Transformations(),
1391 Config
::getInstance(),
1393 $result = $this->insertEdit
->executeSqlQuery($query);
1395 self
::assertSame([], $result[3]);
1399 * Test for executeSqlQuery
1401 public function testExecuteSqlQueryWithTryQuery(): void
1403 $query = ['SELECT * FROM `test_db`.`test_table`;', 'SELECT * FROM `test_db`.`test_table_yaml`;'];
1404 Config
::getInstance()->settings
['IgnoreMultiSubmitErrors'] = true;
1405 $_POST['submit_type'] = '';
1407 $dbi = DatabaseInterface
::getInstance();
1408 $this->insertEdit
= new InsertEdit(
1411 new Transformations(),
1414 Config
::getInstance(),
1416 $result = $this->insertEdit
->executeSqlQuery($query);
1418 self
::assertSame([], $result[3]);
1422 * Test for getWarningMessages
1424 public function testGetWarningMessages(): void
1427 Warning
::fromArray(['Level' => 'Error', 'Code' => '1001', 'Message' => 'Message 1']),
1428 Warning
::fromArray(['Level' => 'Warning', 'Code' => '1002', 'Message' => 'Message 2']),
1431 $dbi = $this->getMockBuilder(DatabaseInterface
::class)
1432 ->disableOriginalConstructor()
1435 $dbi->expects(self
::once())
1436 ->method('getWarnings')
1437 ->willReturn($warnings);
1439 DatabaseInterface
::$instance = $dbi;
1440 $this->insertEdit
= new InsertEdit(
1443 new Transformations(),
1446 Config
::getInstance(),
1449 $result = (array) $this->callFunction(
1452 'getWarningMessages',
1456 self
::assertSame(['Error: #1001 Message 1', 'Warning: #1002 Message 2'], $result);
1460 * Test for getDisplayValueForForeignTableColumn
1462 public function testGetDisplayValueForForeignTableColumn(): void
1465 $map['f']['foreign_db'] = 'information_schema';
1466 $map['f']['foreign_table'] = 'TABLES';
1467 $map['f']['foreign_field'] = 'f';
1469 $resultStub = self
::createMock(DummyResult
::class);
1471 $dbi = $this->getMockBuilder(DatabaseInterface
::class)
1472 ->disableOriginalConstructor()
1475 $dbi->expects(self
::once())
1476 ->method('tryQuery')
1477 ->with('SELECT `TABLE_COMMENT` FROM `information_schema`.`TABLES` WHERE `f`=1')
1478 ->willReturn($resultStub);
1480 $resultStub->expects(self
::once())
1484 $resultStub->expects(self
::once())
1485 ->method('fetchValue')
1489 DatabaseInterface
::$instance = $dbi;
1490 $this->insertEdit
= new InsertEdit(
1493 new Transformations(),
1496 Config
::getInstance(),
1499 $result = $this->insertEdit
->getDisplayValueForForeignTableColumn('=1', $map, 'f');
1501 self
::assertSame('2', $result);
1505 * Test for getLinkForRelationalDisplayField
1507 public function testGetLinkForRelationalDisplayField(): void
1509 Config
::getInstance()->settings
['ServerDefault'] = 1;
1510 $_SESSION['tmpval']['relational_display'] = 'K';
1512 $map['f']['foreign_db'] = 'information_schema';
1513 $map['f']['foreign_table'] = 'TABLES';
1514 $map['f']['foreign_field'] = 'f';
1516 $result = $this->insertEdit
->getLinkForRelationalDisplayField($map, 'f', '=1', 'a>', 'b<');
1518 $sqlSignature = Core
::signSqlQuery('SELECT * FROM `information_schema`.`TABLES` WHERE `f`=1');
1521 '<a href="index.php?route=/sql&db=information_schema&table=TABLES&pos=0&'
1522 . 'sql_signature=' . $sqlSignature . '&'
1523 . 'sql_query=SELECT+%2A+FROM+%60information_schema%60.%60TABLES%60+WHERE'
1524 . '+%60f%60%3D1&lang=en" title="a>">b<</a>',
1528 $_SESSION['tmpval']['relational_display'] = 'D';
1529 $result = $this->insertEdit
->getLinkForRelationalDisplayField($map, 'f', '=1', 'a>', 'b<');
1532 '<a href="index.php?route=/sql&db=information_schema&table=TABLES&pos=0&'
1533 . 'sql_signature=' . $sqlSignature . '&'
1534 . 'sql_query=SELECT+%2A+FROM+%60information_schema%60.%60TABLES%60+WHERE'
1535 . '+%60f%60%3D1&lang=en" title="b<">a></a>',
1541 * Test for transformEditedValues
1543 public function testTransformEditedValues(): void
1545 $_SESSION[' HMAC_secret '] = hash('sha1', 'test');
1546 $editedValues = [['c' => 'cname']];
1547 $config = Config
::getInstance();
1548 $config->settings
['DefaultTransformations']['PreApPend'] = ['', ''];
1549 $config->settings
['ServerDefault'] = 1;
1550 $_POST['where_clause'] = '1';
1551 $_POST['where_clause_sign'] = Core
::signSqlQuery($_POST['where_clause']);
1552 $result = $this->insertEdit
->transformEditedValues(
1555 "'','option ,, quoted',abd",
1557 'Text_Plain_PreApPend.php',
1563 [['a' => 'b'], 'transformations' => ['cnameoption ,, quoted']],
1569 * Test for getQueryValuesForInsert
1571 public function testGetQueryValuesForInsert(): void
1574 $result = $this->insertEdit
->getQueryValueForInsert(
1590 self
::assertSame("'foo'", $result);
1592 // Test for file upload
1593 $result = $this->insertEdit
->getQueryValueForInsert(
1610 self
::assertSame('0x123', $result);
1613 $this->dummyDbi
->addResult(
1616 ['uuid1234'],// Minimal working setup for 2FA
1621 $result = $this->insertEdit
->getQueryValueForInsert(
1638 self
::assertSame("'uuid1234'", $result);
1641 $result = $this->insertEdit
->getQueryValueForInsert(
1657 self
::assertSame("AES_ENCRYPT('\\'','')", $result);
1660 $result = $this->insertEdit
->getQueryValueForInsert(
1676 self
::assertSame("ABS('\\'')", $result);
1679 $result = $this->insertEdit
->getQueryValueForInsert(
1695 self
::assertSame('RAND()', $result);
1698 $result = $this->insertEdit
->getQueryValueForInsert(
1706 'PHP_PASSWORD_HASH',
1714 self
::assertTrue(password_verify("a'c", mb_substr($result, 1, -1)));
1717 $result = $this->insertEdit
->getQueryValueForInsert(
1718 new EditField('', "'POINT(3 4)',4326", '', true, false, false, 'ST_GeomFromText', null, null, false),
1722 self
::assertSame('ST_GeomFromText(\'POINT(3 4)\',4326)', $result);
1725 $result = $this->insertEdit
->getQueryValueForInsert(
1726 new EditField('', 'POINT(3 4),4326', '', true, false, false, 'ST_GeomFromText', null, null, false),
1730 self
::assertSame('ST_GeomFromText(\'POINT(3 4)\',4326)', $result);
1733 $result = $this->insertEdit
->getQueryValueForInsert(
1734 new EditField('', "'POINT(3 4)'", '', true, false, false, 'ST_GeomFromText', null, null, false),
1738 self
::assertSame('ST_GeomFromText(\'POINT(3 4)\')', $result);
1741 $result = $this->insertEdit
->getQueryValueForInsert(
1742 new EditField('', 'POINT(3 4)', '', true, false, false, 'ST_GeomFromText', null, null, false),
1746 self
::assertSame('ST_GeomFromText(\'POINT(3 4)\')', $result);
1748 // Test different data types
1750 // Datatype: protected copied from the databse
1751 Current
::$table = 'test_table';
1752 $result = $this->insertEdit
->getQueryValueForInsert(
1768 self
::assertSame('0x313031', $result);
1770 // An empty value for auto increment column should be converted to NULL
1771 $result = $this->insertEdit
->getQueryValueForInsert(
1774 '', // empty for null
1787 self
::assertSame('NULL', $result);
1789 // Simple empty value
1790 $result = $this->insertEdit
->getQueryValueForInsert(
1806 self
::assertSame("''", $result);
1809 $result = $this->insertEdit
->getQueryValueForInsert(
1812 '', // doesn't matter what the value is
1825 self
::assertSame("''", $result);
1827 // Datatype: protected with no value should produce an empty string
1828 $result = $this->insertEdit
->getQueryValueForInsert(
1844 self
::assertSame('', $result);
1846 // Datatype: protected with null flag set
1847 $result = $this->insertEdit
->getQueryValueForInsert(
1863 self
::assertSame('NULL', $result);
1866 $result = $this->insertEdit
->getQueryValueForInsert(
1882 self
::assertSame("b'00010'", $result);
1885 $result = $this->insertEdit
->getQueryValueForInsert(
1901 self
::assertSame("'20\\'12'", $result);
1904 $result = $this->insertEdit
->getQueryValueForInsert(
1920 self
::assertSame('NULL', $result);
1922 // Datatype: protected but NULL checkbox was unchecked without uploading a file
1923 $result = $this->insertEdit
->getQueryValueForInsert(
1930 true, // was previously NULL
1939 self
::assertSame("''", $result);
1941 // Datatype: date with default value
1942 $result = $this->insertEdit
->getQueryValueForInsert(
1945 'current_timestamp()',
1949 true, // NULL should be ignored
1958 self
::assertSame('current_timestamp()', $result);
1960 // Datatype: hex without 0x
1961 $result = $this->insertEdit
->getQueryValueForInsert(
1977 self
::assertSame('0x222aaafff', $result);
1979 // Datatype: hex with 0x
1980 $result = $this->insertEdit
->getQueryValueForInsert(
1996 self
::assertSame('0x222aaafff', $result);
2000 * Test for getQueryValuesForUpdate
2002 public function testGetQueryValuesForUpdate(): void
2005 $result = $this->insertEdit
->getQueryValueForUpdate(
2019 self
::assertSame("`fld` = 'foo'", $result);
2021 // Update of null when it was null previously
2022 $result = $this->insertEdit
->getQueryValueForUpdate(
2025 '', // null fields will have no value
2036 self
::assertSame('', $result);
2038 // Update of null when it was NOT null previously
2039 $result = $this->insertEdit
->getQueryValueForUpdate(
2042 '', // null fields will have no value
2049 '', // in edit mode the previous value will be empty string
2053 self
::assertSame('`fld` = NULL', $result);
2055 // Update to NOT null when it was null previously
2056 $result = $this->insertEdit
->getQueryValueForUpdate(
2070 self
::assertSame("`fld` = 'ab\'c'", $result);
2072 // Test to see if a zero-string is not ignored
2073 $result = $this->insertEdit
->getQueryValueForUpdate(
2076 '0', // zero-string provided as value
2087 self
::assertSame("`fld` = '0'", $result);
2089 // Test to check if blob field that was left unchanged during edit will be ignored
2090 $result = $this->insertEdit
->getQueryValueForUpdate(
2104 self
::assertSame('', $result);
2106 // Test to see if a field will be ignored if it the value is unchanged
2107 $result = $this->insertEdit
->getQueryValueForUpdate(
2122 self
::assertSame('', $result);
2124 // Test that an empty value uses the uuid function to generate a value
2125 $result = $this->insertEdit
->getQueryValueForUpdate(
2140 self
::assertSame('`fld` = uuid()', $result);
2142 // Test that the uuid function as a value uses the uuid function to generate a value
2143 $result = $this->insertEdit
->getQueryValueForUpdate(
2158 self
::assertSame('`fld` = uuid()', $result);
2160 // Test that the uuid function as a value uses the uuid function to generate a value
2161 $result = $this->insertEdit
->getQueryValueForUpdate(
2176 self
::assertSame('`fld` = uuid()', $result);
2178 // Test that the uuid type does not have a default value other than null when it is nullable
2179 $result = $this->insertEdit
->getQueryValueForUpdate(
2194 self
::assertSame('`fld` = NULL', $result);
2198 * Test for verifyWhetherValueCanBeTruncatedAndAppendExtraData
2200 public function testVerifyWhetherValueCanBeTruncatedAndAppendExtraData(): void
2202 $extraData = ['isNeedToRecheck' => true];
2204 $_POST['where_clause'] = [];
2205 $_POST['where_clause'][0] = 1;
2207 $dbi = $this->getMockBuilder(DatabaseInterface
::class)
2208 ->disableOriginalConstructor()
2211 $resultStub = self
::createMock(DummyResult
::class);
2213 $dbi->expects(self
::exactly(3))
2214 ->method('tryQuery')
2215 ->with('SELECT `table`.`a` FROM `db`.`table` WHERE 1')
2216 ->willReturn($resultStub);
2218 $meta1 = FieldHelper
::fromArray(['type' => MYSQLI_TYPE_TINY
]);
2219 $meta2 = FieldHelper
::fromArray(['type' => MYSQLI_TYPE_TINY
]);
2220 $meta3 = FieldHelper
::fromArray(['type' => MYSQLI_TYPE_TIMESTAMP
]);
2221 $dbi->expects(self
::exactly(3))
2222 ->method('getFieldsMeta')
2223 ->willReturn([$meta1], [$meta2], [$meta3]);
2225 $resultStub->expects(self
::exactly(3))
2226 ->method('fetchValue')
2227 ->willReturn(false, '123', '2013-08-28 06:34:14');
2229 DatabaseInterface
::$instance = $dbi;
2230 $this->insertEdit
= new InsertEdit(
2233 new Transformations(),
2236 Config
::getInstance(),
2239 $this->insertEdit
->verifyWhetherValueCanBeTruncatedAndAppendExtraData('db', 'table', 'a', $extraData);
2241 self
::assertFalse($extraData['isNeedToRecheck']);
2243 $this->insertEdit
->verifyWhetherValueCanBeTruncatedAndAppendExtraData('db', 'table', 'a', $extraData);
2245 self
::assertSame('123', $extraData['truncatableFieldValue']);
2246 self
::assertTrue($extraData['isNeedToRecheck']);
2248 $this->insertEdit
->verifyWhetherValueCanBeTruncatedAndAppendExtraData('db', 'table', 'a', $extraData);
2250 self
::assertSame('2013-08-28 06:34:14.000000', $extraData['truncatableFieldValue']);
2251 self
::assertTrue($extraData['isNeedToRecheck']);
2255 * Test for getTableColumns
2257 public function testGetTableColumns(): void
2259 $dbi = $this->getMockBuilder(DatabaseInterface
::class)
2260 ->disableOriginalConstructor()
2263 $dbi->expects(self
::once())
2264 ->method('selectDb')
2268 new Column('b', 'd', null, false, '', null, '', '', ''),
2269 new Column('f', 'h', null, true, '', null, '', '', ''),
2272 $dbi->expects(self
::once())
2273 ->method('getColumns')
2274 ->with('db', 'table')
2275 ->willReturn($columns);
2277 DatabaseInterface
::$instance = $dbi;
2278 $this->insertEdit
= new InsertEdit(
2281 new Transformations(),
2284 Config
::getInstance(),
2287 $result = $this->insertEdit
->getTableColumns('db', 'table');
2291 new Column('b', 'd', null, false, '', null, '', '', ''),
2292 new Column('f', 'h', null, true, '', null, '', '', ''),
2299 * Test for determineInsertOrEdit
2301 public function testDetermineInsertOrEdit(): void
2303 $dbi = $this->getMockBuilder(DatabaseInterface
::class)
2304 ->disableOriginalConstructor()
2307 $resultStub = self
::createMock(DummyResult
::class);
2309 $dbi->expects(self
::exactly(2))
2311 ->willReturn($resultStub);
2313 DatabaseInterface
::$instance = $dbi;
2314 $_POST['where_clause'] = '1';
2315 $_SESSION['edit_next'] = '1';
2316 $_POST['ShowFunctionFields'] = true;
2317 $_POST['ShowFieldTypesInDataEditView'] = true;
2318 $_POST['after_insert'] = 'edit_next';
2319 $config = Config
::getInstance();
2320 $config->settings
['InsertRows'] = 2;
2321 $config->settings
['ShowSQL'] = false;
2322 $_POST['default_action'] = 'insert';
2324 $responseMock = $this->getMockBuilder(ResponseRenderer
::class)
2325 ->disableOriginalConstructor()
2326 ->onlyMethods(['addHtml'])
2329 $restoreInstance = ResponseRenderer
::getInstance();
2330 $response = new ReflectionProperty(ResponseRenderer
::class, 'instance');
2331 $response->setValue(null, $responseMock);
2333 $this->insertEdit
= new InsertEdit(
2336 new Transformations(),
2339 Config
::getInstance(),
2342 $result = $this->insertEdit
->determineInsertOrEdit('1', 'db', 'table');
2345 [false, null, [$resultStub], [[]], false, 'edit_next'],
2350 unset($_POST['where_clause']);
2351 unset($_SESSION['edit_next']);
2352 $_POST['default_action'] = '';
2354 $result = $this->insertEdit
->determineInsertOrEdit(null, 'db', 'table');
2356 $response->setValue(null, $restoreInstance);
2359 [true, null, $resultStub, [[], []], false, 'edit_next'],
2365 * Test for getCommentsMap
2367 public function testGetCommentsMap(): void
2369 $config = Config
::getInstance();
2370 $config->settings
['ShowPropertyComments'] = false;
2372 $dbi = $this->getMockBuilder(DatabaseInterface
::class)
2373 ->disableOriginalConstructor()
2376 $dbi->expects(self
::once())
2377 ->method('getColumns')
2378 ->with('db', 'table')
2379 ->willReturn([new Column('d', 'd', null, false, '', null, '', '', 'b')]);
2381 $dbi->expects(self
::any())
2382 ->method('getTable')
2383 ->willReturn(new Table('table', 'db', $dbi));
2385 DatabaseInterface
::$instance = $dbi;
2386 $this->insertEdit
= new InsertEdit(
2389 new Transformations(),
2392 Config
::getInstance(),
2397 $this->insertEdit
->getCommentsMap('db', 'table'),
2400 $config->settings
['ShowPropertyComments'] = true;
2404 $this->insertEdit
->getCommentsMap('db', 'table'),
2409 * Test for getHtmlForIgnoreOption
2411 public function testGetHtmlForIgnoreOption(): void
2413 $expected = '<input type="checkbox" %sname="insert_ignore_1"'
2414 . ' id="insert_ignore_1"><label for="insert_ignore_1">'
2415 . 'Ignore</label><br>' . "\n";
2416 $checked = 'checked ';
2418 sprintf($expected, $checked),
2419 $this->insertEdit
->getHtmlForIgnoreOption(1),
2423 sprintf($expected, ''),
2424 $this->insertEdit
->getHtmlForIgnoreOption(1, false),
2429 * Test for getHtmlForInsertEditFormColumn
2431 public function testGetHtmlForInsertEditFormColumn(): void
2433 $_SESSION[' HMAC_secret '] = hash('sha1', 'test');
2434 InsertEdit
::$pluginScripts = [];
2435 $foreigners = ['foreign_keys_data' => []];
2436 $tableColumn = new Column('col', 'varchar(20)', null, true, '', null, '', 'insert,update,select', '');
2437 $repopulate = [md5('col') => 'val'];
2439 'input_transformation' => 'Input/Image_JPEG_Upload.php',
2440 'input_transformation_options' => '150',
2443 // Test w/ input transformation
2444 $actual = $this->callFunction(
2447 'getHtmlForInsertEditFormColumn',
2468 $actual = $this->parseString($actual);
2470 self
::assertStringContainsString('col', $actual);
2471 self
::assertStringContainsString('<option>AES_ENCRYPT</option>', $actual);
2472 self
::assertStringContainsString('<span class="column_type" dir="ltr">varchar(20)</span>', $actual);
2473 self
::assertStringContainsString('<tr class="noclick">', $actual);
2474 self
::assertStringContainsString('<span class="default_value hide">', $actual);
2475 self
::assertStringContainsString('<img src="" width="150" height="100" alt="Image preview here">', $actual);
2476 self
::assertStringContainsString(
2477 '<input type="file" '
2478 . 'name="fields_upload[multi_edit][0][d89e2ddb530bb8953b290ab0793aecb0]" '
2479 . 'accept="image/*" '
2480 . 'class="image-upload"'
2485 // Test w/o input_transformation
2486 $tableColumn = new Column('qwerty', 'datetime', null, true, '', null, '', 'insert,update,select', '');
2487 $repopulate = [md5('qwerty') => '12-10-14'];
2488 $actual = $this->callFunction(
2491 'getHtmlForInsertEditFormColumn',
2512 $actual = $this->parseString($actual);
2514 self
::assertStringContainsString('qwerty', $actual);
2515 self
::assertStringContainsString('<option>UUID</option>', $actual);
2516 self
::assertStringContainsString('<span class="column_type" dir="ltr">datetime</span>', $actual);
2517 self
::assertStringContainsString(
2518 '<input type="text" name="fields[multi_edit][0][d8578edf8458ce06fbc5bb76a58c5ca4]" value="12-10-14.000000"',
2522 self
::assertStringContainsString(
2523 '<select name="funcs[multi_edit][0][d8578edf8458ce06fbc5bb76a58c5ca4]"'
2524 . ' onchange="return verificationsAfterFieldChange(\'d8578edf8458ce06fbc5bb76a58c5ca4\','
2525 . ' \'0\', \'datetime\')" id="field_1_1">',
2528 self
::assertStringContainsString('<option>DATE</option>', $actual);
2530 self
::assertStringContainsString(
2531 '<input type="hidden" name="fields_null_prev[multi_edit][0][d8578edf8458ce06fbc5bb76a58c5ca4]">',
2535 self
::assertStringContainsString(
2536 '<input type="checkbox" class="checkbox_null"'
2537 . ' name="fields_null[multi_edit][0][d8578edf8458ce06fbc5bb76a58c5ca4]" id="field_1_2"'
2538 . ' aria-label="Use the NULL value for this column.">',
2542 self
::assertStringContainsString(
2543 '<input type="hidden" class="nullify_code"'
2544 . ' name="nullify_code[multi_edit][0][d8578edf8458ce06fbc5bb76a58c5ca4]" value="5"',
2548 self
::assertStringContainsString(
2549 '<input type="hidden" class="hashed_field"'
2550 . ' name="hashed_field[multi_edit][0][d8578edf8458ce06fbc5bb76a58c5ca4]" '
2551 . 'value="d8578edf8458ce06fbc5bb76a58c5ca4">',
2555 self
::assertStringContainsString(
2556 '<input type="hidden" class="multi_edit"'
2557 . ' name="multi_edit[multi_edit][0][d8578edf8458ce06fbc5bb76a58c5ca4]" value="[multi_edit][0]"',
2563 * Test for getHtmlForInsertEditRow
2565 public function testGetHtmlForInsertEditRow(): void
2567 InsertEdit
::$pluginScripts = [];
2568 $config = Config
::getInstance();
2569 $config->settings
['LongtextDoubleTextarea'] = true;
2570 $config->settings
['CharEditing'] = 'input';
2571 $config->settings
['TextareaRows'] = 10;
2572 $config->settings
['TextareaCols'] = 11;
2573 $foreigners = ['foreign_keys_data' => []];
2575 new Column('test', 'longtext', null, true, '', null, '', 'select,insert,update,references', ''),
2578 $actual = $this->insertEdit
->getHtmlForInsertEditRow(
2582 [FieldHelper
::fromArray(['type' => 0, 'length' => -1])],
2593 self
::assertStringContainsString('test', $actual);
2594 self
::assertStringContainsString('<th>Column</th>', $actual);
2595 self
::assertStringContainsString('<a', $actual);
2596 self
::assertStringContainsString('<th class="w-50">Value</th>', $actual);
2597 self
::assertStringContainsString('<span class="column_type" dir="ltr">longtext</span>', $actual);
2598 self
::assertStringContainsString(
2599 '<textarea name="fields[multi_edit][0][098f6bcd4621d373cade4e832627b4f6]" id="field_1_3"'
2600 . ' data-type="CHAR" dir="ltr" rows="20" cols="22"',
2606 * Test for getHtmlForInsertEditRow based on the column privilges
2608 public function testGetHtmlForInsertEditRowBasedOnColumnPrivileges(): void
2610 InsertEdit
::$pluginScripts = [];
2611 $config = Config
::getInstance();
2612 $config->settings
['LongtextDoubleTextarea'] = true;
2613 $config->settings
['CharEditing'] = 'input';
2614 $foreigners = ['foreign_keys_data' => []];
2618 new Column('foo', 'longtext', null, true, '', null, '', 'select,insert,update,references', ''),
2619 new Column('bar', 'longtext', null, true, '', null, '', 'select,insert,references', ''),
2623 FieldHelper
::fromArray(['type' => 0, 'length' => -1]),
2624 FieldHelper
::fromArray(['type' => 0, 'length' => -1]),
2625 FieldHelper
::fromArray(['type' => 0, 'length' => -1]),
2628 $actual = $this->insertEdit
->getHtmlForInsertEditRow(
2643 self
::assertStringContainsString('foo', $actual);
2644 self
::assertStringContainsString('bar', $actual);
2648 new Column('foo', 'longtext', null, true, '', null, '', 'select,insert,update,references', ''),
2649 new Column('bar', 'longtext', null, true, '', null, '', 'select,update,references', ''),
2650 new Column('point', 'point', null, false, '', null, '', 'select,update,references', ''),
2652 $actual = $this->insertEdit
->getHtmlForInsertEditRow(
2667 self
::assertStringContainsString('foo', $actual);
2668 self
::assertStringContainsString(
2669 '<textarea name="fields[multi_edit][0][37b51d194a7513e45b56f6524f2d51f2]"',
2672 self
::assertStringContainsString(
2673 '<span class="text-nowrap"><img src="themes/dot.gif" title="Edit/Insert"' .
2674 ' alt="Edit/Insert" class="icon ic_b_edit"> Edit/Insert</span>',
2680 * Convert mixed type value to string
2682 private function parseString(mixed $value): string
2684 if (is_string($value)) {
2688 if (is_object($value) ||
is_scalar($value)) {
2689 return (string) $value;