Ref #16847 - Fix JSON export code duplicated and not following rules in raw query export mode
Signed-off-by: William Desportes <williamdes@wdes.fr>
This commit is contained in:
parent
45aeee579a
commit
cbd35c9fa8
@ -231,6 +231,42 @@ class ExportJson extends ExportPlugin
|
||||
'data' => '@@DATA@@',
|
||||
]
|
||||
);
|
||||
|
||||
return $this->doExportForQuery(
|
||||
$dbi,
|
||||
$sql_query,
|
||||
$buffer,
|
||||
$crlf,
|
||||
$aliases,
|
||||
$db,
|
||||
$table
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Export to JSON
|
||||
*
|
||||
* @return bool False on export fail and true on export end success
|
||||
*
|
||||
* @phpstan-param array{
|
||||
* string: array{
|
||||
* 'tables': array{
|
||||
* string: array{
|
||||
* 'columns': array{string: string}
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }|array|null $aliases
|
||||
*/
|
||||
protected function doExportForQuery(
|
||||
DatabaseInterface $dbi,
|
||||
string $sql_query,
|
||||
string $buffer,
|
||||
string $crlf,
|
||||
?array $aliases,
|
||||
?string $db,
|
||||
?string $table
|
||||
): bool {
|
||||
[$header, $footer] = explode('"@@DATA@@"', $buffer);
|
||||
|
||||
if (! $this->export->outputHandler($header . $crlf . '[' . $crlf)) {
|
||||
@ -248,7 +284,9 @@ class ExportJson extends ExportPlugin
|
||||
$columns = [];
|
||||
for ($i = 0; $i < $columns_cnt; $i++) {
|
||||
$col_as = $dbi->fieldName($result, $i);
|
||||
if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) {
|
||||
if ($db !== null && $table !== null && $aliases !== null
|
||||
&& ! empty($aliases[$db]['tables'][$table]['columns'][$col_as])
|
||||
) {
|
||||
$col_as = $aliases[$db]['tables'][$table]['columns'][$col_as];
|
||||
}
|
||||
$columns[$i] = stripslashes($col_as);
|
||||
@ -323,56 +361,15 @@ class ExportJson extends ExportPlugin
|
||||
'data' => '@@DATA@@',
|
||||
]
|
||||
);
|
||||
[$header, $footer] = explode('"@@DATA@@"', $buffer);
|
||||
|
||||
if (! $this->export->outputHandler($header . $crlf . '[' . $crlf)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = $dbi->query(
|
||||
return $this->doExportForQuery(
|
||||
$dbi,
|
||||
$sql_query,
|
||||
DatabaseInterface::CONNECT_USER,
|
||||
DatabaseInterface::QUERY_UNBUFFERED
|
||||
$buffer,
|
||||
$crlf,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
$columns_cnt = $dbi->numFields($result);
|
||||
|
||||
$columns = [];
|
||||
for ($i = 0; $i < $columns_cnt; $i++) {
|
||||
$col_as = $dbi->fieldName($result, $i);
|
||||
$columns[$i] = stripslashes($col_as);
|
||||
}
|
||||
|
||||
$record_cnt = 0;
|
||||
while ($record = $dbi->fetchRow($result)) {
|
||||
$record_cnt++;
|
||||
|
||||
if ($record_cnt > 1) {
|
||||
if (! $this->export->outputHandler(',' . $crlf)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$data = [];
|
||||
|
||||
for ($i = 0; $i < $columns_cnt; $i++) {
|
||||
$data[$columns[$i]] = $record[$i];
|
||||
}
|
||||
|
||||
$encodedData = $this->encode($data);
|
||||
if (! $encodedData) {
|
||||
return false;
|
||||
}
|
||||
if (! $this->export->outputHandler($encodedData)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (! $this->export->outputHandler($crlf . ']' . $crlf . $footer . $crlf)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$dbi->freeResult($result);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -340,4 +340,103 @@ class ExportJsonTest extends AbstractTestCase
|
||||
$this->object->exportData('db', 'tbl', "\n", 'example.com', 'SELECT')
|
||||
);
|
||||
}
|
||||
|
||||
public function testExportRawComplexData(): void
|
||||
{
|
||||
$dbi = $this->getMockBuilder(DatabaseInterface::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$flags = [];
|
||||
$normalString = new stdClass();
|
||||
$normalString->blob = false;
|
||||
$normalString->numeric = false;
|
||||
$normalString->type = 'string';
|
||||
$normalString->name = 'f1';
|
||||
$normalString->charsetnr = 33;
|
||||
$normalString->length = 20;
|
||||
$flags[] = $normalString;
|
||||
$binaryField = new stdClass();
|
||||
$binaryField->blob = false;
|
||||
$binaryField->numeric = false;
|
||||
$binaryField->type = 'string';
|
||||
$binaryField->name = 'f1';
|
||||
$binaryField->charsetnr = 63;
|
||||
$binaryField->length = 20;
|
||||
$flags[] = $binaryField;
|
||||
$textField = new stdClass();
|
||||
$textField->blob = false;
|
||||
$textField->numeric = false;
|
||||
$textField->type = 'blob';
|
||||
$textField->name = 'f1';
|
||||
$textField->charsetnr = 23;
|
||||
$textField->length = 20;
|
||||
$flags[] = $textField;
|
||||
$blobField = new stdClass();
|
||||
$blobField->blob = false;
|
||||
$blobField->numeric = false;
|
||||
$blobField->type = 'blob';
|
||||
$blobField->name = 'f1';
|
||||
$blobField->charsetnr = 63;
|
||||
$blobField->length = 20;
|
||||
$flags[] = $blobField;
|
||||
|
||||
$dbi->expects($this->once())
|
||||
->method('getFieldsMeta')
|
||||
->with(null)
|
||||
->will($this->returnValue($flags));
|
||||
|
||||
$dbi->expects($this->once())
|
||||
->method('numFields')
|
||||
->with(null)
|
||||
->will($this->returnValue(4));
|
||||
|
||||
$dbi->expects($this->exactly(4))
|
||||
->method('fieldName')
|
||||
->withConsecutive(
|
||||
[null, 0],
|
||||
[null, 1],
|
||||
[null, 2],
|
||||
[null, 3]
|
||||
)
|
||||
->willReturnOnConsecutiveCalls(
|
||||
'f1',
|
||||
'f2',
|
||||
'f3',
|
||||
'f4'
|
||||
);
|
||||
|
||||
$dbi->expects($this->exactly(4))
|
||||
->method('fetchRow')
|
||||
->withConsecutive(
|
||||
[null],
|
||||
[null],
|
||||
[null],
|
||||
[null]
|
||||
)
|
||||
->willReturnOnConsecutiveCalls(
|
||||
// normalString binaryField textField blobField
|
||||
['"\'"><iframe onload=alert(1)>шеллы', '0x12346857fefe', "My awesome\nText", '0xaf1234f68c57fefe'],
|
||||
[null, null, null, null],
|
||||
['', '0x1', 'шеллы', '0x2'],
|
||||
null// No more data
|
||||
);
|
||||
|
||||
$GLOBALS['dbi'] = $dbi;
|
||||
|
||||
$this->expectOutputString(
|
||||
'{"type":"raw","data":'
|
||||
. "\n[\n"
|
||||
. '{"f1":"\"\'\"><iframe onload=alert(1)>\u0448\u0435\u043b\u043b\u044b",'
|
||||
. '"f2":"0x3078313233343638353766656665",'
|
||||
. '"f3":"My awesome\nText","f4":"0x307861663132333466363863353766656665"},' . "\n"
|
||||
. '{"f1":null,"f2":null,"f3":null,"f4":null},' . "\n"
|
||||
. '{"f1":"","f2":"0x307831","f3":"\u0448\u0435\u043b\u043b\u044b","f4":"0x307832"}' . "\n"
|
||||
. "]\n}\n"
|
||||
);
|
||||
|
||||
$this->assertTrue(
|
||||
$this->object->exportRawQuery('example.com', 'SELECT', "\n")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user