Produce valid JSON on export

The JSON export now generates valid JSON data, but this means that the
resulting JSON format has changed.

Fixes #12307

Signed-off-by: Michal Čihař <michal@cihar.com>
This commit is contained in:
Michal Čihař 2016-06-14 08:36:28 +02:00
parent 25ede08182
commit 136b85fc97
4 changed files with 168 additions and 40 deletions

View File

@ -17,6 +17,7 @@ phpMyAdmin - ChangeLog
- issue #12196 Removed $cfg['ThemePath']
- issue #6274 Add support for export user settings as config.inc.php snippet
- issue #5555 Better report query errors while generating SQL exports
- issue #12307 Produce valid JSON on export
4.6.3 (not yet released)
- issue #12249 Fixed cookie path on Windows

View File

@ -152,6 +152,88 @@ JSON (JavaScript Object Notation) is a lightweight data-interchange format. It
is easy for humans to read and write and it is easy for machines to parse and
generate.
.. versionchanged:: 4.7.0
The generated JSON structure has been changed in phpMyAdmin 4.7.0 to
produce valid JSON data.
The generated JSON is list of objects with following attributes:
.. js:data:: type
Type of given object, can be one of:
``header``
Export header containing comment and phpMyAdmin version.
``database``
Start of a database marker, containing name of database.
``table``
Table data export.
.. js:data:: version
Used in ``header`` :js:data:`type` and indicates phpMyAdmin version.
.. js:data:: comment
Optional textual comment.
.. js:data:: name
Object name - either table or database based on :js:data:`type`.
.. js:data:: database
Database name for ``table`` :js:data:`type`.
.. js:data:: data
Table content for ``table`` :js:data:`type`.
Sample output:
.. code-block:: json
[
{
"comment": "Export to JSON plugin for PHPMyAdmin",
"type": "header",
"version": "4.7.0-dev"
},
{
"name": "cars",
"type": "database"
},
{
"data": [
{
"car_id": "1",
"description": "Green Chrysler 300",
"make_id": "5",
"mileage": "113688",
"price": "13545.00",
"transmission": "automatic",
"yearmade": "2007"
}
],
"database": "cars",
"name": "cars",
"type": "table"
},
{
"data": [
{
"make": "Chrysler",
"make_id": "5"
}
],
"database": "cars",
"name": "makes",
"type": "table"
}
]
LaTeX
-----

View File

@ -24,6 +24,8 @@ use PMA;
*/
class ExportJson extends ExportPlugin
{
private $first = true;
/**
* Constructor
*/
@ -32,6 +34,24 @@ class ExportJson extends ExportPlugin
$this->setProperties();
}
/**
* Encodes the data into JSON
*
* @param mixed $data Data to encode
*
* @return string
*/
public function encode($data)
{
if (isset($GLOBALS['json_pretty_print'])
&& $GLOBALS['json_pretty_print']
) {
return json_encode($data, JSON_PRETTY_PRINT);
} else {
return json_encode($data);
}
}
/**
* Sets the export JSON properties
*
@ -79,14 +99,17 @@ class ExportJson extends ExportPlugin
*/
public function exportHeader()
{
PMA_exportOutputHandler(
'/**' . $GLOBALS['crlf']
. ' Export to JSON plugin for PHPMyAdmin' . $GLOBALS['crlf']
. ' @version ' . PMA_VERSION . $GLOBALS['crlf']
. ' */' . $GLOBALS['crlf'] . $GLOBALS['crlf']
global $crlf;
$meta = array(
'type' => 'header',
'version' => PMA_VERSION,
'comment' => 'Export to JSON plugin for PHPMyAdmin',
);
return true;
return PMA_exportOutputHandler(
'[' . $crlf . $this->encode($meta) . ',' . $crlf
);
}
/**
@ -96,7 +119,9 @@ class ExportJson extends ExportPlugin
*/
public function exportFooter()
{
return true;
global $crlf;
return PMA_exportOutputHandler(']' . $crlf);
}
/**
@ -109,14 +134,20 @@ class ExportJson extends ExportPlugin
*/
public function exportDBHeader($db, $db_alias = '')
{
global $crlf;
if (empty($db_alias)) {
$db_alias = $db;
}
PMA_exportOutputHandler(
'// Database \'' . $db_alias . '\'' . $GLOBALS['crlf']
$meta = array(
'type' => 'database',
'name' => $db_alias
);
return true;
return PMA_exportOutputHandler(
$this->encode($meta) . ',' . $crlf
);
}
/**
@ -169,6 +200,28 @@ class ExportJson extends ExportPlugin
$table_alias = $table;
$this->initAlias($aliases, $db_alias, $table_alias);
if (! $this->first) {
if (!PMA_exportOutputHandler(',')) {
return false;
}
} else {
$this->first = false;
}
$buffer = $this->encode(
array(
'type' => 'table',
'name' => $table_alias,
'database' => $db_alias,
'data' => "@@DATA@@"
)
);
list($header, $footer) = explode('"@@DATA@@"', $buffer);
if (!PMA_exportOutputHandler($header . $crlf . '[' . $crlf)) {
return false;
}
$result = $GLOBALS['dbi']->query(
$sql_query,
null,
@ -191,16 +244,10 @@ class ExportJson extends ExportPlugin
$record_cnt++;
// Output table name as comment if this is the first record of the table
if ($record_cnt == 1) {
$buffer = $crlf . '// ' . $db_alias . '.' . $table_alias
. $crlf . $crlf;
$buffer .= '[';
} else {
$buffer = ', ';
}
if (!PMA_exportOutputHandler($buffer)) {
return false;
if ($record_cnt > 1) {
if (!PMA_exportOutputHandler(',' . $crlf)) {
return false;
}
}
$data = array();
@ -209,23 +256,13 @@ class ExportJson extends ExportPlugin
$data[$columns[$i]] = $record[$i];
}
if (isset($GLOBALS['json_pretty_print'])
&& $GLOBALS['json_pretty_print']
) {
$encoded = json_encode($data, JSON_PRETTY_PRINT);
} else {
$encoded = json_encode($data);
}
if (!PMA_exportOutputHandler($encoded)) {
if (!PMA_exportOutputHandler($this->encode($data))) {
return false;
}
}
if ($record_cnt) {
if (!PMA_exportOutputHandler(']' . $crlf)) {
return false;
}
if (!PMA_exportOutputHandler($crlf . ']' . $crlf . $footer . $crlf)) {
return false;
}
$GLOBALS['dbi']->freeResult($result);

View File

@ -139,10 +139,10 @@ class ExportJsonTest extends PMATestCase
$GLOBALS['crlf'] = "\n";
$this->expectOutputString(
'/**' . "\n"
. ' Export to JSON plugin for PHPMyAdmin' . "\n"
. ' @version ' . PMA_VERSION . "\n"
. ' */' . "\n" . "\n"
"[\n"
. '{"type":"header","version":"' . PMA_VERSION
. '","comment":"Export to JSON plugin for PHPMyAdmin"},'
. "\n"
);
$this->assertTrue(
@ -157,6 +157,10 @@ class ExportJsonTest extends PMATestCase
*/
public function testExportFooter()
{
$this->expectOutputString(
']'
);
$this->assertTrue(
$this->object->exportFooter()
);
@ -172,7 +176,7 @@ class ExportJsonTest extends PMATestCase
$GLOBALS['crlf'] = "\n";
$this->expectOutputString(
"// Database 'testDB'\n"
'{"type":"database","name":"testDB"},' . "\n"
);
$this->assertTrue(
@ -243,8 +247,12 @@ class ExportJsonTest extends PMATestCase
$GLOBALS['dbi'] = $dbi;
$this->expectOutputString(
"\n// db.tbl\n\n" .
"[{\"f1\":\"foo\"}, {\"f1\":\"bar\"}]\n"
'{"type":"table","name":"tbl","database":"db","data":'
. "\n[\n"
. '{"f1":"foo"},'
. "\n"
. '{"f1":"bar"}'
. "\n]\n}\n"
);
$this->assertTrue(