Update website
This commit is contained in:
parent
4413528994
commit
1d90fbf296
6865 changed files with 1091082 additions and 0 deletions
|
@ -0,0 +1,392 @@
|
|||
<?php
|
||||
/**
|
||||
* Set of functions used to build NHibernate dumps of tables
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Plugins\Export;
|
||||
|
||||
use PhpMyAdmin\Plugins\Export\Helpers\TableProperty;
|
||||
use PhpMyAdmin\Plugins\ExportPlugin;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup;
|
||||
use PhpMyAdmin\Properties\Options\Items\HiddenPropertyItem;
|
||||
use PhpMyAdmin\Properties\Options\Items\SelectPropertyItem;
|
||||
use PhpMyAdmin\Properties\Plugins\ExportPluginProperties;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function __;
|
||||
use function implode;
|
||||
use function preg_match;
|
||||
use function preg_replace;
|
||||
use function sprintf;
|
||||
use function ucfirst;
|
||||
|
||||
/**
|
||||
* Handles the export for the CodeGen class
|
||||
*/
|
||||
class ExportCodegen extends ExportPlugin
|
||||
{
|
||||
/**
|
||||
* CodeGen Formats
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $cgFormats;
|
||||
|
||||
private const HANDLER_NHIBERNATE_CS = 0;
|
||||
private const HANDLER_NHIBERNATE_XML = 1;
|
||||
|
||||
/**
|
||||
* @psalm-return non-empty-lowercase-string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'codegen';
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the local variables that are used for export CodeGen.
|
||||
*/
|
||||
protected function init(): void
|
||||
{
|
||||
$this->setCgFormats([
|
||||
self::HANDLER_NHIBERNATE_CS => 'NHibernate C# DO',
|
||||
self::HANDLER_NHIBERNATE_XML => 'NHibernate XML',
|
||||
]);
|
||||
}
|
||||
|
||||
protected function setProperties(): ExportPluginProperties
|
||||
{
|
||||
$exportPluginProperties = new ExportPluginProperties();
|
||||
$exportPluginProperties->setText('CodeGen');
|
||||
$exportPluginProperties->setExtension('cs');
|
||||
$exportPluginProperties->setMimeType('text/cs');
|
||||
$exportPluginProperties->setOptionsText(__('Options'));
|
||||
|
||||
// create the root group that will be the options field for
|
||||
// $exportPluginProperties
|
||||
// this will be shown as "Format specific options"
|
||||
$exportSpecificOptions = new OptionsPropertyRootGroup('Format Specific Options');
|
||||
|
||||
// general options main group
|
||||
$generalOptions = new OptionsPropertyMainGroup('general_opts');
|
||||
// create primary items and add them to the group
|
||||
$leaf = new HiddenPropertyItem('structure_or_data');
|
||||
$generalOptions->addProperty($leaf);
|
||||
$leaf = new SelectPropertyItem(
|
||||
'format',
|
||||
__('Format:')
|
||||
);
|
||||
$leaf->setValues($this->getCgFormats());
|
||||
$generalOptions->addProperty($leaf);
|
||||
// add the main group to the root group
|
||||
$exportSpecificOptions->addProperty($generalOptions);
|
||||
|
||||
// set the options for the export plugin property item
|
||||
$exportPluginProperties->setOptions($exportSpecificOptions);
|
||||
|
||||
return $exportPluginProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export header
|
||||
*/
|
||||
public function exportHeader(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export footer
|
||||
*/
|
||||
public function exportFooter(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database header
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $dbAlias Aliases of db
|
||||
*/
|
||||
public function exportDBHeader($db, $dbAlias = ''): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database footer
|
||||
*
|
||||
* @param string $db Database name
|
||||
*/
|
||||
public function exportDBFooter($db): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs CREATE DATABASE statement
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $exportType 'server', 'database', 'table'
|
||||
* @param string $dbAlias Aliases of db
|
||||
*/
|
||||
public function exportDBCreate($db, $exportType, $dbAlias = ''): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the content of a table in NHibernate format
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
* @param string $crlf the end of line sequence
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string $sqlQuery SQL query for obtaining data
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*/
|
||||
public function exportData(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$sqlQuery,
|
||||
array $aliases = []
|
||||
): bool {
|
||||
$format = (int) $GLOBALS['codegen_format'];
|
||||
|
||||
if ($format === self::HANDLER_NHIBERNATE_CS) {
|
||||
return $this->export->outputHandler($this->handleNHibernateCSBody($db, $table, $crlf, $aliases));
|
||||
}
|
||||
|
||||
if ($format === self::HANDLER_NHIBERNATE_XML) {
|
||||
return $this->export->outputHandler($this->handleNHibernateXMLBody($db, $table, $crlf, $aliases));
|
||||
}
|
||||
|
||||
return $this->export->outputHandler(sprintf('%s is not supported.', $format));
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to make identifiers (from table or database names)
|
||||
*
|
||||
* @param string $str name to be converted
|
||||
* @param bool $ucfirst whether to make the first character uppercase
|
||||
*
|
||||
* @return string identifier
|
||||
*/
|
||||
public static function cgMakeIdentifier($str, $ucfirst = true)
|
||||
{
|
||||
// remove unsafe characters
|
||||
$str = (string) preg_replace('/[^\p{L}\p{Nl}_]/u', '', $str);
|
||||
// make sure first character is a letter or _
|
||||
if (! preg_match('/^\pL/u', $str)) {
|
||||
$str = '_' . $str;
|
||||
}
|
||||
|
||||
if ($ucfirst) {
|
||||
$str = ucfirst($str);
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* C# Handler
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
* @param string $crlf line separator
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*
|
||||
* @return string containing C# code lines, separated by "\n"
|
||||
*/
|
||||
private function handleNHibernateCSBody($db, $table, $crlf, array $aliases = [])
|
||||
{
|
||||
global $dbi;
|
||||
|
||||
$db_alias = $db;
|
||||
$table_alias = $table;
|
||||
$this->initAlias($aliases, $db_alias, $table_alias);
|
||||
|
||||
$result = $dbi->query(
|
||||
sprintf(
|
||||
'DESC %s.%s',
|
||||
Util::backquote($db),
|
||||
Util::backquote($table)
|
||||
)
|
||||
);
|
||||
|
||||
/** @var TableProperty[] $tableProperties */
|
||||
$tableProperties = [];
|
||||
while ($row = $result->fetchRow()) {
|
||||
$col_as = $this->getAlias($aliases, $row[0], 'col', $db, $table);
|
||||
if (! empty($col_as)) {
|
||||
$row[0] = $col_as;
|
||||
}
|
||||
|
||||
$tableProperties[] = new TableProperty($row);
|
||||
}
|
||||
|
||||
unset($result);
|
||||
|
||||
$lines = [];
|
||||
$lines[] = 'using System;';
|
||||
$lines[] = 'using System.Collections;';
|
||||
$lines[] = 'using System.Collections.Generic;';
|
||||
$lines[] = 'using System.Text;';
|
||||
$lines[] = 'namespace ' . self::cgMakeIdentifier($db_alias);
|
||||
$lines[] = '{';
|
||||
$lines[] = ' #region '
|
||||
. self::cgMakeIdentifier($table_alias);
|
||||
$lines[] = ' public class '
|
||||
. self::cgMakeIdentifier($table_alias);
|
||||
$lines[] = ' {';
|
||||
$lines[] = ' #region Member Variables';
|
||||
foreach ($tableProperties as $tableProperty) {
|
||||
$lines[] = $tableProperty->formatCs(' protected #dotNetPrimitiveType# _#name#;');
|
||||
}
|
||||
|
||||
$lines[] = ' #endregion';
|
||||
$lines[] = ' #region Constructors';
|
||||
$lines[] = ' public '
|
||||
. self::cgMakeIdentifier($table_alias) . '() { }';
|
||||
$temp = [];
|
||||
foreach ($tableProperties as $tableProperty) {
|
||||
if ($tableProperty->isPK()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$temp[] = $tableProperty->formatCs('#dotNetPrimitiveType# #name#');
|
||||
}
|
||||
|
||||
$lines[] = ' public '
|
||||
. self::cgMakeIdentifier($table_alias)
|
||||
. '('
|
||||
. implode(', ', $temp)
|
||||
. ')';
|
||||
$lines[] = ' {';
|
||||
foreach ($tableProperties as $tableProperty) {
|
||||
if ($tableProperty->isPK()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$lines[] = $tableProperty->formatCs(' this._#name#=#name#;');
|
||||
}
|
||||
|
||||
$lines[] = ' }';
|
||||
$lines[] = ' #endregion';
|
||||
$lines[] = ' #region Public Properties';
|
||||
foreach ($tableProperties as $tableProperty) {
|
||||
$lines[] = $tableProperty->formatCs(
|
||||
' public virtual #dotNetPrimitiveType# #ucfirstName#'
|
||||
. "\n"
|
||||
. ' {' . "\n"
|
||||
. ' get {return _#name#;}' . "\n"
|
||||
. ' set {_#name#=value;}' . "\n"
|
||||
. ' }'
|
||||
);
|
||||
}
|
||||
|
||||
$lines[] = ' #endregion';
|
||||
$lines[] = ' }';
|
||||
$lines[] = ' #endregion';
|
||||
$lines[] = '}';
|
||||
|
||||
return implode($crlf, $lines);
|
||||
}
|
||||
|
||||
/**
|
||||
* XML Handler
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
* @param string $crlf line separator
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*
|
||||
* @return string containing XML code lines, separated by "\n"
|
||||
*/
|
||||
private function handleNHibernateXMLBody(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
array $aliases = []
|
||||
) {
|
||||
global $dbi;
|
||||
|
||||
$db_alias = $db;
|
||||
$table_alias = $table;
|
||||
$this->initAlias($aliases, $db_alias, $table_alias);
|
||||
$lines = [];
|
||||
$lines[] = '<?xml version="1.0" encoding="utf-8" ?>';
|
||||
$lines[] = '<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" '
|
||||
. 'namespace="' . self::cgMakeIdentifier($db_alias) . '" '
|
||||
. 'assembly="' . self::cgMakeIdentifier($db_alias) . '">';
|
||||
$lines[] = ' <class '
|
||||
. 'name="' . self::cgMakeIdentifier($table_alias) . '" '
|
||||
. 'table="' . self::cgMakeIdentifier($table_alias) . '">';
|
||||
$result = $dbi->query(
|
||||
sprintf(
|
||||
'DESC %s.%s',
|
||||
Util::backquote($db),
|
||||
Util::backquote($table)
|
||||
)
|
||||
);
|
||||
|
||||
while ($row = $result->fetchRow()) {
|
||||
$col_as = $this->getAlias($aliases, $row[0], 'col', $db, $table);
|
||||
if (! empty($col_as)) {
|
||||
$row[0] = $col_as;
|
||||
}
|
||||
|
||||
$tableProperty = new TableProperty($row);
|
||||
if ($tableProperty->isPK()) {
|
||||
$lines[] = $tableProperty->formatXml(
|
||||
' <id name="#ucfirstName#" type="#dotNetObjectType#"'
|
||||
. ' unsaved-value="0">' . "\n"
|
||||
. ' <column name="#name#" sql-type="#type#"'
|
||||
. ' not-null="#notNull#" unique="#unique#"'
|
||||
. ' index="PRIMARY"/>' . "\n"
|
||||
. ' <generator class="native" />' . "\n"
|
||||
. ' </id>'
|
||||
);
|
||||
} else {
|
||||
$lines[] = $tableProperty->formatXml(
|
||||
' <property name="#ucfirstName#"'
|
||||
. ' type="#dotNetObjectType#">' . "\n"
|
||||
. ' <column name="#name#" sql-type="#type#"'
|
||||
. ' not-null="#notNull#" #indexName#/>' . "\n"
|
||||
. ' </property>'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$lines[] = ' </class>';
|
||||
$lines[] = '</hibernate-mapping>';
|
||||
|
||||
return implode($crlf, $lines);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for CodeGen formats
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getCgFormats()
|
||||
{
|
||||
return $this->cgFormats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for CodeGen formats
|
||||
*
|
||||
* @param array $CG_FORMATS contains CodeGen Formats
|
||||
*/
|
||||
private function setCgFormats(array $CG_FORMATS): void
|
||||
{
|
||||
$this->cgFormats = $CG_FORMATS;
|
||||
}
|
||||
}
|
334
admin/phpMyAdmin/libraries/classes/Plugins/Export/ExportCsv.php
Normal file
334
admin/phpMyAdmin/libraries/classes/Plugins/Export/ExportCsv.php
Normal file
|
@ -0,0 +1,334 @@
|
|||
<?php
|
||||
/**
|
||||
* CSV export code
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Plugins\Export;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Plugins\ExportPlugin;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup;
|
||||
use PhpMyAdmin\Properties\Options\Items\BoolPropertyItem;
|
||||
use PhpMyAdmin\Properties\Options\Items\HiddenPropertyItem;
|
||||
use PhpMyAdmin\Properties\Options\Items\TextPropertyItem;
|
||||
use PhpMyAdmin\Properties\Plugins\ExportPluginProperties;
|
||||
|
||||
use function __;
|
||||
use function mb_strtolower;
|
||||
use function mb_substr;
|
||||
use function preg_replace;
|
||||
use function str_replace;
|
||||
use function stripslashes;
|
||||
use function trim;
|
||||
|
||||
/**
|
||||
* Handles the export for the CSV format
|
||||
*/
|
||||
class ExportCsv extends ExportPlugin
|
||||
{
|
||||
/**
|
||||
* @psalm-return non-empty-lowercase-string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'csv';
|
||||
}
|
||||
|
||||
protected function setProperties(): ExportPluginProperties
|
||||
{
|
||||
$exportPluginProperties = new ExportPluginProperties();
|
||||
$exportPluginProperties->setText('CSV');
|
||||
$exportPluginProperties->setExtension('csv');
|
||||
$exportPluginProperties->setMimeType('text/comma-separated-values');
|
||||
$exportPluginProperties->setOptionsText(__('Options'));
|
||||
|
||||
// create the root group that will be the options field for
|
||||
// $exportPluginProperties
|
||||
// this will be shown as "Format specific options"
|
||||
$exportSpecificOptions = new OptionsPropertyRootGroup('Format Specific Options');
|
||||
|
||||
// general options main group
|
||||
$generalOptions = new OptionsPropertyMainGroup('general_opts');
|
||||
// create leaf items and add them to the group
|
||||
$leaf = new TextPropertyItem(
|
||||
'separator',
|
||||
__('Columns separated with:')
|
||||
);
|
||||
$generalOptions->addProperty($leaf);
|
||||
$leaf = new TextPropertyItem(
|
||||
'enclosed',
|
||||
__('Columns enclosed with:')
|
||||
);
|
||||
$generalOptions->addProperty($leaf);
|
||||
$leaf = new TextPropertyItem(
|
||||
'escaped',
|
||||
__('Columns escaped with:')
|
||||
);
|
||||
$generalOptions->addProperty($leaf);
|
||||
$leaf = new TextPropertyItem(
|
||||
'terminated',
|
||||
__('Lines terminated with:')
|
||||
);
|
||||
$generalOptions->addProperty($leaf);
|
||||
$leaf = new TextPropertyItem(
|
||||
'null',
|
||||
__('Replace NULL with:')
|
||||
);
|
||||
$generalOptions->addProperty($leaf);
|
||||
$leaf = new BoolPropertyItem(
|
||||
'removeCRLF',
|
||||
__('Remove carriage return/line feed characters within columns')
|
||||
);
|
||||
$generalOptions->addProperty($leaf);
|
||||
$leaf = new BoolPropertyItem(
|
||||
'columns',
|
||||
__('Put columns names in the first row')
|
||||
);
|
||||
$generalOptions->addProperty($leaf);
|
||||
$leaf = new HiddenPropertyItem('structure_or_data');
|
||||
$generalOptions->addProperty($leaf);
|
||||
// add the main group to the root group
|
||||
$exportSpecificOptions->addProperty($generalOptions);
|
||||
|
||||
// set the options for the export plugin property item
|
||||
$exportPluginProperties->setOptions($exportSpecificOptions);
|
||||
|
||||
return $exportPluginProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export header
|
||||
*/
|
||||
public function exportHeader(): bool
|
||||
{
|
||||
global $what, $csv_terminated, $csv_separator, $csv_enclosed, $csv_escaped;
|
||||
|
||||
// Here we just prepare some values for export
|
||||
if ($what === 'excel') {
|
||||
$csv_terminated = "\015\012";
|
||||
switch ($GLOBALS['excel_edition']) {
|
||||
case 'win':
|
||||
// as tested on Windows with Excel 2002 and Excel 2007
|
||||
$csv_separator = ';';
|
||||
break;
|
||||
case 'mac_excel2003':
|
||||
$csv_separator = ';';
|
||||
break;
|
||||
case 'mac_excel2008':
|
||||
$csv_separator = ',';
|
||||
break;
|
||||
}
|
||||
|
||||
$csv_enclosed = '"';
|
||||
$csv_escaped = '"';
|
||||
if (isset($GLOBALS['excel_columns'])) {
|
||||
$GLOBALS['csv_columns'] = true;
|
||||
}
|
||||
} else {
|
||||
if (empty($csv_terminated) || mb_strtolower($csv_terminated) === 'auto') {
|
||||
$csv_terminated = $GLOBALS['crlf'];
|
||||
} else {
|
||||
$csv_terminated = str_replace(
|
||||
[
|
||||
'\\r',
|
||||
'\\n',
|
||||
'\\t',
|
||||
],
|
||||
[
|
||||
"\015",
|
||||
"\012",
|
||||
"\011",
|
||||
],
|
||||
$csv_terminated
|
||||
);
|
||||
}
|
||||
|
||||
$csv_separator = str_replace('\\t', "\011", $csv_separator);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export footer
|
||||
*/
|
||||
public function exportFooter(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database header
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $dbAlias Alias of db
|
||||
*/
|
||||
public function exportDBHeader($db, $dbAlias = ''): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database footer
|
||||
*
|
||||
* @param string $db Database name
|
||||
*/
|
||||
public function exportDBFooter($db): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs CREATE DATABASE statement
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $exportType 'server', 'database', 'table'
|
||||
* @param string $dbAlias Aliases of db
|
||||
*/
|
||||
public function exportDBCreate($db, $exportType, $dbAlias = ''): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the content of a table in CSV format
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
* @param string $crlf the end of line sequence
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string $sqlQuery SQL query for obtaining data
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*/
|
||||
public function exportData(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$sqlQuery,
|
||||
array $aliases = []
|
||||
): bool {
|
||||
global $what, $csv_terminated, $csv_separator, $csv_enclosed, $csv_escaped, $dbi;
|
||||
|
||||
$db_alias = $db;
|
||||
$table_alias = $table;
|
||||
$this->initAlias($aliases, $db_alias, $table_alias);
|
||||
|
||||
// Gets the data from the database
|
||||
$result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED);
|
||||
$fields_cnt = $result->numFields();
|
||||
|
||||
// If required, get fields name at the first line
|
||||
if (isset($GLOBALS['csv_columns']) && $GLOBALS['csv_columns']) {
|
||||
$schema_insert = '';
|
||||
foreach ($result->getFieldNames() as $col_as) {
|
||||
if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) {
|
||||
$col_as = $aliases[$db]['tables'][$table]['columns'][$col_as];
|
||||
}
|
||||
|
||||
$col_as = stripslashes($col_as);
|
||||
if ($csv_enclosed == '') {
|
||||
$schema_insert .= $col_as;
|
||||
} else {
|
||||
$schema_insert .= $csv_enclosed
|
||||
. str_replace($csv_enclosed, $csv_escaped . $csv_enclosed, $col_as)
|
||||
. $csv_enclosed;
|
||||
}
|
||||
|
||||
$schema_insert .= $csv_separator;
|
||||
}
|
||||
|
||||
$schema_insert = trim(mb_substr($schema_insert, 0, -1));
|
||||
if (! $this->export->outputHandler($schema_insert . $csv_terminated)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Format the data
|
||||
while ($row = $result->fetchRow()) {
|
||||
$schema_insert = '';
|
||||
for ($j = 0; $j < $fields_cnt; $j++) {
|
||||
if (! isset($row[$j])) {
|
||||
$schema_insert .= $GLOBALS[$what . '_null'];
|
||||
} elseif ($row[$j] == '0' || $row[$j] != '') {
|
||||
// always enclose fields
|
||||
if ($what === 'excel') {
|
||||
$row[$j] = preg_replace("/\015(\012)?/", "\012", $row[$j]);
|
||||
}
|
||||
|
||||
// remove CRLF characters within field
|
||||
if (isset($GLOBALS[$what . '_removeCRLF']) && $GLOBALS[$what . '_removeCRLF']) {
|
||||
$row[$j] = str_replace(
|
||||
[
|
||||
"\r",
|
||||
"\n",
|
||||
],
|
||||
'',
|
||||
$row[$j]
|
||||
);
|
||||
}
|
||||
|
||||
if ($csv_enclosed == '') {
|
||||
$schema_insert .= $row[$j];
|
||||
} else {
|
||||
// also double the escape string if found in the data
|
||||
if ($csv_escaped != $csv_enclosed) {
|
||||
$schema_insert .= $csv_enclosed
|
||||
. str_replace(
|
||||
$csv_enclosed,
|
||||
$csv_escaped . $csv_enclosed,
|
||||
str_replace(
|
||||
$csv_escaped,
|
||||
$csv_escaped . $csv_escaped,
|
||||
$row[$j]
|
||||
)
|
||||
)
|
||||
. $csv_enclosed;
|
||||
} else {
|
||||
// avoid a problem when escape string equals enclose
|
||||
$schema_insert .= $csv_enclosed
|
||||
. str_replace($csv_enclosed, $csv_escaped . $csv_enclosed, $row[$j])
|
||||
. $csv_enclosed;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$schema_insert .= '';
|
||||
}
|
||||
|
||||
if ($j >= $fields_cnt - 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$schema_insert .= $csv_separator;
|
||||
}
|
||||
|
||||
if (! $this->export->outputHandler($schema_insert . $csv_terminated)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs result of raw query in CSV format
|
||||
*
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string|null $db the database where the query is executed
|
||||
* @param string $sqlQuery the rawquery to output
|
||||
* @param string $crlf the end of line sequence
|
||||
*/
|
||||
public function exportRawQuery(string $errorUrl, ?string $db, string $sqlQuery, string $crlf): bool
|
||||
{
|
||||
global $dbi;
|
||||
|
||||
if ($db !== null) {
|
||||
$dbi->selectDb($db);
|
||||
}
|
||||
|
||||
return $this->exportData($db ?? '', '', $crlf, $errorUrl, $sqlQuery);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
/**
|
||||
* Class for exporting CSV dumps of tables for excel
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Plugins\Export;
|
||||
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup;
|
||||
use PhpMyAdmin\Properties\Options\Items\BoolPropertyItem;
|
||||
use PhpMyAdmin\Properties\Options\Items\HiddenPropertyItem;
|
||||
use PhpMyAdmin\Properties\Options\Items\SelectPropertyItem;
|
||||
use PhpMyAdmin\Properties\Options\Items\TextPropertyItem;
|
||||
use PhpMyAdmin\Properties\Plugins\ExportPluginProperties;
|
||||
|
||||
use function __;
|
||||
|
||||
/**
|
||||
* Handles the export for the CSV-Excel format
|
||||
*/
|
||||
class ExportExcel extends ExportCsv
|
||||
{
|
||||
/**
|
||||
* @psalm-return non-empty-lowercase-string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'excel';
|
||||
}
|
||||
|
||||
protected function setProperties(): ExportPluginProperties
|
||||
{
|
||||
$exportPluginProperties = new ExportPluginProperties();
|
||||
$exportPluginProperties->setText('CSV for MS Excel');
|
||||
$exportPluginProperties->setExtension('csv');
|
||||
$exportPluginProperties->setMimeType('text/comma-separated-values');
|
||||
$exportPluginProperties->setOptionsText(__('Options'));
|
||||
|
||||
// create the root group that will be the options field for
|
||||
// $exportPluginProperties
|
||||
// this will be shown as "Format specific options"
|
||||
$exportSpecificOptions = new OptionsPropertyRootGroup('Format Specific Options');
|
||||
|
||||
// general options main group
|
||||
$generalOptions = new OptionsPropertyMainGroup('general_opts');
|
||||
// create primary items and add them to the group
|
||||
$leaf = new TextPropertyItem(
|
||||
'null',
|
||||
__('Replace NULL with:')
|
||||
);
|
||||
$generalOptions->addProperty($leaf);
|
||||
$leaf = new BoolPropertyItem(
|
||||
'removeCRLF',
|
||||
__('Remove carriage return/line feed characters within columns')
|
||||
);
|
||||
$generalOptions->addProperty($leaf);
|
||||
$leaf = new BoolPropertyItem(
|
||||
'columns',
|
||||
__('Put columns names in the first row')
|
||||
);
|
||||
$generalOptions->addProperty($leaf);
|
||||
$leaf = new SelectPropertyItem(
|
||||
'edition',
|
||||
__('Excel edition:')
|
||||
);
|
||||
$leaf->setValues(
|
||||
[
|
||||
'win' => 'Windows',
|
||||
'mac_excel2003' => 'Excel 2003 / Macintosh',
|
||||
'mac_excel2008' => 'Excel 2008 / Macintosh',
|
||||
]
|
||||
);
|
||||
$generalOptions->addProperty($leaf);
|
||||
$leaf = new HiddenPropertyItem('structure_or_data');
|
||||
$generalOptions->addProperty($leaf);
|
||||
// add the main group to the root group
|
||||
$exportSpecificOptions->addProperty($generalOptions);
|
||||
|
||||
// set the options for the export plugin property item
|
||||
$exportPluginProperties->setOptions($exportSpecificOptions);
|
||||
|
||||
return $exportPluginProperties;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,641 @@
|
|||
<?php
|
||||
/**
|
||||
* HTML-Word export code
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Plugins\Export;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Plugins\ExportPlugin;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup;
|
||||
use PhpMyAdmin\Properties\Options\Items\BoolPropertyItem;
|
||||
use PhpMyAdmin\Properties\Options\Items\RadioPropertyItem;
|
||||
use PhpMyAdmin\Properties\Options\Items\TextPropertyItem;
|
||||
use PhpMyAdmin\Properties\Plugins\ExportPluginProperties;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function __;
|
||||
use function htmlspecialchars;
|
||||
use function in_array;
|
||||
use function str_replace;
|
||||
use function stripslashes;
|
||||
|
||||
/**
|
||||
* Handles the export for the HTML-Word format
|
||||
*/
|
||||
class ExportHtmlword extends ExportPlugin
|
||||
{
|
||||
/**
|
||||
* @psalm-return non-empty-lowercase-string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'htmlword';
|
||||
}
|
||||
|
||||
protected function setProperties(): ExportPluginProperties
|
||||
{
|
||||
$exportPluginProperties = new ExportPluginProperties();
|
||||
$exportPluginProperties->setText('Microsoft Word 2000');
|
||||
$exportPluginProperties->setExtension('doc');
|
||||
$exportPluginProperties->setMimeType('application/vnd.ms-word');
|
||||
$exportPluginProperties->setForceFile(true);
|
||||
$exportPluginProperties->setOptionsText(__('Options'));
|
||||
|
||||
// create the root group that will be the options field for
|
||||
// $exportPluginProperties
|
||||
// this will be shown as "Format specific options"
|
||||
$exportSpecificOptions = new OptionsPropertyRootGroup('Format Specific Options');
|
||||
|
||||
// what to dump (structure/data/both)
|
||||
$dumpWhat = new OptionsPropertyMainGroup(
|
||||
'dump_what',
|
||||
__('Dump table')
|
||||
);
|
||||
// create primary items and add them to the group
|
||||
$leaf = new RadioPropertyItem('structure_or_data');
|
||||
$leaf->setValues(
|
||||
[
|
||||
'structure' => __('structure'),
|
||||
'data' => __('data'),
|
||||
'structure_and_data' => __('structure and data'),
|
||||
]
|
||||
);
|
||||
$dumpWhat->addProperty($leaf);
|
||||
// add the main group to the root group
|
||||
$exportSpecificOptions->addProperty($dumpWhat);
|
||||
|
||||
// data options main group
|
||||
$dataOptions = new OptionsPropertyMainGroup(
|
||||
'dump_what',
|
||||
__('Data dump options')
|
||||
);
|
||||
$dataOptions->setForce('structure');
|
||||
// create primary items and add them to the group
|
||||
$leaf = new TextPropertyItem(
|
||||
'null',
|
||||
__('Replace NULL with:')
|
||||
);
|
||||
$dataOptions->addProperty($leaf);
|
||||
$leaf = new BoolPropertyItem(
|
||||
'columns',
|
||||
__('Put columns names in the first row')
|
||||
);
|
||||
$dataOptions->addProperty($leaf);
|
||||
// add the main group to the root group
|
||||
$exportSpecificOptions->addProperty($dataOptions);
|
||||
|
||||
// set the options for the export plugin property item
|
||||
$exportPluginProperties->setOptions($exportSpecificOptions);
|
||||
|
||||
return $exportPluginProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export header
|
||||
*/
|
||||
public function exportHeader(): bool
|
||||
{
|
||||
global $charset;
|
||||
|
||||
return $this->export->outputHandler(
|
||||
'<html xmlns:o="urn:schemas-microsoft-com:office:office"
|
||||
xmlns:x="urn:schemas-microsoft-com:office:word"
|
||||
xmlns="http://www.w3.org/TR/REC-html40">
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'
|
||||
. ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html;charset='
|
||||
. ($charset ?? 'utf-8') . '" />
|
||||
</head>
|
||||
<body>'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export footer
|
||||
*/
|
||||
public function exportFooter(): bool
|
||||
{
|
||||
return $this->export->outputHandler('</body></html>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database header
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $dbAlias Aliases of db
|
||||
*/
|
||||
public function exportDBHeader($db, $dbAlias = ''): bool
|
||||
{
|
||||
if (empty($dbAlias)) {
|
||||
$dbAlias = $db;
|
||||
}
|
||||
|
||||
return $this->export->outputHandler(
|
||||
'<h1>' . __('Database') . ' ' . htmlspecialchars($dbAlias) . '</h1>'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database footer
|
||||
*
|
||||
* @param string $db Database name
|
||||
*/
|
||||
public function exportDBFooter($db): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs CREATE DATABASE statement
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $exportType 'server', 'database', 'table'
|
||||
* @param string $dbAlias Aliases of db
|
||||
*/
|
||||
public function exportDBCreate($db, $exportType, $dbAlias = ''): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the content of a table in HTML-Word format
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
* @param string $crlf the end of line sequence
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string $sqlQuery SQL query for obtaining data
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*/
|
||||
public function exportData(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$sqlQuery,
|
||||
array $aliases = []
|
||||
): bool {
|
||||
global $what, $dbi;
|
||||
|
||||
$db_alias = $db;
|
||||
$table_alias = $table;
|
||||
$this->initAlias($aliases, $db_alias, $table_alias);
|
||||
|
||||
if (
|
||||
! $this->export->outputHandler(
|
||||
'<h2>'
|
||||
. __('Dumping data for table') . ' ' . htmlspecialchars($table_alias)
|
||||
. '</h2>'
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $this->export->outputHandler('<table width="100%" cellspacing="1">')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Gets the data from the database
|
||||
$result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED);
|
||||
$fields_cnt = $result->numFields();
|
||||
|
||||
// If required, get fields name at the first line
|
||||
if (isset($GLOBALS['htmlword_columns'])) {
|
||||
$schema_insert = '<tr class="print-category">';
|
||||
foreach ($result->getFieldNames() as $col_as) {
|
||||
if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) {
|
||||
$col_as = $aliases[$db]['tables'][$table]['columns'][$col_as];
|
||||
}
|
||||
|
||||
$col_as = stripslashes($col_as);
|
||||
$schema_insert .= '<td class="print"><strong>'
|
||||
. htmlspecialchars($col_as)
|
||||
. '</strong></td>';
|
||||
}
|
||||
|
||||
$schema_insert .= '</tr>';
|
||||
if (! $this->export->outputHandler($schema_insert)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Format the data
|
||||
while ($row = $result->fetchRow()) {
|
||||
$schema_insert = '<tr class="print-category">';
|
||||
for ($j = 0; $j < $fields_cnt; $j++) {
|
||||
if (! isset($row[$j])) {
|
||||
$value = $GLOBALS[$what . '_null'];
|
||||
} elseif ($row[$j] == '0' || $row[$j] != '') {
|
||||
$value = $row[$j];
|
||||
} else {
|
||||
$value = '';
|
||||
}
|
||||
|
||||
$schema_insert .= '<td class="print">'
|
||||
. htmlspecialchars((string) $value)
|
||||
. '</td>';
|
||||
}
|
||||
|
||||
$schema_insert .= '</tr>';
|
||||
if (! $this->export->outputHandler($schema_insert)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->export->outputHandler('</table>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a stand-in CREATE definition to resolve view dependencies
|
||||
*
|
||||
* @param string $db the database name
|
||||
* @param string $view the view name
|
||||
* @param string $crlf the end of line sequence
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*
|
||||
* @return string resulting definition
|
||||
*/
|
||||
public function getTableDefStandIn($db, $view, $crlf, $aliases = [])
|
||||
{
|
||||
global $dbi;
|
||||
|
||||
$schema_insert = '<table width="100%" cellspacing="1">'
|
||||
. '<tr class="print-category">'
|
||||
. '<th class="print">'
|
||||
. __('Column')
|
||||
. '</th>'
|
||||
. '<td class="print"><strong>'
|
||||
. __('Type')
|
||||
. '</strong></td>'
|
||||
. '<td class="print"><strong>'
|
||||
. __('Null')
|
||||
. '</strong></td>'
|
||||
. '<td class="print"><strong>'
|
||||
. __('Default')
|
||||
. '</strong></td>'
|
||||
. '</tr>';
|
||||
|
||||
/**
|
||||
* Get the unique keys in the view
|
||||
*/
|
||||
$unique_keys = [];
|
||||
$keys = $dbi->getTableIndexes($db, $view);
|
||||
foreach ($keys as $key) {
|
||||
if ($key['Non_unique'] != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$unique_keys[] = $key['Column_name'];
|
||||
}
|
||||
|
||||
$columns = $dbi->getColumns($db, $view);
|
||||
foreach ($columns as $column) {
|
||||
$col_as = $column['Field'];
|
||||
if (! empty($aliases[$db]['tables'][$view]['columns'][$col_as])) {
|
||||
$col_as = $aliases[$db]['tables'][$view]['columns'][$col_as];
|
||||
}
|
||||
|
||||
$schema_insert .= $this->formatOneColumnDefinition($column, $unique_keys, $col_as);
|
||||
$schema_insert .= '</tr>';
|
||||
}
|
||||
|
||||
$schema_insert .= '</table>';
|
||||
|
||||
return $schema_insert;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns $table's CREATE definition
|
||||
*
|
||||
* @param string $db the database name
|
||||
* @param string $table the table name
|
||||
* @param bool $do_relation whether to include relation comments
|
||||
* @param bool $do_comments whether to include the pmadb-style column
|
||||
* comments as comments in the structure;
|
||||
* this is deprecated but the parameter is
|
||||
* left here because /export calls
|
||||
* PMA_exportStructure() also for other
|
||||
* export types which use this parameter
|
||||
* @param bool $do_mime whether to include mime comments
|
||||
* at the end
|
||||
* @param bool $view whether we're handling a view
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*
|
||||
* @return string resulting schema
|
||||
*/
|
||||
public function getTableDef(
|
||||
$db,
|
||||
$table,
|
||||
$do_relation,
|
||||
$do_comments,
|
||||
$do_mime,
|
||||
$view = false,
|
||||
array $aliases = []
|
||||
) {
|
||||
global $dbi;
|
||||
|
||||
$relationParameters = $this->relation->getRelationParameters();
|
||||
|
||||
$schema_insert = '';
|
||||
|
||||
/**
|
||||
* Gets fields properties
|
||||
*/
|
||||
$dbi->selectDb($db);
|
||||
|
||||
// Check if we can use Relations
|
||||
[$res_rel, $have_rel] = $this->relation->getRelationsAndStatus(
|
||||
$do_relation && $relationParameters->relationFeature !== null,
|
||||
$db,
|
||||
$table
|
||||
);
|
||||
|
||||
/**
|
||||
* Displays the table structure
|
||||
*/
|
||||
$schema_insert .= '<table width="100%" cellspacing="1">';
|
||||
|
||||
$schema_insert .= '<tr class="print-category">';
|
||||
$schema_insert .= '<th class="print">'
|
||||
. __('Column')
|
||||
. '</th>';
|
||||
$schema_insert .= '<td class="print"><strong>'
|
||||
. __('Type')
|
||||
. '</strong></td>';
|
||||
$schema_insert .= '<td class="print"><strong>'
|
||||
. __('Null')
|
||||
. '</strong></td>';
|
||||
$schema_insert .= '<td class="print"><strong>'
|
||||
. __('Default')
|
||||
. '</strong></td>';
|
||||
if ($do_relation && $have_rel) {
|
||||
$schema_insert .= '<td class="print"><strong>'
|
||||
. __('Links to')
|
||||
. '</strong></td>';
|
||||
}
|
||||
|
||||
if ($do_comments) {
|
||||
$schema_insert .= '<td class="print"><strong>'
|
||||
. __('Comments')
|
||||
. '</strong></td>';
|
||||
$comments = $this->relation->getComments($db, $table);
|
||||
}
|
||||
|
||||
if ($do_mime && $relationParameters->browserTransformationFeature !== null) {
|
||||
$schema_insert .= '<td class="print"><strong>'
|
||||
. __('Media type')
|
||||
. '</strong></td>';
|
||||
$mime_map = $this->transformations->getMime($db, $table, true);
|
||||
}
|
||||
|
||||
$schema_insert .= '</tr>';
|
||||
|
||||
$columns = $dbi->getColumns($db, $table);
|
||||
/**
|
||||
* Get the unique keys in the table
|
||||
*/
|
||||
$unique_keys = [];
|
||||
$keys = $dbi->getTableIndexes($db, $table);
|
||||
foreach ($keys as $key) {
|
||||
if ($key['Non_unique'] != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$unique_keys[] = $key['Column_name'];
|
||||
}
|
||||
|
||||
foreach ($columns as $column) {
|
||||
$col_as = $column['Field'];
|
||||
if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) {
|
||||
$col_as = $aliases[$db]['tables'][$table]['columns'][$col_as];
|
||||
}
|
||||
|
||||
$schema_insert .= $this->formatOneColumnDefinition($column, $unique_keys, $col_as);
|
||||
$field_name = $column['Field'];
|
||||
if ($do_relation && $have_rel) {
|
||||
$schema_insert .= '<td class="print">'
|
||||
. htmlspecialchars(
|
||||
$this->getRelationString(
|
||||
$res_rel,
|
||||
$field_name,
|
||||
$db,
|
||||
$aliases
|
||||
)
|
||||
)
|
||||
. '</td>';
|
||||
}
|
||||
|
||||
if ($do_comments && $relationParameters->columnCommentsFeature !== null) {
|
||||
$schema_insert .= '<td class="print">'
|
||||
. (isset($comments[$field_name])
|
||||
? htmlspecialchars($comments[$field_name])
|
||||
: '') . '</td>';
|
||||
}
|
||||
|
||||
if ($do_mime && $relationParameters->browserTransformationFeature !== null) {
|
||||
$schema_insert .= '<td class="print">'
|
||||
. (isset($mime_map[$field_name]) ?
|
||||
htmlspecialchars(
|
||||
str_replace('_', '/', $mime_map[$field_name]['mimetype'])
|
||||
)
|
||||
: '') . '</td>';
|
||||
}
|
||||
|
||||
$schema_insert .= '</tr>';
|
||||
}
|
||||
|
||||
$schema_insert .= '</table>';
|
||||
|
||||
return $schema_insert;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs triggers
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
*
|
||||
* @return string Formatted triggers list
|
||||
*/
|
||||
protected function getTriggers($db, $table)
|
||||
{
|
||||
global $dbi;
|
||||
|
||||
$dump = '<table width="100%" cellspacing="1">';
|
||||
$dump .= '<tr class="print-category">';
|
||||
$dump .= '<th class="print">' . __('Name') . '</th>';
|
||||
$dump .= '<td class="print"><strong>' . __('Time') . '</strong></td>';
|
||||
$dump .= '<td class="print"><strong>' . __('Event') . '</strong></td>';
|
||||
$dump .= '<td class="print"><strong>' . __('Definition') . '</strong></td>';
|
||||
$dump .= '</tr>';
|
||||
|
||||
$triggers = $dbi->getTriggers($db, $table);
|
||||
|
||||
foreach ($triggers as $trigger) {
|
||||
$dump .= '<tr class="print-category">';
|
||||
$dump .= '<td class="print">'
|
||||
. htmlspecialchars($trigger['name'])
|
||||
. '</td>'
|
||||
. '<td class="print">'
|
||||
. htmlspecialchars($trigger['action_timing'])
|
||||
. '</td>'
|
||||
. '<td class="print">'
|
||||
. htmlspecialchars($trigger['event_manipulation'])
|
||||
. '</td>'
|
||||
. '<td class="print">'
|
||||
. htmlspecialchars($trigger['definition'])
|
||||
. '</td>'
|
||||
. '</tr>';
|
||||
}
|
||||
|
||||
$dump .= '</table>';
|
||||
|
||||
return $dump;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs table's structure
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
* @param string $crlf the end of line sequence
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string $exportMode 'create_table', 'triggers', 'create_view',
|
||||
* 'stand_in'
|
||||
* @param string $exportType 'server', 'database', 'table'
|
||||
* @param bool $do_relation whether to include relation comments
|
||||
* @param bool $do_comments whether to include the pmadb-style column
|
||||
* comments as comments in the structure;
|
||||
* this is deprecated but the parameter is
|
||||
* left here because /export calls
|
||||
* PMA_exportStructure() also for other
|
||||
* export types which use this parameter
|
||||
* @param bool $do_mime whether to include mime comments
|
||||
* @param bool $dates whether to include creation/update/check dates
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*/
|
||||
public function exportStructure(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$exportMode,
|
||||
$exportType,
|
||||
$do_relation = false,
|
||||
$do_comments = false,
|
||||
$do_mime = false,
|
||||
$dates = false,
|
||||
array $aliases = []
|
||||
): bool {
|
||||
global $dbi;
|
||||
|
||||
$db_alias = $db;
|
||||
$table_alias = $table;
|
||||
$this->initAlias($aliases, $db_alias, $table_alias);
|
||||
|
||||
$dump = '';
|
||||
|
||||
switch ($exportMode) {
|
||||
case 'create_table':
|
||||
$dump .= '<h2>'
|
||||
. __('Table structure for table') . ' '
|
||||
. htmlspecialchars($table_alias)
|
||||
. '</h2>';
|
||||
$dump .= $this->getTableDef($db, $table, $do_relation, $do_comments, $do_mime, false, $aliases);
|
||||
break;
|
||||
case 'triggers':
|
||||
$dump = '';
|
||||
$triggers = $dbi->getTriggers($db, $table);
|
||||
if ($triggers) {
|
||||
$dump .= '<h2>'
|
||||
. __('Triggers') . ' ' . htmlspecialchars($table_alias)
|
||||
. '</h2>';
|
||||
$dump .= $this->getTriggers($db, $table);
|
||||
}
|
||||
|
||||
break;
|
||||
case 'create_view':
|
||||
$dump .= '<h2>'
|
||||
. __('Structure for view') . ' ' . htmlspecialchars($table_alias)
|
||||
. '</h2>';
|
||||
$dump .= $this->getTableDef($db, $table, $do_relation, $do_comments, $do_mime, true, $aliases);
|
||||
break;
|
||||
case 'stand_in':
|
||||
$dump .= '<h2>'
|
||||
. __('Stand-in structure for view') . ' '
|
||||
. htmlspecialchars($table_alias)
|
||||
. '</h2>';
|
||||
// export a stand-in definition to resolve view dependencies
|
||||
$dump .= $this->getTableDefStandIn($db, $table, $crlf, $aliases);
|
||||
}
|
||||
|
||||
return $this->export->outputHandler($dump);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the definition for one column
|
||||
*
|
||||
* @param array $column info about this column
|
||||
* @param array $unique_keys unique keys of the table
|
||||
* @param string $col_alias Column Alias
|
||||
*
|
||||
* @return string Formatted column definition
|
||||
*/
|
||||
protected function formatOneColumnDefinition(
|
||||
array $column,
|
||||
array $unique_keys,
|
||||
$col_alias = ''
|
||||
) {
|
||||
if (empty($col_alias)) {
|
||||
$col_alias = $column['Field'];
|
||||
}
|
||||
|
||||
$definition = '<tr class="print-category">';
|
||||
|
||||
$extracted_columnspec = Util::extractColumnSpec($column['Type']);
|
||||
|
||||
$type = htmlspecialchars($extracted_columnspec['print_type']);
|
||||
if (empty($type)) {
|
||||
$type = ' ';
|
||||
}
|
||||
|
||||
if (! isset($column['Default'])) {
|
||||
if ($column['Null'] !== 'NO') {
|
||||
$column['Default'] = 'NULL';
|
||||
}
|
||||
}
|
||||
|
||||
$fmt_pre = '';
|
||||
$fmt_post = '';
|
||||
if (in_array($column['Field'], $unique_keys)) {
|
||||
$fmt_pre = '<strong>' . $fmt_pre;
|
||||
$fmt_post .= '</strong>';
|
||||
}
|
||||
|
||||
if ($column['Key'] === 'PRI') {
|
||||
$fmt_pre = '<em>' . $fmt_pre;
|
||||
$fmt_post .= '</em>';
|
||||
}
|
||||
|
||||
$definition .= '<td class="print">' . $fmt_pre
|
||||
. htmlspecialchars($col_alias) . $fmt_post . '</td>';
|
||||
$definition .= '<td class="print">' . htmlspecialchars($type) . '</td>';
|
||||
$definition .= '<td class="print">'
|
||||
. ($column['Null'] == '' || $column['Null'] === 'NO'
|
||||
? __('No')
|
||||
: __('Yes'))
|
||||
. '</td>';
|
||||
$definition .= '<td class="print">'
|
||||
. htmlspecialchars($column['Default'] ?? '')
|
||||
. '</td>';
|
||||
|
||||
return $definition;
|
||||
}
|
||||
}
|
346
admin/phpMyAdmin/libraries/classes/Plugins/Export/ExportJson.php
Normal file
346
admin/phpMyAdmin/libraries/classes/Plugins/Export/ExportJson.php
Normal file
|
@ -0,0 +1,346 @@
|
|||
<?php
|
||||
/**
|
||||
* Set of methods used to build dumps of tables as JSON
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Plugins\Export;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\FieldMetadata;
|
||||
use PhpMyAdmin\Plugins\ExportPlugin;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup;
|
||||
use PhpMyAdmin\Properties\Options\Items\BoolPropertyItem;
|
||||
use PhpMyAdmin\Properties\Options\Items\HiddenPropertyItem;
|
||||
use PhpMyAdmin\Properties\Plugins\ExportPluginProperties;
|
||||
use PhpMyAdmin\Version;
|
||||
|
||||
use function __;
|
||||
use function bin2hex;
|
||||
use function explode;
|
||||
use function json_encode;
|
||||
use function stripslashes;
|
||||
|
||||
use const JSON_PRETTY_PRINT;
|
||||
use const JSON_UNESCAPED_UNICODE;
|
||||
|
||||
/**
|
||||
* Handles the export for the JSON format
|
||||
*/
|
||||
class ExportJson extends ExportPlugin
|
||||
{
|
||||
/** @var bool */
|
||||
private $first = true;
|
||||
|
||||
/**
|
||||
* @psalm-return non-empty-lowercase-string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'json';
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the data into JSON
|
||||
*
|
||||
* @param mixed $data Data to encode
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public function encode($data)
|
||||
{
|
||||
$options = 0;
|
||||
if (isset($GLOBALS['json_pretty_print']) && $GLOBALS['json_pretty_print']) {
|
||||
$options |= JSON_PRETTY_PRINT;
|
||||
}
|
||||
|
||||
if (isset($GLOBALS['json_unicode']) && $GLOBALS['json_unicode']) {
|
||||
$options |= JSON_UNESCAPED_UNICODE;
|
||||
}
|
||||
|
||||
return json_encode($data, $options);
|
||||
}
|
||||
|
||||
protected function setProperties(): ExportPluginProperties
|
||||
{
|
||||
$exportPluginProperties = new ExportPluginProperties();
|
||||
$exportPluginProperties->setText('JSON');
|
||||
$exportPluginProperties->setExtension('json');
|
||||
$exportPluginProperties->setMimeType('text/plain');
|
||||
$exportPluginProperties->setOptionsText(__('Options'));
|
||||
|
||||
// create the root group that will be the options field for
|
||||
// $exportPluginProperties
|
||||
// this will be shown as "Format specific options"
|
||||
$exportSpecificOptions = new OptionsPropertyRootGroup('Format Specific Options');
|
||||
|
||||
// general options main group
|
||||
$generalOptions = new OptionsPropertyMainGroup('general_opts');
|
||||
// create primary items and add them to the group
|
||||
$leaf = new HiddenPropertyItem('structure_or_data');
|
||||
$generalOptions->addProperty($leaf);
|
||||
|
||||
$leaf = new BoolPropertyItem(
|
||||
'pretty_print',
|
||||
__('Output pretty-printed JSON (Use human-readable formatting)')
|
||||
);
|
||||
$generalOptions->addProperty($leaf);
|
||||
|
||||
$leaf = new BoolPropertyItem(
|
||||
'unicode',
|
||||
__('Output unicode characters unescaped')
|
||||
);
|
||||
$generalOptions->addProperty($leaf);
|
||||
|
||||
// add the main group to the root group
|
||||
$exportSpecificOptions->addProperty($generalOptions);
|
||||
|
||||
// set the options for the export plugin property item
|
||||
$exportPluginProperties->setOptions($exportSpecificOptions);
|
||||
|
||||
return $exportPluginProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export header
|
||||
*/
|
||||
public function exportHeader(): bool
|
||||
{
|
||||
global $crlf;
|
||||
|
||||
$data = $this->encode([
|
||||
'type' => 'header',
|
||||
'version' => Version::VERSION,
|
||||
'comment' => 'Export to JSON plugin for PHPMyAdmin',
|
||||
]);
|
||||
if ($data === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->export->outputHandler('[' . $crlf . $data . ',' . $crlf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export footer
|
||||
*/
|
||||
public function exportFooter(): bool
|
||||
{
|
||||
global $crlf;
|
||||
|
||||
return $this->export->outputHandler(']' . $crlf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database header
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $dbAlias Aliases of db
|
||||
*/
|
||||
public function exportDBHeader($db, $dbAlias = ''): bool
|
||||
{
|
||||
global $crlf;
|
||||
|
||||
if (empty($dbAlias)) {
|
||||
$dbAlias = $db;
|
||||
}
|
||||
|
||||
$data = $this->encode(['type' => 'database', 'name' => $dbAlias]);
|
||||
if ($data === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->export->outputHandler($data . ',' . $crlf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database footer
|
||||
*
|
||||
* @param string $db Database name
|
||||
*/
|
||||
public function exportDBFooter($db): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs CREATE DATABASE statement
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $exportType 'server', 'database', 'table'
|
||||
* @param string $dbAlias Aliases of db
|
||||
*/
|
||||
public function exportDBCreate($db, $exportType, $dbAlias = ''): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the content of a table in JSON format
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
* @param string $crlf the end of line sequence
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string $sqlQuery SQL query for obtaining data
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*/
|
||||
public function exportData(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$sqlQuery,
|
||||
array $aliases = []
|
||||
): bool {
|
||||
global $dbi;
|
||||
|
||||
$db_alias = $db;
|
||||
$table_alias = $table;
|
||||
$this->initAlias($aliases, $db_alias, $table_alias);
|
||||
|
||||
if (! $this->first) {
|
||||
if (! $this->export->outputHandler(',')) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$this->first = false;
|
||||
}
|
||||
|
||||
$buffer = $this->encode([
|
||||
'type' => 'table',
|
||||
'name' => $table_alias,
|
||||
'database' => $db_alias,
|
||||
'data' => '@@DATA@@',
|
||||
]);
|
||||
if ($buffer === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->doExportForQuery($dbi, $sqlQuery, $buffer, $crlf, $aliases, $db, $table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Export to JSON
|
||||
*
|
||||
* @phpstan-param array{
|
||||
* string: array{
|
||||
* 'tables': array{
|
||||
* string: array{
|
||||
* 'columns': array{string: string}
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }|array|null $aliases
|
||||
*/
|
||||
protected function doExportForQuery(
|
||||
DatabaseInterface $dbi,
|
||||
string $sqlQuery,
|
||||
string $buffer,
|
||||
string $crlf,
|
||||
?array $aliases,
|
||||
?string $db,
|
||||
?string $table
|
||||
): bool {
|
||||
[$header, $footer] = explode('"@@DATA@@"', $buffer);
|
||||
|
||||
if (! $this->export->outputHandler($header . $crlf . '[' . $crlf)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED);
|
||||
$columns_cnt = $result->numFields();
|
||||
$fieldsMeta = $dbi->getFieldsMeta($result);
|
||||
|
||||
$columns = [];
|
||||
foreach ($fieldsMeta as $i => $field) {
|
||||
$col_as = $field->name;
|
||||
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);
|
||||
}
|
||||
|
||||
$record_cnt = 0;
|
||||
while ($record = $result->fetchRow()) {
|
||||
$record_cnt++;
|
||||
|
||||
// Output table name as comment if this is the first record of the table
|
||||
if ($record_cnt > 1) {
|
||||
if (! $this->export->outputHandler(',' . $crlf)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$data = [];
|
||||
|
||||
for ($i = 0; $i < $columns_cnt; $i++) {
|
||||
// 63 is the binary charset, see: https://dev.mysql.com/doc/internals/en/charsets.html
|
||||
$isBlobAndIsBinaryCharset = isset($fieldsMeta[$i])
|
||||
&& $fieldsMeta[$i]->isType(FieldMetadata::TYPE_BLOB)
|
||||
&& $fieldsMeta[$i]->charsetnr === 63;
|
||||
// This can occur for binary fields
|
||||
$isBinaryString = isset($fieldsMeta[$i])
|
||||
&& $fieldsMeta[$i]->isType(FieldMetadata::TYPE_STRING)
|
||||
&& $fieldsMeta[$i]->charsetnr === 63;
|
||||
if (
|
||||
isset($fieldsMeta[$i]) &&
|
||||
(
|
||||
$fieldsMeta[$i]->isMappedTypeGeometry ||
|
||||
$isBlobAndIsBinaryCharset ||
|
||||
$isBinaryString
|
||||
) &&
|
||||
$record[$i] !== null
|
||||
) {
|
||||
// export GIS and blob types as hex
|
||||
$record[$i] = '0x' . bin2hex($record[$i]);
|
||||
}
|
||||
|
||||
$data[$columns[$i]] = $record[$i];
|
||||
}
|
||||
|
||||
$encodedData = $this->encode($data);
|
||||
if (! $encodedData) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $this->export->outputHandler($encodedData)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->export->outputHandler($crlf . ']' . $crlf . $footer . $crlf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs result raw query in JSON format
|
||||
*
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string|null $db the database where the query is executed
|
||||
* @param string $sqlQuery the rawquery to output
|
||||
* @param string $crlf the end of line sequence
|
||||
*/
|
||||
public function exportRawQuery(string $errorUrl, ?string $db, string $sqlQuery, string $crlf): bool
|
||||
{
|
||||
global $dbi;
|
||||
|
||||
$buffer = $this->encode([
|
||||
'type' => 'raw',
|
||||
'data' => '@@DATA@@',
|
||||
]);
|
||||
if ($buffer === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($db !== null) {
|
||||
$dbi->selectDb($db);
|
||||
}
|
||||
|
||||
return $this->doExportForQuery($dbi, $sqlQuery, $buffer, $crlf, null, $db, null);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,712 @@
|
|||
<?php
|
||||
/**
|
||||
* Set of methods used to build dumps of tables as Latex
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Plugins\Export;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Plugins\ExportPlugin;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup;
|
||||
use PhpMyAdmin\Properties\Options\Items\BoolPropertyItem;
|
||||
use PhpMyAdmin\Properties\Options\Items\RadioPropertyItem;
|
||||
use PhpMyAdmin\Properties\Options\Items\TextPropertyItem;
|
||||
use PhpMyAdmin\Properties\Plugins\ExportPluginProperties;
|
||||
use PhpMyAdmin\Util;
|
||||
use PhpMyAdmin\Version;
|
||||
|
||||
use function __;
|
||||
use function count;
|
||||
use function in_array;
|
||||
use function mb_strpos;
|
||||
use function mb_substr;
|
||||
use function str_replace;
|
||||
use function stripslashes;
|
||||
|
||||
use const PHP_VERSION;
|
||||
|
||||
/**
|
||||
* Handles the export for the Latex format
|
||||
*/
|
||||
class ExportLatex extends ExportPlugin
|
||||
{
|
||||
/**
|
||||
* @psalm-return non-empty-lowercase-string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'latex';
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the local variables that are used for export Latex.
|
||||
*/
|
||||
protected function init(): void
|
||||
{
|
||||
/* Messages used in default captions */
|
||||
$GLOBALS['strLatexContent'] = __('Content of table @TABLE@');
|
||||
$GLOBALS['strLatexContinued'] = __('(continued)');
|
||||
$GLOBALS['strLatexStructure'] = __('Structure of table @TABLE@');
|
||||
}
|
||||
|
||||
protected function setProperties(): ExportPluginProperties
|
||||
{
|
||||
global $plugin_param;
|
||||
$hide_structure = false;
|
||||
if ($plugin_param['export_type'] === 'table' && ! $plugin_param['single_table']) {
|
||||
$hide_structure = true;
|
||||
}
|
||||
|
||||
$exportPluginProperties = new ExportPluginProperties();
|
||||
$exportPluginProperties->setText('LaTeX');
|
||||
$exportPluginProperties->setExtension('tex');
|
||||
$exportPluginProperties->setMimeType('application/x-tex');
|
||||
$exportPluginProperties->setOptionsText(__('Options'));
|
||||
|
||||
// create the root group that will be the options field for
|
||||
// $exportPluginProperties
|
||||
// this will be shown as "Format specific options"
|
||||
$exportSpecificOptions = new OptionsPropertyRootGroup('Format Specific Options');
|
||||
|
||||
// general options main group
|
||||
$generalOptions = new OptionsPropertyMainGroup('general_opts');
|
||||
// create primary items and add them to the group
|
||||
$leaf = new BoolPropertyItem(
|
||||
'caption',
|
||||
__('Include table caption')
|
||||
);
|
||||
$generalOptions->addProperty($leaf);
|
||||
// add the main group to the root group
|
||||
$exportSpecificOptions->addProperty($generalOptions);
|
||||
|
||||
// what to dump (structure/data/both) main group
|
||||
$dumpWhat = new OptionsPropertyMainGroup(
|
||||
'dump_what',
|
||||
__('Dump table')
|
||||
);
|
||||
// create primary items and add them to the group
|
||||
$leaf = new RadioPropertyItem('structure_or_data');
|
||||
$leaf->setValues(
|
||||
[
|
||||
'structure' => __('structure'),
|
||||
'data' => __('data'),
|
||||
'structure_and_data' => __('structure and data'),
|
||||
]
|
||||
);
|
||||
$dumpWhat->addProperty($leaf);
|
||||
// add the main group to the root group
|
||||
$exportSpecificOptions->addProperty($dumpWhat);
|
||||
|
||||
// structure options main group
|
||||
if (! $hide_structure) {
|
||||
$structureOptions = new OptionsPropertyMainGroup(
|
||||
'structure',
|
||||
__('Object creation options')
|
||||
);
|
||||
$structureOptions->setForce('data');
|
||||
// create primary items and add them to the group
|
||||
$leaf = new TextPropertyItem(
|
||||
'structure_caption',
|
||||
__('Table caption:')
|
||||
);
|
||||
$leaf->setDoc('faq6-27');
|
||||
$structureOptions->addProperty($leaf);
|
||||
$leaf = new TextPropertyItem(
|
||||
'structure_continued_caption',
|
||||
__('Table caption (continued):')
|
||||
);
|
||||
$leaf->setDoc('faq6-27');
|
||||
$structureOptions->addProperty($leaf);
|
||||
$leaf = new TextPropertyItem(
|
||||
'structure_label',
|
||||
__('Label key:')
|
||||
);
|
||||
$leaf->setDoc('faq6-27');
|
||||
$structureOptions->addProperty($leaf);
|
||||
$relationParameters = $this->relation->getRelationParameters();
|
||||
if ($relationParameters->relationFeature !== null) {
|
||||
$leaf = new BoolPropertyItem(
|
||||
'relation',
|
||||
__('Display foreign key relationships')
|
||||
);
|
||||
$structureOptions->addProperty($leaf);
|
||||
}
|
||||
|
||||
$leaf = new BoolPropertyItem(
|
||||
'comments',
|
||||
__('Display comments')
|
||||
);
|
||||
$structureOptions->addProperty($leaf);
|
||||
if ($relationParameters->browserTransformationFeature !== null) {
|
||||
$leaf = new BoolPropertyItem(
|
||||
'mime',
|
||||
__('Display media types')
|
||||
);
|
||||
$structureOptions->addProperty($leaf);
|
||||
}
|
||||
|
||||
// add the main group to the root group
|
||||
$exportSpecificOptions->addProperty($structureOptions);
|
||||
}
|
||||
|
||||
// data options main group
|
||||
$dataOptions = new OptionsPropertyMainGroup(
|
||||
'data',
|
||||
__('Data dump options')
|
||||
);
|
||||
$dataOptions->setForce('structure');
|
||||
// create primary items and add them to the group
|
||||
$leaf = new BoolPropertyItem(
|
||||
'columns',
|
||||
__('Put columns names in the first row:')
|
||||
);
|
||||
$dataOptions->addProperty($leaf);
|
||||
$leaf = new TextPropertyItem(
|
||||
'data_caption',
|
||||
__('Table caption:')
|
||||
);
|
||||
$leaf->setDoc('faq6-27');
|
||||
$dataOptions->addProperty($leaf);
|
||||
$leaf = new TextPropertyItem(
|
||||
'data_continued_caption',
|
||||
__('Table caption (continued):')
|
||||
);
|
||||
$leaf->setDoc('faq6-27');
|
||||
$dataOptions->addProperty($leaf);
|
||||
$leaf = new TextPropertyItem(
|
||||
'data_label',
|
||||
__('Label key:')
|
||||
);
|
||||
$leaf->setDoc('faq6-27');
|
||||
$dataOptions->addProperty($leaf);
|
||||
$leaf = new TextPropertyItem(
|
||||
'null',
|
||||
__('Replace NULL with:')
|
||||
);
|
||||
$dataOptions->addProperty($leaf);
|
||||
// add the main group to the root group
|
||||
$exportSpecificOptions->addProperty($dataOptions);
|
||||
|
||||
// set the options for the export plugin property item
|
||||
$exportPluginProperties->setOptions($exportSpecificOptions);
|
||||
|
||||
return $exportPluginProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export header
|
||||
*/
|
||||
public function exportHeader(): bool
|
||||
{
|
||||
global $crlf, $cfg, $dbi;
|
||||
|
||||
$head = '% phpMyAdmin LaTeX Dump' . $crlf
|
||||
. '% version ' . Version::VERSION . $crlf
|
||||
. '% https://www.phpmyadmin.net/' . $crlf
|
||||
. '%' . $crlf
|
||||
. '% ' . __('Host:') . ' ' . $cfg['Server']['host'];
|
||||
if (! empty($cfg['Server']['port'])) {
|
||||
$head .= ':' . $cfg['Server']['port'];
|
||||
}
|
||||
|
||||
$head .= $crlf
|
||||
. '% ' . __('Generation Time:') . ' '
|
||||
. Util::localisedDate() . $crlf
|
||||
. '% ' . __('Server version:') . ' ' . $dbi->getVersionString() . $crlf
|
||||
. '% ' . __('PHP Version:') . ' ' . PHP_VERSION . $crlf;
|
||||
|
||||
return $this->export->outputHandler($head);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export footer
|
||||
*/
|
||||
public function exportFooter(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database header
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $dbAlias Aliases of db
|
||||
*/
|
||||
public function exportDBHeader($db, $dbAlias = ''): bool
|
||||
{
|
||||
if (empty($dbAlias)) {
|
||||
$dbAlias = $db;
|
||||
}
|
||||
|
||||
global $crlf;
|
||||
$head = '% ' . $crlf
|
||||
. '% ' . __('Database:') . ' \'' . $dbAlias . '\'' . $crlf
|
||||
. '% ' . $crlf;
|
||||
|
||||
return $this->export->outputHandler($head);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database footer
|
||||
*
|
||||
* @param string $db Database name
|
||||
*/
|
||||
public function exportDBFooter($db): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs CREATE DATABASE statement
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $exportType 'server', 'database', 'table'
|
||||
* @param string $dbAlias Aliases of db
|
||||
*/
|
||||
public function exportDBCreate($db, $exportType, $dbAlias = ''): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the content of a table in JSON format
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
* @param string $crlf the end of line sequence
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string $sqlQuery SQL query for obtaining data
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*/
|
||||
public function exportData(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$sqlQuery,
|
||||
array $aliases = []
|
||||
): bool {
|
||||
global $dbi;
|
||||
|
||||
$db_alias = $db;
|
||||
$table_alias = $table;
|
||||
$this->initAlias($aliases, $db_alias, $table_alias);
|
||||
|
||||
$result = $dbi->tryQuery($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED);
|
||||
|
||||
$columns_cnt = $result->numFields();
|
||||
$columns = [];
|
||||
$columns_alias = [];
|
||||
foreach ($result->getFieldNames() as $i => $col_as) {
|
||||
$columns[$i] = $col_as;
|
||||
if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) {
|
||||
$col_as = $aliases[$db]['tables'][$table]['columns'][$col_as];
|
||||
}
|
||||
|
||||
$columns_alias[$i] = $col_as;
|
||||
}
|
||||
|
||||
$buffer = $crlf . '%' . $crlf . '% ' . __('Data:') . ' ' . $table_alias
|
||||
. $crlf . '%' . $crlf . ' \\begin{longtable}{|';
|
||||
|
||||
for ($index = 0; $index < $columns_cnt; $index++) {
|
||||
$buffer .= 'l|';
|
||||
}
|
||||
|
||||
$buffer .= '} ' . $crlf;
|
||||
|
||||
$buffer .= ' \\hline \\endhead \\hline \\endfoot \\hline ' . $crlf;
|
||||
if (isset($GLOBALS['latex_caption'])) {
|
||||
$buffer .= ' \\caption{'
|
||||
. Util::expandUserString(
|
||||
$GLOBALS['latex_data_caption'],
|
||||
[
|
||||
'texEscape',
|
||||
static::class,
|
||||
],
|
||||
[
|
||||
'table' => $table_alias,
|
||||
'database' => $db_alias,
|
||||
]
|
||||
)
|
||||
. '} \\label{'
|
||||
. Util::expandUserString(
|
||||
$GLOBALS['latex_data_label'],
|
||||
null,
|
||||
[
|
||||
'table' => $table_alias,
|
||||
'database' => $db_alias,
|
||||
]
|
||||
)
|
||||
. '} \\\\';
|
||||
}
|
||||
|
||||
if (! $this->export->outputHandler($buffer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// show column names
|
||||
if (isset($GLOBALS['latex_columns'])) {
|
||||
$buffer = '\\hline ';
|
||||
for ($i = 0; $i < $columns_cnt; $i++) {
|
||||
$buffer .= '\\multicolumn{1}{|c|}{\\textbf{'
|
||||
. self::texEscape(stripslashes($columns_alias[$i])) . '}} & ';
|
||||
}
|
||||
|
||||
$buffer = mb_substr($buffer, 0, -2) . '\\\\ \\hline \hline ';
|
||||
if (! $this->export->outputHandler($buffer . ' \\endfirsthead ' . $crlf)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($GLOBALS['latex_caption'])) {
|
||||
if (
|
||||
! $this->export->outputHandler(
|
||||
'\\caption{'
|
||||
. Util::expandUserString(
|
||||
$GLOBALS['latex_data_continued_caption'],
|
||||
[
|
||||
'texEscape',
|
||||
static::class,
|
||||
],
|
||||
[
|
||||
'table' => $table_alias,
|
||||
'database' => $db_alias,
|
||||
]
|
||||
)
|
||||
. '} \\\\ '
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (! $this->export->outputHandler($buffer . '\\endhead \\endfoot' . $crlf)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (! $this->export->outputHandler('\\\\ \hline')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// print the whole table
|
||||
while ($record = $result->fetchAssoc()) {
|
||||
$buffer = '';
|
||||
// print each row
|
||||
for ($i = 0; $i < $columns_cnt; $i++) {
|
||||
if ($record[$columns[$i]] !== null && isset($record[$columns[$i]])) {
|
||||
$column_value = self::texEscape(
|
||||
stripslashes($record[$columns[$i]])
|
||||
);
|
||||
} else {
|
||||
$column_value = $GLOBALS['latex_null'];
|
||||
}
|
||||
|
||||
// last column ... no need for & character
|
||||
if ($i == $columns_cnt - 1) {
|
||||
$buffer .= $column_value;
|
||||
} else {
|
||||
$buffer .= $column_value . ' & ';
|
||||
}
|
||||
}
|
||||
|
||||
$buffer .= ' \\\\ \\hline ' . $crlf;
|
||||
if (! $this->export->outputHandler($buffer)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$buffer = ' \\end{longtable}' . $crlf;
|
||||
|
||||
return $this->export->outputHandler($buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs result raw query
|
||||
*
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string|null $db the database where the query is executed
|
||||
* @param string $sqlQuery the rawquery to output
|
||||
* @param string $crlf the end of line sequence
|
||||
*/
|
||||
public function exportRawQuery(string $errorUrl, ?string $db, string $sqlQuery, string $crlf): bool
|
||||
{
|
||||
global $dbi;
|
||||
|
||||
if ($db !== null) {
|
||||
$dbi->selectDb($db);
|
||||
}
|
||||
|
||||
return $this->exportData($db ?? '', '', $crlf, $errorUrl, $sqlQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs table's structure
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
* @param string $crlf the end of line sequence
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string $exportMode 'create_table', 'triggers', 'create_view',
|
||||
* 'stand_in'
|
||||
* @param string $exportType 'server', 'database', 'table'
|
||||
* @param bool $do_relation whether to include relation comments
|
||||
* @param bool $do_comments whether to include the pmadb-style column
|
||||
* comments as comments in the structure;
|
||||
* this is deprecated but the parameter is
|
||||
* left here because /export calls
|
||||
* exportStructure() also for other
|
||||
* export types which use this parameter
|
||||
* @param bool $do_mime whether to include mime comments
|
||||
* @param bool $dates whether to include creation/update/check dates
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*/
|
||||
public function exportStructure(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$exportMode,
|
||||
$exportType,
|
||||
$do_relation = false,
|
||||
$do_comments = false,
|
||||
$do_mime = false,
|
||||
$dates = false,
|
||||
array $aliases = []
|
||||
): bool {
|
||||
global $dbi;
|
||||
|
||||
$db_alias = $db;
|
||||
$table_alias = $table;
|
||||
$this->initAlias($aliases, $db_alias, $table_alias);
|
||||
|
||||
$relationParameters = $this->relation->getRelationParameters();
|
||||
|
||||
/* We do not export triggers */
|
||||
if ($exportMode === 'triggers') {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the unique keys in the table
|
||||
*/
|
||||
$unique_keys = [];
|
||||
$keys = $dbi->getTableIndexes($db, $table);
|
||||
foreach ($keys as $key) {
|
||||
if ($key['Non_unique'] != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$unique_keys[] = $key['Column_name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets fields properties
|
||||
*/
|
||||
$dbi->selectDb($db);
|
||||
|
||||
// Check if we can use Relations
|
||||
[$res_rel, $have_rel] = $this->relation->getRelationsAndStatus(
|
||||
$do_relation && $relationParameters->relationFeature !== null,
|
||||
$db,
|
||||
$table
|
||||
);
|
||||
/**
|
||||
* Displays the table structure
|
||||
*/
|
||||
$buffer = $crlf . '%' . $crlf . '% ' . __('Structure:') . ' '
|
||||
. $table_alias . $crlf . '%' . $crlf . ' \\begin{longtable}{';
|
||||
if (! $this->export->outputHandler($buffer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$alignment = '|l|c|c|c|';
|
||||
if ($do_relation && $have_rel) {
|
||||
$alignment .= 'l|';
|
||||
}
|
||||
|
||||
if ($do_comments) {
|
||||
$alignment .= 'l|';
|
||||
}
|
||||
|
||||
if ($do_mime && $relationParameters->browserTransformationFeature !== null) {
|
||||
$alignment .= 'l|';
|
||||
}
|
||||
|
||||
$buffer = $alignment . '} ' . $crlf;
|
||||
|
||||
$header = ' \\hline ';
|
||||
$header .= '\\multicolumn{1}{|c|}{\\textbf{' . __('Column')
|
||||
. '}} & \\multicolumn{1}{|c|}{\\textbf{' . __('Type')
|
||||
. '}} & \\multicolumn{1}{|c|}{\\textbf{' . __('Null')
|
||||
. '}} & \\multicolumn{1}{|c|}{\\textbf{' . __('Default') . '}}';
|
||||
if ($do_relation && $have_rel) {
|
||||
$header .= ' & \\multicolumn{1}{|c|}{\\textbf{' . __('Links to') . '}}';
|
||||
}
|
||||
|
||||
if ($do_comments) {
|
||||
$header .= ' & \\multicolumn{1}{|c|}{\\textbf{' . __('Comments') . '}}';
|
||||
$comments = $this->relation->getComments($db, $table);
|
||||
}
|
||||
|
||||
if ($do_mime && $relationParameters->browserTransformationFeature !== null) {
|
||||
$header .= ' & \\multicolumn{1}{|c|}{\\textbf{MIME}}';
|
||||
$mime_map = $this->transformations->getMime($db, $table, true);
|
||||
}
|
||||
|
||||
// Table caption for first page and label
|
||||
if (isset($GLOBALS['latex_caption'])) {
|
||||
$buffer .= ' \\caption{'
|
||||
. Util::expandUserString(
|
||||
$GLOBALS['latex_structure_caption'],
|
||||
[
|
||||
'texEscape',
|
||||
static::class,
|
||||
],
|
||||
[
|
||||
'table' => $table_alias,
|
||||
'database' => $db_alias,
|
||||
]
|
||||
)
|
||||
. '} \\label{'
|
||||
. Util::expandUserString(
|
||||
$GLOBALS['latex_structure_label'],
|
||||
null,
|
||||
[
|
||||
'table' => $table_alias,
|
||||
'database' => $db_alias,
|
||||
]
|
||||
)
|
||||
. '} \\\\' . $crlf;
|
||||
}
|
||||
|
||||
$buffer .= $header . ' \\\\ \\hline \\hline' . $crlf
|
||||
. '\\endfirsthead' . $crlf;
|
||||
// Table caption on next pages
|
||||
if (isset($GLOBALS['latex_caption'])) {
|
||||
$buffer .= ' \\caption{'
|
||||
. Util::expandUserString(
|
||||
$GLOBALS['latex_structure_continued_caption'],
|
||||
[
|
||||
'texEscape',
|
||||
static::class,
|
||||
],
|
||||
[
|
||||
'table' => $table_alias,
|
||||
'database' => $db_alias,
|
||||
]
|
||||
)
|
||||
. '} \\\\ ' . $crlf;
|
||||
}
|
||||
|
||||
$buffer .= $header . ' \\\\ \\hline \\hline \\endhead \\endfoot ' . $crlf;
|
||||
|
||||
if (! $this->export->outputHandler($buffer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$fields = $dbi->getColumns($db, $table);
|
||||
foreach ($fields as $row) {
|
||||
$extracted_columnspec = Util::extractColumnSpec($row['Type']);
|
||||
$type = $extracted_columnspec['print_type'];
|
||||
if (empty($type)) {
|
||||
$type = ' ';
|
||||
}
|
||||
|
||||
if (! isset($row['Default'])) {
|
||||
if ($row['Null'] !== 'NO') {
|
||||
$row['Default'] = 'NULL';
|
||||
}
|
||||
}
|
||||
|
||||
$field_name = $col_as = $row['Field'];
|
||||
if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) {
|
||||
$col_as = $aliases[$db]['tables'][$table]['columns'][$col_as];
|
||||
}
|
||||
|
||||
$local_buffer = $col_as . "\000" . $type . "\000"
|
||||
. ($row['Null'] == '' || $row['Null'] === 'NO'
|
||||
? __('No') : __('Yes'))
|
||||
. "\000" . ($row['Default'] ?? '');
|
||||
|
||||
if ($do_relation && $have_rel) {
|
||||
$local_buffer .= "\000";
|
||||
$local_buffer .= $this->getRelationString($res_rel, $field_name, $db, $aliases);
|
||||
}
|
||||
|
||||
if ($do_comments && $relationParameters->columnCommentsFeature !== null) {
|
||||
$local_buffer .= "\000";
|
||||
if (isset($comments[$field_name])) {
|
||||
$local_buffer .= $comments[$field_name];
|
||||
}
|
||||
}
|
||||
|
||||
if ($do_mime && $relationParameters->browserTransformationFeature !== null) {
|
||||
$local_buffer .= "\000";
|
||||
if (isset($mime_map[$field_name])) {
|
||||
$local_buffer .= str_replace('_', '/', $mime_map[$field_name]['mimetype']);
|
||||
}
|
||||
}
|
||||
|
||||
$local_buffer = self::texEscape($local_buffer);
|
||||
if ($row['Key'] === 'PRI') {
|
||||
$pos = (int) mb_strpos($local_buffer, "\000");
|
||||
$local_buffer = '\\textit{'
|
||||
.
|
||||
mb_substr($local_buffer, 0, $pos)
|
||||
. '}' .
|
||||
mb_substr($local_buffer, $pos);
|
||||
}
|
||||
|
||||
if (in_array($field_name, $unique_keys)) {
|
||||
$pos = (int) mb_strpos($local_buffer, "\000");
|
||||
$local_buffer = '\\textbf{'
|
||||
.
|
||||
mb_substr($local_buffer, 0, $pos)
|
||||
. '}' .
|
||||
mb_substr($local_buffer, $pos);
|
||||
}
|
||||
|
||||
$buffer = str_replace("\000", ' & ', $local_buffer);
|
||||
$buffer .= ' \\\\ \\hline ' . $crlf;
|
||||
|
||||
if (! $this->export->outputHandler($buffer)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$buffer = ' \\end{longtable}' . $crlf;
|
||||
|
||||
return $this->export->outputHandler($buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes some special characters for use in TeX/LaTeX
|
||||
*
|
||||
* @param string $string the string to convert
|
||||
*
|
||||
* @return string the converted string with escape codes
|
||||
*/
|
||||
public static function texEscape($string)
|
||||
{
|
||||
$escape = [
|
||||
'$',
|
||||
'%',
|
||||
'{',
|
||||
'}',
|
||||
'&',
|
||||
'#',
|
||||
'_',
|
||||
'^',
|
||||
];
|
||||
$cnt_escape = count($escape);
|
||||
for ($k = 0; $k < $cnt_escape; $k++) {
|
||||
$string = str_replace($escape[$k], '\\' . $escape[$k], $string);
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,383 @@
|
|||
<?php
|
||||
/**
|
||||
* Set of functions used to build MediaWiki dumps of tables
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Plugins\Export;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Plugins\ExportPlugin;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertySubgroup;
|
||||
use PhpMyAdmin\Properties\Options\Items\BoolPropertyItem;
|
||||
use PhpMyAdmin\Properties\Options\Items\RadioPropertyItem;
|
||||
use PhpMyAdmin\Properties\Plugins\ExportPluginProperties;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function __;
|
||||
use function array_values;
|
||||
use function count;
|
||||
use function htmlspecialchars;
|
||||
use function str_repeat;
|
||||
|
||||
/**
|
||||
* Handles the export for the MediaWiki class
|
||||
*/
|
||||
class ExportMediawiki extends ExportPlugin
|
||||
{
|
||||
/**
|
||||
* @psalm-return non-empty-lowercase-string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'mediawiki';
|
||||
}
|
||||
|
||||
protected function setProperties(): ExportPluginProperties
|
||||
{
|
||||
$exportPluginProperties = new ExportPluginProperties();
|
||||
$exportPluginProperties->setText('MediaWiki Table');
|
||||
$exportPluginProperties->setExtension('mediawiki');
|
||||
$exportPluginProperties->setMimeType('text/plain');
|
||||
$exportPluginProperties->setOptionsText(__('Options'));
|
||||
|
||||
// create the root group that will be the options field for
|
||||
// $exportPluginProperties
|
||||
// this will be shown as "Format specific options"
|
||||
$exportSpecificOptions = new OptionsPropertyRootGroup('Format Specific Options');
|
||||
|
||||
// general options main group
|
||||
$generalOptions = new OptionsPropertyMainGroup(
|
||||
'general_opts',
|
||||
__('Dump table')
|
||||
);
|
||||
|
||||
// what to dump (structure/data/both)
|
||||
$subgroup = new OptionsPropertySubgroup(
|
||||
'dump_table',
|
||||
__('Dump table')
|
||||
);
|
||||
$leaf = new RadioPropertyItem('structure_or_data');
|
||||
$leaf->setValues(
|
||||
[
|
||||
'structure' => __('structure'),
|
||||
'data' => __('data'),
|
||||
'structure_and_data' => __('structure and data'),
|
||||
]
|
||||
);
|
||||
$subgroup->setSubgroupHeader($leaf);
|
||||
$generalOptions->addProperty($subgroup);
|
||||
|
||||
// export table name
|
||||
$leaf = new BoolPropertyItem(
|
||||
'caption',
|
||||
__('Export table names')
|
||||
);
|
||||
$generalOptions->addProperty($leaf);
|
||||
|
||||
// export table headers
|
||||
$leaf = new BoolPropertyItem(
|
||||
'headers',
|
||||
__('Export table headers')
|
||||
);
|
||||
$generalOptions->addProperty($leaf);
|
||||
//add the main group to the root group
|
||||
$exportSpecificOptions->addProperty($generalOptions);
|
||||
|
||||
// set the options for the export plugin property item
|
||||
$exportPluginProperties->setOptions($exportSpecificOptions);
|
||||
|
||||
return $exportPluginProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export header
|
||||
*/
|
||||
public function exportHeader(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export footer
|
||||
*/
|
||||
public function exportFooter(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database header
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $dbAlias Alias of db
|
||||
*/
|
||||
public function exportDBHeader($db, $dbAlias = ''): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database footer
|
||||
*
|
||||
* @param string $db Database name
|
||||
*/
|
||||
public function exportDBFooter($db): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs CREATE DATABASE statement
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $exportType 'server', 'database', 'table'
|
||||
* @param string $dbAlias Aliases of db
|
||||
*/
|
||||
public function exportDBCreate($db, $exportType, $dbAlias = ''): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs table's structure
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
* @param string $crlf the end of line sequence
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string $exportMode 'create_table','triggers','create_view',
|
||||
* 'stand_in'
|
||||
* @param string $exportType 'server', 'database', 'table'
|
||||
* @param bool $do_relation whether to include relation comments
|
||||
* @param bool $do_comments whether to include the pmadb-style column
|
||||
* comments as comments in the structure; this is
|
||||
* deprecated but the parameter is left here
|
||||
* because /export calls exportStructure()
|
||||
* also for other export types which use this
|
||||
* parameter
|
||||
* @param bool $do_mime whether to include mime comments
|
||||
* @param bool $dates whether to include creation/update/check dates
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*/
|
||||
public function exportStructure(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$exportMode,
|
||||
$exportType,
|
||||
$do_relation = false,
|
||||
$do_comments = false,
|
||||
$do_mime = false,
|
||||
$dates = false,
|
||||
array $aliases = []
|
||||
): bool {
|
||||
global $dbi;
|
||||
|
||||
$db_alias = $db;
|
||||
$table_alias = $table;
|
||||
$this->initAlias($aliases, $db_alias, $table_alias);
|
||||
|
||||
$output = '';
|
||||
switch ($exportMode) {
|
||||
case 'create_table':
|
||||
$columns = $dbi->getColumns($db, $table);
|
||||
$columns = array_values($columns);
|
||||
$row_cnt = count($columns);
|
||||
|
||||
// Print structure comment
|
||||
$output = $this->exportComment(
|
||||
'Table structure for '
|
||||
. Util::backquote($table_alias)
|
||||
);
|
||||
|
||||
// Begin the table construction
|
||||
$output .= '{| class="wikitable" style="text-align:center;"'
|
||||
. $this->exportCRLF();
|
||||
|
||||
// Add the table name
|
||||
if (isset($GLOBALS['mediawiki_caption'])) {
|
||||
$output .= "|+'''" . $table_alias . "'''" . $this->exportCRLF();
|
||||
}
|
||||
|
||||
// Add the table headers
|
||||
if (isset($GLOBALS['mediawiki_headers'])) {
|
||||
$output .= '|- style="background:#ffdead;"' . $this->exportCRLF();
|
||||
$output .= '! style="background:#ffffff" | '
|
||||
. $this->exportCRLF();
|
||||
for ($i = 0; $i < $row_cnt; ++$i) {
|
||||
$col_as = $columns[$i]['Field'];
|
||||
if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) {
|
||||
$col_as = $aliases[$db]['tables'][$table]['columns'][$col_as];
|
||||
}
|
||||
|
||||
$output .= ' | ' . $col_as . $this->exportCRLF();
|
||||
}
|
||||
}
|
||||
|
||||
// Add the table structure
|
||||
$output .= '|-' . $this->exportCRLF();
|
||||
$output .= '! Type' . $this->exportCRLF();
|
||||
for ($i = 0; $i < $row_cnt; ++$i) {
|
||||
$output .= ' | ' . $columns[$i]['Type'] . $this->exportCRLF();
|
||||
}
|
||||
|
||||
$output .= '|-' . $this->exportCRLF();
|
||||
$output .= '! Null' . $this->exportCRLF();
|
||||
for ($i = 0; $i < $row_cnt; ++$i) {
|
||||
$output .= ' | ' . $columns[$i]['Null'] . $this->exportCRLF();
|
||||
}
|
||||
|
||||
$output .= '|-' . $this->exportCRLF();
|
||||
$output .= '! Default' . $this->exportCRLF();
|
||||
for ($i = 0; $i < $row_cnt; ++$i) {
|
||||
$output .= ' | ' . $columns[$i]['Default'] . $this->exportCRLF();
|
||||
}
|
||||
|
||||
$output .= '|-' . $this->exportCRLF();
|
||||
$output .= '! Extra' . $this->exportCRLF();
|
||||
for ($i = 0; $i < $row_cnt; ++$i) {
|
||||
$output .= ' | ' . $columns[$i]['Extra'] . $this->exportCRLF();
|
||||
}
|
||||
|
||||
$output .= '|}' . str_repeat($this->exportCRLF(), 2);
|
||||
break;
|
||||
}
|
||||
|
||||
return $this->export->outputHandler($output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the content of a table in MediaWiki format
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
* @param string $crlf the end of line sequence
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string $sqlQuery SQL query for obtaining data
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*/
|
||||
public function exportData(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$sqlQuery,
|
||||
array $aliases = []
|
||||
): bool {
|
||||
global $dbi;
|
||||
|
||||
$db_alias = $db;
|
||||
$table_alias = $table;
|
||||
$this->initAlias($aliases, $db_alias, $table_alias);
|
||||
|
||||
// Print data comment
|
||||
$output = $this->exportComment(
|
||||
$table_alias != ''
|
||||
? 'Table data for ' . Util::backquote($table_alias)
|
||||
: 'Query results'
|
||||
);
|
||||
|
||||
// Begin the table construction
|
||||
// Use the "wikitable" class for style
|
||||
// Use the "sortable" class for allowing tables to be sorted by column
|
||||
$output .= '{| class="wikitable sortable" style="text-align:center;"'
|
||||
. $this->exportCRLF();
|
||||
|
||||
// Add the table name
|
||||
if (isset($GLOBALS['mediawiki_caption'])) {
|
||||
$output .= "|+'''" . $table_alias . "'''" . $this->exportCRLF();
|
||||
}
|
||||
|
||||
// Add the table headers
|
||||
if (isset($GLOBALS['mediawiki_headers'])) {
|
||||
// Get column names
|
||||
$column_names = $dbi->getColumnNames($db, $table);
|
||||
|
||||
// Add column names as table headers
|
||||
if ($column_names !== []) {
|
||||
// Use '|-' for separating rows
|
||||
$output .= '|-' . $this->exportCRLF();
|
||||
|
||||
// Use '!' for separating table headers
|
||||
foreach ($column_names as $column) {
|
||||
if (! empty($aliases[$db]['tables'][$table]['columns'][$column])) {
|
||||
$column = $aliases[$db]['tables'][$table]['columns'][$column];
|
||||
}
|
||||
|
||||
$output .= ' ! ' . $column . '' . $this->exportCRLF();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the table data from the database
|
||||
$result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED);
|
||||
$fields_cnt = $result->numFields();
|
||||
|
||||
while ($row = $result->fetchRow()) {
|
||||
$output .= '|-' . $this->exportCRLF();
|
||||
|
||||
// Use '|' for separating table columns
|
||||
for ($i = 0; $i < $fields_cnt; ++$i) {
|
||||
$output .= ' | ' . $row[$i] . '' . $this->exportCRLF();
|
||||
}
|
||||
}
|
||||
|
||||
// End table construction
|
||||
$output .= '|}' . str_repeat($this->exportCRLF(), 2);
|
||||
|
||||
return $this->export->outputHandler($output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs result raw query in MediaWiki format
|
||||
*
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string|null $db the database where the query is executed
|
||||
* @param string $sqlQuery the rawquery to output
|
||||
* @param string $crlf the end of line sequence
|
||||
*/
|
||||
public function exportRawQuery(string $errorUrl, ?string $db, string $sqlQuery, string $crlf): bool
|
||||
{
|
||||
global $dbi;
|
||||
|
||||
if ($db !== null) {
|
||||
$dbi->selectDb($db);
|
||||
}
|
||||
|
||||
return $this->exportData($db ?? '', '', $crlf, $errorUrl, $sqlQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs comments containing info about the exported tables
|
||||
*
|
||||
* @param string $text Text of comment
|
||||
*
|
||||
* @return string The formatted comment
|
||||
*/
|
||||
private function exportComment($text = '')
|
||||
{
|
||||
// see https://www.mediawiki.org/wiki/Help:Formatting
|
||||
$comment = $this->exportCRLF();
|
||||
$comment .= '<!--' . $this->exportCRLF();
|
||||
$comment .= htmlspecialchars($text) . $this->exportCRLF();
|
||||
$comment .= '-->' . str_repeat($this->exportCRLF(), 2);
|
||||
|
||||
return $comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs CRLF
|
||||
*
|
||||
* @return string CRLF
|
||||
*/
|
||||
private function exportCRLF()
|
||||
{
|
||||
// The CRLF expected by the mediawiki format is "\n"
|
||||
return "\n";
|
||||
}
|
||||
}
|
329
admin/phpMyAdmin/libraries/classes/Plugins/Export/ExportOds.php
Normal file
329
admin/phpMyAdmin/libraries/classes/Plugins/Export/ExportOds.php
Normal file
|
@ -0,0 +1,329 @@
|
|||
<?php
|
||||
/**
|
||||
* Set of functions used to build OpenDocument Spreadsheet dumps of tables
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Plugins\Export;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\FieldMetadata;
|
||||
use PhpMyAdmin\OpenDocument;
|
||||
use PhpMyAdmin\Plugins\ExportPlugin;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup;
|
||||
use PhpMyAdmin\Properties\Options\Items\BoolPropertyItem;
|
||||
use PhpMyAdmin\Properties\Options\Items\HiddenPropertyItem;
|
||||
use PhpMyAdmin\Properties\Options\Items\TextPropertyItem;
|
||||
use PhpMyAdmin\Properties\Plugins\ExportPluginProperties;
|
||||
|
||||
use function __;
|
||||
use function bin2hex;
|
||||
use function date;
|
||||
use function htmlspecialchars;
|
||||
use function stripslashes;
|
||||
use function strtotime;
|
||||
|
||||
/**
|
||||
* Handles the export for the ODS class
|
||||
*/
|
||||
class ExportOds extends ExportPlugin
|
||||
{
|
||||
protected function init(): void
|
||||
{
|
||||
$GLOBALS['ods_buffer'] = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-return non-empty-lowercase-string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'ods';
|
||||
}
|
||||
|
||||
protected function setProperties(): ExportPluginProperties
|
||||
{
|
||||
$exportPluginProperties = new ExportPluginProperties();
|
||||
$exportPluginProperties->setText('OpenDocument Spreadsheet');
|
||||
$exportPluginProperties->setExtension('ods');
|
||||
$exportPluginProperties->setMimeType('application/vnd.oasis.opendocument.spreadsheet');
|
||||
$exportPluginProperties->setForceFile(true);
|
||||
$exportPluginProperties->setOptionsText(__('Options'));
|
||||
|
||||
// create the root group that will be the options field for
|
||||
// $exportPluginProperties
|
||||
// this will be shown as "Format specific options"
|
||||
$exportSpecificOptions = new OptionsPropertyRootGroup('Format Specific Options');
|
||||
|
||||
// general options main group
|
||||
$generalOptions = new OptionsPropertyMainGroup('general_opts');
|
||||
// create primary items and add them to the group
|
||||
$leaf = new TextPropertyItem(
|
||||
'null',
|
||||
__('Replace NULL with:')
|
||||
);
|
||||
$generalOptions->addProperty($leaf);
|
||||
$leaf = new BoolPropertyItem(
|
||||
'columns',
|
||||
__('Put columns names in the first row')
|
||||
);
|
||||
$generalOptions->addProperty($leaf);
|
||||
$leaf = new HiddenPropertyItem('structure_or_data');
|
||||
$generalOptions->addProperty($leaf);
|
||||
// add the main group to the root group
|
||||
$exportSpecificOptions->addProperty($generalOptions);
|
||||
|
||||
// set the options for the export plugin property item
|
||||
$exportPluginProperties->setOptions($exportSpecificOptions);
|
||||
|
||||
return $exportPluginProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export header
|
||||
*/
|
||||
public function exportHeader(): bool
|
||||
{
|
||||
$GLOBALS['ods_buffer'] .= '<?xml version="1.0" encoding="utf-8"?' . '>'
|
||||
. '<office:document-content '
|
||||
. OpenDocument::NS . ' office:version="1.0">'
|
||||
. '<office:automatic-styles>'
|
||||
. '<number:date-style style:name="N37"'
|
||||
. ' number:automatic-order="true">'
|
||||
. '<number:month number:style="long"/>'
|
||||
. '<number:text>/</number:text>'
|
||||
. '<number:day number:style="long"/>'
|
||||
. '<number:text>/</number:text>'
|
||||
. '<number:year/>'
|
||||
. '</number:date-style>'
|
||||
. '<number:time-style style:name="N43">'
|
||||
. '<number:hours number:style="long"/>'
|
||||
. '<number:text>:</number:text>'
|
||||
. '<number:minutes number:style="long"/>'
|
||||
. '<number:text>:</number:text>'
|
||||
. '<number:seconds number:style="long"/>'
|
||||
. '<number:text> </number:text>'
|
||||
. '<number:am-pm/>'
|
||||
. '</number:time-style>'
|
||||
. '<number:date-style style:name="N50"'
|
||||
. ' number:automatic-order="true"'
|
||||
. ' number:format-source="language">'
|
||||
. '<number:month/>'
|
||||
. '<number:text>/</number:text>'
|
||||
. '<number:day/>'
|
||||
. '<number:text>/</number:text>'
|
||||
. '<number:year/>'
|
||||
. '<number:text> </number:text>'
|
||||
. '<number:hours number:style="long"/>'
|
||||
. '<number:text>:</number:text>'
|
||||
. '<number:minutes number:style="long"/>'
|
||||
. '<number:text> </number:text>'
|
||||
. '<number:am-pm/>'
|
||||
. '</number:date-style>'
|
||||
. '<style:style style:name="DateCell" style:family="table-cell"'
|
||||
. ' style:parent-style-name="Default" style:data-style-name="N37"/>'
|
||||
. '<style:style style:name="TimeCell" style:family="table-cell"'
|
||||
. ' style:parent-style-name="Default" style:data-style-name="N43"/>'
|
||||
. '<style:style style:name="DateTimeCell" style:family="table-cell"'
|
||||
. ' style:parent-style-name="Default" style:data-style-name="N50"/>'
|
||||
. '</office:automatic-styles>'
|
||||
. '<office:body>'
|
||||
. '<office:spreadsheet>';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export footer
|
||||
*/
|
||||
public function exportFooter(): bool
|
||||
{
|
||||
$GLOBALS['ods_buffer'] .= '</office:spreadsheet></office:body></office:document-content>';
|
||||
|
||||
return $this->export->outputHandler(
|
||||
OpenDocument::create(
|
||||
'application/vnd.oasis.opendocument.spreadsheet',
|
||||
$GLOBALS['ods_buffer']
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database header
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $dbAlias Aliases of db
|
||||
*/
|
||||
public function exportDBHeader($db, $dbAlias = ''): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database footer
|
||||
*
|
||||
* @param string $db Database name
|
||||
*/
|
||||
public function exportDBFooter($db): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs CREATE DATABASE statement
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $exportType 'server', 'database', 'table'
|
||||
* @param string $dbAlias Aliases of db
|
||||
*/
|
||||
public function exportDBCreate($db, $exportType, $dbAlias = ''): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the content of a table in NHibernate format
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
* @param string $crlf the end of line sequence
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string $sqlQuery SQL query for obtaining data
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*/
|
||||
public function exportData(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$sqlQuery,
|
||||
array $aliases = []
|
||||
): bool {
|
||||
global $what, $dbi;
|
||||
|
||||
$db_alias = $db;
|
||||
$table_alias = $table;
|
||||
$this->initAlias($aliases, $db_alias, $table_alias);
|
||||
// Gets the data from the database
|
||||
$result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED);
|
||||
$fields_cnt = $result->numFields();
|
||||
/** @var FieldMetadata[] $fieldsMeta */
|
||||
$fieldsMeta = $dbi->getFieldsMeta($result);
|
||||
|
||||
$GLOBALS['ods_buffer'] .= '<table:table table:name="' . htmlspecialchars($table_alias) . '">';
|
||||
|
||||
// If required, get fields name at the first line
|
||||
if (isset($GLOBALS[$what . '_columns'])) {
|
||||
$GLOBALS['ods_buffer'] .= '<table:table-row>';
|
||||
foreach ($fieldsMeta as $field) {
|
||||
$col_as = $field->name;
|
||||
if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) {
|
||||
$col_as = $aliases[$db]['tables'][$table]['columns'][$col_as];
|
||||
}
|
||||
|
||||
$GLOBALS['ods_buffer'] .= '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>'
|
||||
. htmlspecialchars(
|
||||
stripslashes($col_as)
|
||||
)
|
||||
. '</text:p>'
|
||||
. '</table:table-cell>';
|
||||
}
|
||||
|
||||
$GLOBALS['ods_buffer'] .= '</table:table-row>';
|
||||
}
|
||||
|
||||
// Format the data
|
||||
while ($row = $result->fetchRow()) {
|
||||
$GLOBALS['ods_buffer'] .= '<table:table-row>';
|
||||
for ($j = 0; $j < $fields_cnt; $j++) {
|
||||
if ($fieldsMeta[$j]->isMappedTypeGeometry) {
|
||||
// export GIS types as hex
|
||||
$row[$j] = '0x' . bin2hex($row[$j]);
|
||||
}
|
||||
|
||||
if (! isset($row[$j])) {
|
||||
$GLOBALS['ods_buffer'] .= '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>'
|
||||
. htmlspecialchars($GLOBALS[$what . '_null'])
|
||||
. '</text:p>'
|
||||
. '</table:table-cell>';
|
||||
} elseif ($fieldsMeta[$j]->isBinary && $fieldsMeta[$j]->isBlob) {
|
||||
// ignore BLOB
|
||||
$GLOBALS['ods_buffer'] .= '<table:table-cell office:value-type="string">'
|
||||
. '<text:p></text:p>'
|
||||
. '</table:table-cell>';
|
||||
} elseif ($fieldsMeta[$j]->isType(FieldMetadata::TYPE_DATE)) {
|
||||
$GLOBALS['ods_buffer'] .= '<table:table-cell office:value-type="date"'
|
||||
. ' office:date-value="'
|
||||
. date('Y-m-d', strtotime($row[$j]))
|
||||
. '" table:style-name="DateCell">'
|
||||
. '<text:p>'
|
||||
. htmlspecialchars($row[$j])
|
||||
. '</text:p>'
|
||||
. '</table:table-cell>';
|
||||
} elseif ($fieldsMeta[$j]->isType(FieldMetadata::TYPE_TIME)) {
|
||||
$GLOBALS['ods_buffer'] .= '<table:table-cell office:value-type="time"'
|
||||
. ' office:time-value="'
|
||||
. date('\P\TH\Hi\Ms\S', strtotime($row[$j]))
|
||||
. '" table:style-name="TimeCell">'
|
||||
. '<text:p>'
|
||||
. htmlspecialchars($row[$j])
|
||||
. '</text:p>'
|
||||
. '</table:table-cell>';
|
||||
} elseif ($fieldsMeta[$j]->isType(FieldMetadata::TYPE_DATETIME)) {
|
||||
$GLOBALS['ods_buffer'] .= '<table:table-cell office:value-type="date"'
|
||||
. ' office:date-value="'
|
||||
. date('Y-m-d\TH:i:s', strtotime($row[$j]))
|
||||
. '" table:style-name="DateTimeCell">'
|
||||
. '<text:p>'
|
||||
. htmlspecialchars($row[$j])
|
||||
. '</text:p>'
|
||||
. '</table:table-cell>';
|
||||
} elseif (
|
||||
$fieldsMeta[$j]->isNumeric
|
||||
) {
|
||||
$GLOBALS['ods_buffer'] .= '<table:table-cell office:value-type="float"'
|
||||
. ' office:value="' . $row[$j] . '" >'
|
||||
. '<text:p>'
|
||||
. htmlspecialchars($row[$j])
|
||||
. '</text:p>'
|
||||
. '</table:table-cell>';
|
||||
} else {
|
||||
$GLOBALS['ods_buffer'] .= '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>'
|
||||
. htmlspecialchars($row[$j])
|
||||
. '</text:p>'
|
||||
. '</table:table-cell>';
|
||||
}
|
||||
}
|
||||
|
||||
$GLOBALS['ods_buffer'] .= '</table:table-row>';
|
||||
}
|
||||
|
||||
$GLOBALS['ods_buffer'] .= '</table:table>';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs result raw query in ODS format
|
||||
*
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string|null $db the database where the query is executed
|
||||
* @param string $sqlQuery the rawquery to output
|
||||
* @param string $crlf the end of line sequence
|
||||
*/
|
||||
public function exportRawQuery(string $errorUrl, ?string $db, string $sqlQuery, string $crlf): bool
|
||||
{
|
||||
global $dbi;
|
||||
|
||||
if ($db !== null) {
|
||||
$dbi->selectDb($db);
|
||||
}
|
||||
|
||||
return $this->exportData($db ?? '', '', $crlf, $errorUrl, $sqlQuery);
|
||||
}
|
||||
}
|
797
admin/phpMyAdmin/libraries/classes/Plugins/Export/ExportOdt.php
Normal file
797
admin/phpMyAdmin/libraries/classes/Plugins/Export/ExportOdt.php
Normal file
|
@ -0,0 +1,797 @@
|
|||
<?php
|
||||
/**
|
||||
* Set of functions used to build OpenDocument Text dumps of tables
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Plugins\Export;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\FieldMetadata;
|
||||
use PhpMyAdmin\OpenDocument;
|
||||
use PhpMyAdmin\Plugins\ExportPlugin;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup;
|
||||
use PhpMyAdmin\Properties\Options\Items\BoolPropertyItem;
|
||||
use PhpMyAdmin\Properties\Options\Items\RadioPropertyItem;
|
||||
use PhpMyAdmin\Properties\Options\Items\TextPropertyItem;
|
||||
use PhpMyAdmin\Properties\Plugins\ExportPluginProperties;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function __;
|
||||
use function bin2hex;
|
||||
use function htmlspecialchars;
|
||||
use function str_replace;
|
||||
use function stripslashes;
|
||||
|
||||
/**
|
||||
* Handles the export for the ODT class
|
||||
*/
|
||||
class ExportOdt extends ExportPlugin
|
||||
{
|
||||
protected function init(): void
|
||||
{
|
||||
$GLOBALS['odt_buffer'] = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-return non-empty-lowercase-string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'odt';
|
||||
}
|
||||
|
||||
protected function setProperties(): ExportPluginProperties
|
||||
{
|
||||
global $plugin_param;
|
||||
$hide_structure = false;
|
||||
if ($plugin_param['export_type'] === 'table' && ! $plugin_param['single_table']) {
|
||||
$hide_structure = true;
|
||||
}
|
||||
|
||||
$exportPluginProperties = new ExportPluginProperties();
|
||||
$exportPluginProperties->setText('OpenDocument Text');
|
||||
$exportPluginProperties->setExtension('odt');
|
||||
$exportPluginProperties->setMimeType('application/vnd.oasis.opendocument.text');
|
||||
$exportPluginProperties->setForceFile(true);
|
||||
$exportPluginProperties->setOptionsText(__('Options'));
|
||||
|
||||
// create the root group that will be the options field for
|
||||
// $exportPluginProperties
|
||||
// this will be shown as "Format specific options"
|
||||
$exportSpecificOptions = new OptionsPropertyRootGroup('Format Specific Options');
|
||||
|
||||
// what to dump (structure/data/both) main group
|
||||
$dumpWhat = new OptionsPropertyMainGroup(
|
||||
'general_opts',
|
||||
__('Dump table')
|
||||
);
|
||||
// create primary items and add them to the group
|
||||
$leaf = new RadioPropertyItem('structure_or_data');
|
||||
$leaf->setValues(
|
||||
[
|
||||
'structure' => __('structure'),
|
||||
'data' => __('data'),
|
||||
'structure_and_data' => __('structure and data'),
|
||||
]
|
||||
);
|
||||
$dumpWhat->addProperty($leaf);
|
||||
// add the main group to the root group
|
||||
$exportSpecificOptions->addProperty($dumpWhat);
|
||||
|
||||
// structure options main group
|
||||
if (! $hide_structure) {
|
||||
$structureOptions = new OptionsPropertyMainGroup(
|
||||
'structure',
|
||||
__('Object creation options')
|
||||
);
|
||||
$structureOptions->setForce('data');
|
||||
$relationParameters = $this->relation->getRelationParameters();
|
||||
// create primary items and add them to the group
|
||||
if ($relationParameters->relationFeature !== null) {
|
||||
$leaf = new BoolPropertyItem(
|
||||
'relation',
|
||||
__('Display foreign key relationships')
|
||||
);
|
||||
$structureOptions->addProperty($leaf);
|
||||
}
|
||||
|
||||
$leaf = new BoolPropertyItem(
|
||||
'comments',
|
||||
__('Display comments')
|
||||
);
|
||||
$structureOptions->addProperty($leaf);
|
||||
if ($relationParameters->browserTransformationFeature !== null) {
|
||||
$leaf = new BoolPropertyItem(
|
||||
'mime',
|
||||
__('Display media types')
|
||||
);
|
||||
$structureOptions->addProperty($leaf);
|
||||
}
|
||||
|
||||
// add the main group to the root group
|
||||
$exportSpecificOptions->addProperty($structureOptions);
|
||||
}
|
||||
|
||||
// data options main group
|
||||
$dataOptions = new OptionsPropertyMainGroup(
|
||||
'data',
|
||||
__('Data dump options')
|
||||
);
|
||||
$dataOptions->setForce('structure');
|
||||
// create primary items and add them to the group
|
||||
$leaf = new BoolPropertyItem(
|
||||
'columns',
|
||||
__('Put columns names in the first row')
|
||||
);
|
||||
$dataOptions->addProperty($leaf);
|
||||
$leaf = new TextPropertyItem(
|
||||
'null',
|
||||
__('Replace NULL with:')
|
||||
);
|
||||
$dataOptions->addProperty($leaf);
|
||||
// add the main group to the root group
|
||||
$exportSpecificOptions->addProperty($dataOptions);
|
||||
|
||||
// set the options for the export plugin property item
|
||||
$exportPluginProperties->setOptions($exportSpecificOptions);
|
||||
|
||||
return $exportPluginProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export header
|
||||
*/
|
||||
public function exportHeader(): bool
|
||||
{
|
||||
$GLOBALS['odt_buffer'] .= '<?xml version="1.0" encoding="utf-8"?' . '>'
|
||||
. '<office:document-content '
|
||||
. OpenDocument::NS . ' office:version="1.0">'
|
||||
. '<office:body>'
|
||||
. '<office:text>';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export footer
|
||||
*/
|
||||
public function exportFooter(): bool
|
||||
{
|
||||
$GLOBALS['odt_buffer'] .= '</office:text></office:body></office:document-content>';
|
||||
|
||||
return $this->export->outputHandler(OpenDocument::create(
|
||||
'application/vnd.oasis.opendocument.text',
|
||||
$GLOBALS['odt_buffer']
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database header
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $dbAlias Aliases of db
|
||||
*/
|
||||
public function exportDBHeader($db, $dbAlias = ''): bool
|
||||
{
|
||||
if (empty($dbAlias)) {
|
||||
$dbAlias = $db;
|
||||
}
|
||||
|
||||
$GLOBALS['odt_buffer'] .= '<text:h text:outline-level="1" text:style-name="Heading_1"'
|
||||
. ' text:is-list-header="true">'
|
||||
. __('Database') . ' ' . htmlspecialchars($dbAlias)
|
||||
. '</text:h>';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database footer
|
||||
*
|
||||
* @param string $db Database name
|
||||
*/
|
||||
public function exportDBFooter($db): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs CREATE DATABASE statement
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $exportType 'server', 'database', 'table'
|
||||
* @param string $dbAlias Aliases of db
|
||||
*/
|
||||
public function exportDBCreate($db, $exportType, $dbAlias = ''): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the content of a table in NHibernate format
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
* @param string $crlf the end of line sequence
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string $sqlQuery SQL query for obtaining data
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*/
|
||||
public function exportData(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$sqlQuery,
|
||||
array $aliases = []
|
||||
): bool {
|
||||
global $what, $dbi;
|
||||
|
||||
$db_alias = $db;
|
||||
$table_alias = $table;
|
||||
$this->initAlias($aliases, $db_alias, $table_alias);
|
||||
// Gets the data from the database
|
||||
$result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED);
|
||||
$fields_cnt = $result->numFields();
|
||||
/** @var FieldMetadata[] $fieldsMeta */
|
||||
$fieldsMeta = $dbi->getFieldsMeta($result);
|
||||
|
||||
$GLOBALS['odt_buffer'] .= '<text:h text:outline-level="2" text:style-name="Heading_2"'
|
||||
. ' text:is-list-header="true">';
|
||||
$table_alias != ''
|
||||
? $GLOBALS['odt_buffer'] .= __('Dumping data for table') . ' ' . htmlspecialchars($table_alias)
|
||||
: $GLOBALS['odt_buffer'] .= __('Dumping data for query result');
|
||||
$GLOBALS['odt_buffer'] .= '</text:h>'
|
||||
. '<table:table'
|
||||
. ' table:name="' . htmlspecialchars($table_alias) . '_structure">'
|
||||
. '<table:table-column'
|
||||
. ' table:number-columns-repeated="' . $fields_cnt . '"/>';
|
||||
|
||||
// If required, get fields name at the first line
|
||||
if (isset($GLOBALS[$what . '_columns'])) {
|
||||
$GLOBALS['odt_buffer'] .= '<table:table-row>';
|
||||
foreach ($fieldsMeta as $field) {
|
||||
$col_as = $field->name;
|
||||
if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) {
|
||||
$col_as = $aliases[$db]['tables'][$table]['columns'][$col_as];
|
||||
}
|
||||
|
||||
$GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>'
|
||||
. htmlspecialchars(
|
||||
stripslashes($col_as)
|
||||
)
|
||||
. '</text:p>'
|
||||
. '</table:table-cell>';
|
||||
}
|
||||
|
||||
$GLOBALS['odt_buffer'] .= '</table:table-row>';
|
||||
}
|
||||
|
||||
// Format the data
|
||||
while ($row = $result->fetchRow()) {
|
||||
$GLOBALS['odt_buffer'] .= '<table:table-row>';
|
||||
for ($j = 0; $j < $fields_cnt; $j++) {
|
||||
if ($fieldsMeta[$j]->isMappedTypeGeometry) {
|
||||
// export GIS types as hex
|
||||
$row[$j] = '0x' . bin2hex($row[$j]);
|
||||
}
|
||||
|
||||
if (! isset($row[$j])) {
|
||||
$GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>'
|
||||
. htmlspecialchars($GLOBALS[$what . '_null'])
|
||||
. '</text:p>'
|
||||
. '</table:table-cell>';
|
||||
} elseif ($fieldsMeta[$j]->isBinary && $fieldsMeta[$j]->isBlob) {
|
||||
// ignore BLOB
|
||||
$GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">'
|
||||
. '<text:p></text:p>'
|
||||
. '</table:table-cell>';
|
||||
} elseif (
|
||||
$fieldsMeta[$j]->isNumeric
|
||||
) {
|
||||
$GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="float"'
|
||||
. ' office:value="' . $row[$j] . '" >'
|
||||
. '<text:p>'
|
||||
. htmlspecialchars($row[$j])
|
||||
. '</text:p>'
|
||||
. '</table:table-cell>';
|
||||
} else {
|
||||
$GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>'
|
||||
. htmlspecialchars($row[$j])
|
||||
. '</text:p>'
|
||||
. '</table:table-cell>';
|
||||
}
|
||||
}
|
||||
|
||||
$GLOBALS['odt_buffer'] .= '</table:table-row>';
|
||||
}
|
||||
|
||||
$GLOBALS['odt_buffer'] .= '</table:table>';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs result raw query in ODT format
|
||||
*
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string|null $db the database where the query is executed
|
||||
* @param string $sqlQuery the rawquery to output
|
||||
* @param string $crlf the end of line sequence
|
||||
*/
|
||||
public function exportRawQuery(string $errorUrl, ?string $db, string $sqlQuery, string $crlf): bool
|
||||
{
|
||||
global $dbi;
|
||||
|
||||
if ($db !== null) {
|
||||
$dbi->selectDb($db);
|
||||
}
|
||||
|
||||
return $this->exportData($db ?? '', '', $crlf, $errorUrl, $sqlQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a stand-in CREATE definition to resolve view dependencies
|
||||
*
|
||||
* @param string $db the database name
|
||||
* @param string $view the view name
|
||||
* @param string $crlf the end of line sequence
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*
|
||||
* @return string resulting definition
|
||||
*/
|
||||
public function getTableDefStandIn($db, $view, $crlf, $aliases = [])
|
||||
{
|
||||
global $dbi;
|
||||
|
||||
$db_alias = $db;
|
||||
$view_alias = $view;
|
||||
$this->initAlias($aliases, $db_alias, $view_alias);
|
||||
/**
|
||||
* Gets fields properties
|
||||
*/
|
||||
$dbi->selectDb($db);
|
||||
|
||||
/**
|
||||
* Displays the table structure
|
||||
*/
|
||||
$GLOBALS['odt_buffer'] .= '<table:table table:name="'
|
||||
. htmlspecialchars($view_alias) . '_data">';
|
||||
$columns_cnt = 4;
|
||||
$GLOBALS['odt_buffer'] .= '<table:table-column'
|
||||
. ' table:number-columns-repeated="' . $columns_cnt . '"/>';
|
||||
/* Header */
|
||||
$GLOBALS['odt_buffer'] .= '<table:table-row>'
|
||||
. '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>' . __('Column') . '</text:p>'
|
||||
. '</table:table-cell>'
|
||||
. '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>' . __('Type') . '</text:p>'
|
||||
. '</table:table-cell>'
|
||||
. '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>' . __('Null') . '</text:p>'
|
||||
. '</table:table-cell>'
|
||||
. '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>' . __('Default') . '</text:p>'
|
||||
. '</table:table-cell>'
|
||||
. '</table:table-row>';
|
||||
|
||||
$columns = $dbi->getColumns($db, $view);
|
||||
foreach ($columns as $column) {
|
||||
$col_as = $column['Field'] ?? null;
|
||||
if (! empty($aliases[$db]['tables'][$view]['columns'][$col_as])) {
|
||||
$col_as = $aliases[$db]['tables'][$view]['columns'][$col_as];
|
||||
}
|
||||
|
||||
$GLOBALS['odt_buffer'] .= $this->formatOneColumnDefinition($column, $col_as);
|
||||
$GLOBALS['odt_buffer'] .= '</table:table-row>';
|
||||
}
|
||||
|
||||
$GLOBALS['odt_buffer'] .= '</table:table>';
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns $table's CREATE definition
|
||||
*
|
||||
* @param string $db the database name
|
||||
* @param string $table the table name
|
||||
* @param string $crlf the end of line sequence
|
||||
* @param string $error_url the url to go back in case of error
|
||||
* @param bool $do_relation whether to include relation comments
|
||||
* @param bool $do_comments whether to include the pmadb-style column
|
||||
* comments as comments in the structure;
|
||||
* this is deprecated but the parameter is
|
||||
* left here because /export calls
|
||||
* PMA_exportStructure() also for other
|
||||
* @param bool $do_mime whether to include mime comments
|
||||
* @param bool $show_dates whether to include creation/update/check dates
|
||||
* @param bool $add_semicolon whether to add semicolon and end-of-line at
|
||||
* the end
|
||||
* @param bool $view whether we're handling a view
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*/
|
||||
public function getTableDef(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
$error_url,
|
||||
$do_relation,
|
||||
$do_comments,
|
||||
$do_mime,
|
||||
$show_dates = false,
|
||||
$add_semicolon = true,
|
||||
$view = false,
|
||||
array $aliases = []
|
||||
): bool {
|
||||
global $dbi;
|
||||
|
||||
$db_alias = $db;
|
||||
$table_alias = $table;
|
||||
$this->initAlias($aliases, $db_alias, $table_alias);
|
||||
|
||||
$relationParameters = $this->relation->getRelationParameters();
|
||||
|
||||
/**
|
||||
* Gets fields properties
|
||||
*/
|
||||
$dbi->selectDb($db);
|
||||
|
||||
// Check if we can use Relations
|
||||
[$res_rel, $have_rel] = $this->relation->getRelationsAndStatus(
|
||||
$do_relation && $relationParameters->relationFeature !== null,
|
||||
$db,
|
||||
$table
|
||||
);
|
||||
/**
|
||||
* Displays the table structure
|
||||
*/
|
||||
$GLOBALS['odt_buffer'] .= '<table:table table:name="'
|
||||
. htmlspecialchars($table_alias) . '_structure">';
|
||||
$columns_cnt = 4;
|
||||
if ($do_relation && $have_rel) {
|
||||
$columns_cnt++;
|
||||
}
|
||||
|
||||
if ($do_comments) {
|
||||
$columns_cnt++;
|
||||
}
|
||||
|
||||
if ($do_mime && $relationParameters->browserTransformationFeature !== null) {
|
||||
$columns_cnt++;
|
||||
}
|
||||
|
||||
$GLOBALS['odt_buffer'] .= '<table:table-column'
|
||||
. ' table:number-columns-repeated="' . $columns_cnt . '"/>';
|
||||
/* Header */
|
||||
$GLOBALS['odt_buffer'] .= '<table:table-row>'
|
||||
. '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>' . __('Column') . '</text:p>'
|
||||
. '</table:table-cell>'
|
||||
. '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>' . __('Type') . '</text:p>'
|
||||
. '</table:table-cell>'
|
||||
. '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>' . __('Null') . '</text:p>'
|
||||
. '</table:table-cell>'
|
||||
. '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>' . __('Default') . '</text:p>'
|
||||
. '</table:table-cell>';
|
||||
if ($do_relation && $have_rel) {
|
||||
$GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>' . __('Links to') . '</text:p>'
|
||||
. '</table:table-cell>';
|
||||
}
|
||||
|
||||
if ($do_comments) {
|
||||
$GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>' . __('Comments') . '</text:p>'
|
||||
. '</table:table-cell>';
|
||||
$comments = $this->relation->getComments($db, $table);
|
||||
}
|
||||
|
||||
if ($do_mime && $relationParameters->browserTransformationFeature !== null) {
|
||||
$GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>' . __('Media type') . '</text:p>'
|
||||
. '</table:table-cell>';
|
||||
$mime_map = $this->transformations->getMime($db, $table, true);
|
||||
}
|
||||
|
||||
$GLOBALS['odt_buffer'] .= '</table:table-row>';
|
||||
|
||||
$columns = $dbi->getColumns($db, $table);
|
||||
foreach ($columns as $column) {
|
||||
$col_as = $field_name = $column['Field'];
|
||||
if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) {
|
||||
$col_as = $aliases[$db]['tables'][$table]['columns'][$col_as];
|
||||
}
|
||||
|
||||
$GLOBALS['odt_buffer'] .= $this->formatOneColumnDefinition($column, $col_as);
|
||||
if ($do_relation && $have_rel) {
|
||||
$foreigner = $this->relation->searchColumnInForeigners($res_rel, $field_name);
|
||||
if ($foreigner) {
|
||||
$rtable = $foreigner['foreign_table'];
|
||||
$rfield = $foreigner['foreign_field'];
|
||||
if (! empty($aliases[$db]['tables'][$rtable]['columns'][$rfield])) {
|
||||
$rfield = $aliases[$db]['tables'][$rtable]['columns'][$rfield];
|
||||
}
|
||||
|
||||
if (! empty($aliases[$db]['tables'][$rtable]['alias'])) {
|
||||
$rtable = $aliases[$db]['tables'][$rtable]['alias'];
|
||||
}
|
||||
|
||||
$relation = htmlspecialchars($rtable . ' (' . $rfield . ')');
|
||||
$GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>'
|
||||
. htmlspecialchars($relation)
|
||||
. '</text:p>'
|
||||
. '</table:table-cell>';
|
||||
}
|
||||
}
|
||||
|
||||
if ($do_comments) {
|
||||
if (isset($comments[$field_name])) {
|
||||
$GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>'
|
||||
. htmlspecialchars($comments[$field_name])
|
||||
. '</text:p>'
|
||||
. '</table:table-cell>';
|
||||
} else {
|
||||
$GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">'
|
||||
. '<text:p></text:p>'
|
||||
. '</table:table-cell>';
|
||||
}
|
||||
}
|
||||
|
||||
if ($do_mime && $relationParameters->browserTransformationFeature !== null) {
|
||||
if (isset($mime_map[$field_name])) {
|
||||
$GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>'
|
||||
. htmlspecialchars(
|
||||
str_replace('_', '/', $mime_map[$field_name]['mimetype'])
|
||||
)
|
||||
. '</text:p>'
|
||||
. '</table:table-cell>';
|
||||
} else {
|
||||
$GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">'
|
||||
. '<text:p></text:p>'
|
||||
. '</table:table-cell>';
|
||||
}
|
||||
}
|
||||
|
||||
$GLOBALS['odt_buffer'] .= '</table:table-row>';
|
||||
}
|
||||
|
||||
$GLOBALS['odt_buffer'] .= '</table:table>';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs triggers
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getTriggers($db, $table, array $aliases = [])
|
||||
{
|
||||
global $dbi;
|
||||
|
||||
$db_alias = $db;
|
||||
$table_alias = $table;
|
||||
$this->initAlias($aliases, $db_alias, $table_alias);
|
||||
$GLOBALS['odt_buffer'] .= '<table:table'
|
||||
. ' table:name="' . htmlspecialchars($table_alias) . '_triggers">'
|
||||
. '<table:table-column'
|
||||
. ' table:number-columns-repeated="4"/>'
|
||||
. '<table:table-row>'
|
||||
. '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>' . __('Name') . '</text:p>'
|
||||
. '</table:table-cell>'
|
||||
. '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>' . __('Time') . '</text:p>'
|
||||
. '</table:table-cell>'
|
||||
. '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>' . __('Event') . '</text:p>'
|
||||
. '</table:table-cell>'
|
||||
. '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>' . __('Definition') . '</text:p>'
|
||||
. '</table:table-cell>'
|
||||
. '</table:table-row>';
|
||||
|
||||
$triggers = $dbi->getTriggers($db, $table);
|
||||
|
||||
foreach ($triggers as $trigger) {
|
||||
$GLOBALS['odt_buffer'] .= '<table:table-row>';
|
||||
$GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>'
|
||||
. htmlspecialchars($trigger['name'])
|
||||
. '</text:p>'
|
||||
. '</table:table-cell>';
|
||||
$GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>'
|
||||
. htmlspecialchars($trigger['action_timing'])
|
||||
. '</text:p>'
|
||||
. '</table:table-cell>';
|
||||
$GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>'
|
||||
. htmlspecialchars($trigger['event_manipulation'])
|
||||
. '</text:p>'
|
||||
. '</table:table-cell>';
|
||||
$GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>'
|
||||
. htmlspecialchars($trigger['definition'])
|
||||
. '</text:p>'
|
||||
. '</table:table-cell>';
|
||||
$GLOBALS['odt_buffer'] .= '</table:table-row>';
|
||||
}
|
||||
|
||||
$GLOBALS['odt_buffer'] .= '</table:table>';
|
||||
|
||||
return $GLOBALS['odt_buffer'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs table's structure
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
* @param string $crlf the end of line sequence
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string $exportMode 'create_table', 'triggers', 'create_view',
|
||||
* 'stand_in'
|
||||
* @param string $exportType 'server', 'database', 'table'
|
||||
* @param bool $do_relation whether to include relation comments
|
||||
* @param bool $do_comments whether to include the pmadb-style column
|
||||
* comments as comments in the structure;
|
||||
* this is deprecated but the parameter is
|
||||
* left here because /export calls
|
||||
* PMA_exportStructure() also for other
|
||||
* @param bool $do_mime whether to include mime comments
|
||||
* @param bool $dates whether to include creation/update/check dates
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*/
|
||||
public function exportStructure(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$exportMode,
|
||||
$exportType,
|
||||
$do_relation = false,
|
||||
$do_comments = false,
|
||||
$do_mime = false,
|
||||
$dates = false,
|
||||
array $aliases = []
|
||||
): bool {
|
||||
global $dbi;
|
||||
|
||||
$db_alias = $db;
|
||||
$table_alias = $table;
|
||||
$this->initAlias($aliases, $db_alias, $table_alias);
|
||||
switch ($exportMode) {
|
||||
case 'create_table':
|
||||
$GLOBALS['odt_buffer'] .= '<text:h text:outline-level="2" text:style-name="Heading_2"'
|
||||
. ' text:is-list-header="true">'
|
||||
. __('Table structure for table') . ' ' .
|
||||
htmlspecialchars($table_alias)
|
||||
. '</text:h>';
|
||||
$this->getTableDef(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$do_relation,
|
||||
$do_comments,
|
||||
$do_mime,
|
||||
$dates,
|
||||
true,
|
||||
false,
|
||||
$aliases
|
||||
);
|
||||
break;
|
||||
case 'triggers':
|
||||
$triggers = $dbi->getTriggers($db, $table);
|
||||
if ($triggers) {
|
||||
$GLOBALS['odt_buffer'] .= '<text:h text:outline-level="2" text:style-name="Heading_2"'
|
||||
. ' text:is-list-header="true">'
|
||||
. __('Triggers') . ' '
|
||||
. htmlspecialchars($table_alias)
|
||||
. '</text:h>';
|
||||
$this->getTriggers($db, $table);
|
||||
}
|
||||
|
||||
break;
|
||||
case 'create_view':
|
||||
$GLOBALS['odt_buffer'] .= '<text:h text:outline-level="2" text:style-name="Heading_2"'
|
||||
. ' text:is-list-header="true">'
|
||||
. __('Structure for view') . ' '
|
||||
. htmlspecialchars($table_alias)
|
||||
. '</text:h>';
|
||||
$this->getTableDef(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$do_relation,
|
||||
$do_comments,
|
||||
$do_mime,
|
||||
$dates,
|
||||
true,
|
||||
true,
|
||||
$aliases
|
||||
);
|
||||
break;
|
||||
case 'stand_in':
|
||||
$GLOBALS['odt_buffer'] .= '<text:h text:outline-level="2" text:style-name="Heading_2"'
|
||||
. ' text:is-list-header="true">'
|
||||
. __('Stand-in structure for view') . ' '
|
||||
. htmlspecialchars($table_alias)
|
||||
. '</text:h>';
|
||||
// export a stand-in definition to resolve view dependencies
|
||||
$this->getTableDefStandIn($db, $table, $crlf, $aliases);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the definition for one column
|
||||
*
|
||||
* @param array $column info about this column
|
||||
* @param string $col_as column alias
|
||||
*
|
||||
* @return string Formatted column definition
|
||||
*/
|
||||
protected function formatOneColumnDefinition($column, $col_as = '')
|
||||
{
|
||||
if (empty($col_as)) {
|
||||
$col_as = $column['Field'];
|
||||
}
|
||||
|
||||
$definition = '<table:table-row>';
|
||||
$definition .= '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>' . htmlspecialchars($col_as) . '</text:p>'
|
||||
. '</table:table-cell>';
|
||||
|
||||
$extracted_columnspec = Util::extractColumnSpec($column['Type']);
|
||||
$type = htmlspecialchars($extracted_columnspec['print_type']);
|
||||
if (empty($type)) {
|
||||
$type = ' ';
|
||||
}
|
||||
|
||||
$definition .= '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>' . htmlspecialchars($type) . '</text:p>'
|
||||
. '</table:table-cell>';
|
||||
if (! isset($column['Default'])) {
|
||||
if ($column['Null'] !== 'NO') {
|
||||
$column['Default'] = 'NULL';
|
||||
} else {
|
||||
$column['Default'] = '';
|
||||
}
|
||||
}
|
||||
|
||||
$definition .= '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>'
|
||||
. ($column['Null'] == '' || $column['Null'] === 'NO'
|
||||
? __('No')
|
||||
: __('Yes'))
|
||||
. '</text:p>'
|
||||
. '</table:table-cell>';
|
||||
$definition .= '<table:table-cell office:value-type="string">'
|
||||
. '<text:p>' . htmlspecialchars($column['Default']) . '</text:p>'
|
||||
. '</table:table-cell>';
|
||||
|
||||
return $definition;
|
||||
}
|
||||
}
|
337
admin/phpMyAdmin/libraries/classes/Plugins/Export/ExportPdf.php
Normal file
337
admin/phpMyAdmin/libraries/classes/Plugins/Export/ExportPdf.php
Normal file
|
@ -0,0 +1,337 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Plugins\Export;
|
||||
|
||||
use PhpMyAdmin\Plugins\Export\Helpers\Pdf;
|
||||
use PhpMyAdmin\Plugins\ExportPlugin;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup;
|
||||
use PhpMyAdmin\Properties\Options\Items\RadioPropertyItem;
|
||||
use PhpMyAdmin\Properties\Options\Items\TextPropertyItem;
|
||||
use PhpMyAdmin\Properties\Plugins\ExportPluginProperties;
|
||||
use TCPDF;
|
||||
|
||||
use function __;
|
||||
use function class_exists;
|
||||
|
||||
/**
|
||||
* Produce a PDF report (export) from a query
|
||||
*/
|
||||
class ExportPdf extends ExportPlugin
|
||||
{
|
||||
/**
|
||||
* PhpMyAdmin\Plugins\Export\Helpers\Pdf instance
|
||||
*
|
||||
* @var Pdf
|
||||
*/
|
||||
private $pdf;
|
||||
|
||||
/**
|
||||
* PDF Report Title
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $pdfReportTitle = '';
|
||||
|
||||
/**
|
||||
* @psalm-return non-empty-lowercase-string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
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();
|
||||
$exportPluginProperties->setText('PDF');
|
||||
$exportPluginProperties->setExtension('pdf');
|
||||
$exportPluginProperties->setMimeType('application/pdf');
|
||||
$exportPluginProperties->setForceFile(true);
|
||||
$exportPluginProperties->setOptionsText(__('Options'));
|
||||
|
||||
// create the root group that will be the options field for
|
||||
// $exportPluginProperties
|
||||
// this will be shown as "Format specific options"
|
||||
$exportSpecificOptions = new OptionsPropertyRootGroup('Format Specific Options');
|
||||
|
||||
// general options main group
|
||||
$generalOptions = new OptionsPropertyMainGroup('general_opts');
|
||||
// create primary items and add them to the group
|
||||
$leaf = new TextPropertyItem(
|
||||
'report_title',
|
||||
__('Report title:')
|
||||
);
|
||||
$generalOptions->addProperty($leaf);
|
||||
// add the group to the root group
|
||||
$exportSpecificOptions->addProperty($generalOptions);
|
||||
|
||||
// what to dump (structure/data/both) main group
|
||||
$dumpWhat = new OptionsPropertyMainGroup(
|
||||
'dump_what',
|
||||
__('Dump table')
|
||||
);
|
||||
$leaf = new RadioPropertyItem('structure_or_data');
|
||||
$leaf->setValues(
|
||||
[
|
||||
'structure' => __('structure'),
|
||||
'data' => __('data'),
|
||||
'structure_and_data' => __('structure and data'),
|
||||
]
|
||||
);
|
||||
$dumpWhat->addProperty($leaf);
|
||||
// add the group to the root group
|
||||
$exportSpecificOptions->addProperty($dumpWhat);
|
||||
|
||||
// set the options for the export plugin property item
|
||||
$exportPluginProperties->setOptions($exportSpecificOptions);
|
||||
|
||||
return $exportPluginProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export header
|
||||
*/
|
||||
public function exportHeader(): bool
|
||||
{
|
||||
$pdf = $this->getPdf();
|
||||
$pdf->Open();
|
||||
|
||||
$pdf->setTitleFontSize(18);
|
||||
$pdf->setTitleText($this->pdfReportTitle);
|
||||
$pdf->setTopMargin(30);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export footer
|
||||
*/
|
||||
public function exportFooter(): bool
|
||||
{
|
||||
$pdf = $this->getPdf();
|
||||
|
||||
// instead of $pdf->Output():
|
||||
return $this->export->outputHandler($pdf->getPDFData());
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database header
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $dbAlias Aliases of db
|
||||
*/
|
||||
public function exportDBHeader($db, $dbAlias = ''): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database footer
|
||||
*
|
||||
* @param string $db Database name
|
||||
*/
|
||||
public function exportDBFooter($db): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs CREATE DATABASE statement
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $exportType 'server', 'database', 'table'
|
||||
* @param string $dbAlias Aliases of db
|
||||
*/
|
||||
public function exportDBCreate($db, $exportType, $dbAlias = ''): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the content of a table in NHibernate format
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
* @param string $crlf the end of line sequence
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string $sqlQuery SQL query for obtaining data
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*/
|
||||
public function exportData(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$sqlQuery,
|
||||
array $aliases = []
|
||||
): bool {
|
||||
$db_alias = $db;
|
||||
$table_alias = $table;
|
||||
$this->initAlias($aliases, $db_alias, $table_alias);
|
||||
$pdf = $this->getPdf();
|
||||
$pdf->setCurrentDb($db);
|
||||
$pdf->setCurrentTable($table);
|
||||
$pdf->setDbAlias($db_alias);
|
||||
$pdf->setTableAlias($table_alias);
|
||||
$pdf->setAliases($aliases);
|
||||
$pdf->setPurpose(__('Dumping data'));
|
||||
$pdf->mysqlReport($sqlQuery);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs result of raw query in PDF format
|
||||
*
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string|null $db the database where the query is executed
|
||||
* @param string $sqlQuery the rawquery to output
|
||||
* @param string $crlf the end of line sequence
|
||||
*/
|
||||
public function exportRawQuery(string $errorUrl, ?string $db, string $sqlQuery, string $crlf): bool
|
||||
{
|
||||
global $dbi;
|
||||
|
||||
$pdf = $this->getPdf();
|
||||
$pdf->setDbAlias('----');
|
||||
$pdf->setTableAlias('----');
|
||||
$pdf->setPurpose(__('Query result data'));
|
||||
|
||||
if ($db !== null) {
|
||||
$pdf->setCurrentDb($db);
|
||||
$dbi->selectDb($db);
|
||||
}
|
||||
|
||||
$pdf->mysqlReport($sqlQuery);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs table structure
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
* @param string $crlf the end of line sequence
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string $exportMode 'create_table', 'triggers', 'create_view',
|
||||
* 'stand_in'
|
||||
* @param string $exportType 'server', 'database', 'table'
|
||||
* @param bool $do_relation whether to include relation comments
|
||||
* @param bool $do_comments whether to include the pmadb-style column
|
||||
* comments as comments in the structure;
|
||||
* this is deprecated but the parameter is
|
||||
* left here because /export calls
|
||||
* PMA_exportStructure() also for other
|
||||
* export types which use this parameter
|
||||
* @param bool $do_mime whether to include mime comments
|
||||
* @param bool $dates whether to include creation/update/check dates
|
||||
* @param array $aliases aliases for db/table/columns
|
||||
*/
|
||||
public function exportStructure(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$exportMode,
|
||||
$exportType,
|
||||
$do_relation = false,
|
||||
$do_comments = false,
|
||||
$do_mime = false,
|
||||
$dates = false,
|
||||
array $aliases = []
|
||||
): bool {
|
||||
$db_alias = $db;
|
||||
$table_alias = $table;
|
||||
$purpose = '';
|
||||
$this->initAlias($aliases, $db_alias, $table_alias);
|
||||
$pdf = $this->getPdf();
|
||||
// getting purpose to show at top
|
||||
switch ($exportMode) {
|
||||
case 'create_table':
|
||||
$purpose = __('Table structure');
|
||||
break;
|
||||
case 'triggers':
|
||||
$purpose = __('Triggers');
|
||||
break;
|
||||
case 'create_view':
|
||||
$purpose = __('View structure');
|
||||
break;
|
||||
case 'stand_in':
|
||||
$purpose = __('Stand in');
|
||||
}
|
||||
|
||||
$pdf->setCurrentDb($db);
|
||||
$pdf->setCurrentTable($table);
|
||||
$pdf->setDbAlias($db_alias);
|
||||
$pdf->setTableAlias($table_alias);
|
||||
$pdf->setAliases($aliases);
|
||||
$pdf->setPurpose($purpose);
|
||||
|
||||
/**
|
||||
* comment display set true as presently in pdf
|
||||
* format, no option is present to take user input.
|
||||
*/
|
||||
$do_comments = true;
|
||||
switch ($exportMode) {
|
||||
case 'create_table':
|
||||
$pdf->getTableDef($db, $table, $do_relation, $do_comments, $do_mime, false, $aliases);
|
||||
break;
|
||||
case 'triggers':
|
||||
$pdf->getTriggers($db, $table);
|
||||
break;
|
||||
case 'create_view':
|
||||
$pdf->getTableDef($db, $table, $do_relation, $do_comments, $do_mime, false, $aliases);
|
||||
break;
|
||||
case 'stand_in':
|
||||
/* export a stand-in definition to resolve view dependencies
|
||||
* Yet to develop this function
|
||||
* $pdf->getTableDefStandIn($db, $table, $crlf);
|
||||
*/
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
/**
|
||||
* Gets the PhpMyAdmin\Plugins\Export\Helpers\Pdf instance
|
||||
*
|
||||
* @return Pdf
|
||||
*/
|
||||
private function getPdf()
|
||||
{
|
||||
return $this->pdf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates the PhpMyAdmin\Plugins\Export\Helpers\Pdf class
|
||||
*
|
||||
* @param Pdf $pdf The instance
|
||||
*/
|
||||
private function setPdf($pdf): void
|
||||
{
|
||||
$this->pdf = $pdf;
|
||||
}
|
||||
|
||||
public static function isAvailable(): bool
|
||||
{
|
||||
return class_exists(TCPDF::class);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,256 @@
|
|||
<?php
|
||||
/**
|
||||
* Set of functions used to build dumps of tables as PHP Arrays
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Plugins\Export;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Plugins\ExportPlugin;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup;
|
||||
use PhpMyAdmin\Properties\Options\Items\HiddenPropertyItem;
|
||||
use PhpMyAdmin\Properties\Plugins\ExportPluginProperties;
|
||||
use PhpMyAdmin\Util;
|
||||
use PhpMyAdmin\Version;
|
||||
|
||||
use function __;
|
||||
use function preg_match;
|
||||
use function preg_replace;
|
||||
use function stripslashes;
|
||||
use function strtr;
|
||||
use function var_export;
|
||||
|
||||
/**
|
||||
* Handles the export for the PHP Array class
|
||||
*/
|
||||
class ExportPhparray extends ExportPlugin
|
||||
{
|
||||
/**
|
||||
* @psalm-return non-empty-lowercase-string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'phparray';
|
||||
}
|
||||
|
||||
protected function setProperties(): ExportPluginProperties
|
||||
{
|
||||
$exportPluginProperties = new ExportPluginProperties();
|
||||
$exportPluginProperties->setText('PHP array');
|
||||
$exportPluginProperties->setExtension('php');
|
||||
$exportPluginProperties->setMimeType('text/plain');
|
||||
$exportPluginProperties->setOptionsText(__('Options'));
|
||||
|
||||
// create the root group that will be the options field for
|
||||
// $exportPluginProperties
|
||||
// this will be shown as "Format specific options"
|
||||
$exportSpecificOptions = new OptionsPropertyRootGroup('Format Specific Options');
|
||||
|
||||
// general options main group
|
||||
$generalOptions = new OptionsPropertyMainGroup('general_opts');
|
||||
// create primary items and add them to the group
|
||||
$leaf = new HiddenPropertyItem('structure_or_data');
|
||||
$generalOptions->addProperty($leaf);
|
||||
// add the main group to the root group
|
||||
$exportSpecificOptions->addProperty($generalOptions);
|
||||
|
||||
// set the options for the export plugin property item
|
||||
$exportPluginProperties->setOptions($exportSpecificOptions);
|
||||
|
||||
return $exportPluginProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes end of comment from a string
|
||||
*
|
||||
* @param string $string String to replace
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function commentString($string)
|
||||
{
|
||||
return strtr($string, '*/', '-');
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export header
|
||||
*/
|
||||
public function exportHeader(): bool
|
||||
{
|
||||
$this->export->outputHandler(
|
||||
'<?php' . $GLOBALS['crlf']
|
||||
. '/**' . $GLOBALS['crlf']
|
||||
. ' * Export to PHP Array plugin for PHPMyAdmin' . $GLOBALS['crlf']
|
||||
. ' * @version ' . Version::VERSION . $GLOBALS['crlf']
|
||||
. ' */' . $GLOBALS['crlf'] . $GLOBALS['crlf']
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export footer
|
||||
*/
|
||||
public function exportFooter(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database header
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $dbAlias Aliases of db
|
||||
*/
|
||||
public function exportDBHeader($db, $dbAlias = ''): bool
|
||||
{
|
||||
if (empty($dbAlias)) {
|
||||
$dbAlias = $db;
|
||||
}
|
||||
|
||||
$this->export->outputHandler(
|
||||
'/**' . $GLOBALS['crlf']
|
||||
. ' * Database ' . $this->commentString(Util::backquote($dbAlias))
|
||||
. $GLOBALS['crlf'] . ' */' . $GLOBALS['crlf']
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database footer
|
||||
*
|
||||
* @param string $db Database name
|
||||
*/
|
||||
public function exportDBFooter($db): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs CREATE DATABASE statement
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $exportType 'server', 'database', 'table'
|
||||
* @param string $dbAlias Aliases of db
|
||||
*/
|
||||
public function exportDBCreate($db, $exportType, $dbAlias = ''): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the content of a table in PHP array format
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
* @param string $crlf the end of line sequence
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string $sqlQuery SQL query for obtaining data
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*/
|
||||
public function exportData(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$sqlQuery,
|
||||
array $aliases = []
|
||||
): bool {
|
||||
global $dbi;
|
||||
|
||||
$db_alias = $db;
|
||||
$table_alias = $table;
|
||||
$this->initAlias($aliases, $db_alias, $table_alias);
|
||||
|
||||
$result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED);
|
||||
|
||||
$columns_cnt = $result->numFields();
|
||||
$columns = [];
|
||||
foreach ($result->getFieldNames() as $i => $col_as) {
|
||||
if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) {
|
||||
$col_as = $aliases[$db]['tables'][$table]['columns'][$col_as];
|
||||
}
|
||||
|
||||
$columns[$i] = stripslashes($col_as);
|
||||
}
|
||||
|
||||
$tablefixed = $table;
|
||||
|
||||
// fix variable names (based on
|
||||
// https://www.php.net/manual/en/language.variables.basics.php)
|
||||
if (! preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $table_alias)) {
|
||||
// fix invalid characters in variable names by replacing them with
|
||||
// underscores
|
||||
$tablefixed = preg_replace('/[^a-zA-Z0-9_\x7f-\xff]/', '_', $table_alias);
|
||||
|
||||
// variable name must not start with a number or dash...
|
||||
if (preg_match('/^[a-zA-Z_\x7f-\xff]/', $tablefixed) === 0) {
|
||||
$tablefixed = '_' . $tablefixed;
|
||||
}
|
||||
}
|
||||
|
||||
$buffer = '';
|
||||
$record_cnt = 0;
|
||||
// Output table name as comment
|
||||
$buffer .= $crlf . '/* '
|
||||
. $this->commentString(Util::backquote($db_alias)) . '.'
|
||||
. $this->commentString(Util::backquote($table_alias)) . ' */' . $crlf;
|
||||
$buffer .= '$' . $tablefixed . ' = array(';
|
||||
if (! $this->export->outputHandler($buffer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reset the buffer
|
||||
$buffer = '';
|
||||
while ($record = $result->fetchRow()) {
|
||||
$record_cnt++;
|
||||
|
||||
if ($record_cnt == 1) {
|
||||
$buffer .= $crlf . ' array(';
|
||||
} else {
|
||||
$buffer .= ',' . $crlf . ' array(';
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $columns_cnt; $i++) {
|
||||
$buffer .= var_export($columns[$i], true)
|
||||
. ' => ' . var_export($record[$i], true)
|
||||
. ($i + 1 >= $columns_cnt ? '' : ',');
|
||||
}
|
||||
|
||||
$buffer .= ')';
|
||||
if (! $this->export->outputHandler($buffer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reset the buffer
|
||||
$buffer = '';
|
||||
}
|
||||
|
||||
$buffer .= $crlf . ');' . $crlf;
|
||||
|
||||
return $this->export->outputHandler($buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs result of raw query as PHP array
|
||||
*
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string|null $db the database where the query is executed
|
||||
* @param string $sqlQuery the rawquery to output
|
||||
* @param string $crlf the end of line sequence
|
||||
*/
|
||||
public function exportRawQuery(string $errorUrl, ?string $db, string $sqlQuery, string $crlf): bool
|
||||
{
|
||||
global $dbi;
|
||||
|
||||
if ($db !== null) {
|
||||
$dbi->selectDb($db);
|
||||
}
|
||||
|
||||
return $this->exportData($db ?? '', '', $crlf, $errorUrl, $sqlQuery);
|
||||
}
|
||||
}
|
2848
admin/phpMyAdmin/libraries/classes/Plugins/Export/ExportSql.php
Normal file
2848
admin/phpMyAdmin/libraries/classes/Plugins/Export/ExportSql.php
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,632 @@
|
|||
<?php
|
||||
/**
|
||||
* Export to Texy! text.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Plugins\Export;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Plugins\ExportPlugin;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup;
|
||||
use PhpMyAdmin\Properties\Options\Items\BoolPropertyItem;
|
||||
use PhpMyAdmin\Properties\Options\Items\RadioPropertyItem;
|
||||
use PhpMyAdmin\Properties\Options\Items\TextPropertyItem;
|
||||
use PhpMyAdmin\Properties\Plugins\ExportPluginProperties;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function __;
|
||||
use function htmlspecialchars;
|
||||
use function in_array;
|
||||
use function str_replace;
|
||||
use function stripslashes;
|
||||
|
||||
/**
|
||||
* Handles the export for the Texy! text class
|
||||
*/
|
||||
class ExportTexytext extends ExportPlugin
|
||||
{
|
||||
/**
|
||||
* @psalm-return non-empty-lowercase-string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'texytext';
|
||||
}
|
||||
|
||||
protected function setProperties(): ExportPluginProperties
|
||||
{
|
||||
$exportPluginProperties = new ExportPluginProperties();
|
||||
$exportPluginProperties->setText('Texy! text');
|
||||
$exportPluginProperties->setExtension('txt');
|
||||
$exportPluginProperties->setMimeType('text/plain');
|
||||
$exportPluginProperties->setOptionsText(__('Options'));
|
||||
|
||||
// create the root group that will be the options field for
|
||||
// $exportPluginProperties
|
||||
// this will be shown as "Format specific options"
|
||||
$exportSpecificOptions = new OptionsPropertyRootGroup('Format Specific Options');
|
||||
|
||||
// what to dump (structure/data/both) main group
|
||||
$dumpWhat = new OptionsPropertyMainGroup(
|
||||
'general_opts',
|
||||
__('Dump table')
|
||||
);
|
||||
// create primary items and add them to the group
|
||||
$leaf = new RadioPropertyItem('structure_or_data');
|
||||
$leaf->setValues(
|
||||
[
|
||||
'structure' => __('structure'),
|
||||
'data' => __('data'),
|
||||
'structure_and_data' => __('structure and data'),
|
||||
]
|
||||
);
|
||||
$dumpWhat->addProperty($leaf);
|
||||
// add the main group to the root group
|
||||
$exportSpecificOptions->addProperty($dumpWhat);
|
||||
|
||||
// data options main group
|
||||
$dataOptions = new OptionsPropertyMainGroup(
|
||||
'data',
|
||||
__('Data dump options')
|
||||
);
|
||||
$dataOptions->setForce('structure');
|
||||
// create primary items and add them to the group
|
||||
$leaf = new BoolPropertyItem(
|
||||
'columns',
|
||||
__('Put columns names in the first row')
|
||||
);
|
||||
$dataOptions->addProperty($leaf);
|
||||
$leaf = new TextPropertyItem(
|
||||
'null',
|
||||
__('Replace NULL with:')
|
||||
);
|
||||
$dataOptions->addProperty($leaf);
|
||||
// add the main group to the root group
|
||||
$exportSpecificOptions->addProperty($dataOptions);
|
||||
|
||||
// set the options for the export plugin property item
|
||||
$exportPluginProperties->setOptions($exportSpecificOptions);
|
||||
|
||||
return $exportPluginProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export header
|
||||
*/
|
||||
public function exportHeader(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export footer
|
||||
*/
|
||||
public function exportFooter(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database header
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $dbAlias Alias of db
|
||||
*/
|
||||
public function exportDBHeader($db, $dbAlias = ''): bool
|
||||
{
|
||||
if (empty($dbAlias)) {
|
||||
$dbAlias = $db;
|
||||
}
|
||||
|
||||
return $this->export->outputHandler(
|
||||
'===' . __('Database') . ' ' . $dbAlias . "\n\n"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database footer
|
||||
*
|
||||
* @param string $db Database name
|
||||
*/
|
||||
public function exportDBFooter($db): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs CREATE DATABASE statement
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $exportType 'server', 'database', 'table'
|
||||
* @param string $dbAlias Aliases of db
|
||||
*/
|
||||
public function exportDBCreate($db, $exportType, $dbAlias = ''): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the content of a table in NHibernate format
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
* @param string $crlf the end of line sequence
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string $sqlQuery SQL query for obtaining data
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*/
|
||||
public function exportData(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$sqlQuery,
|
||||
array $aliases = []
|
||||
): bool {
|
||||
global $what, $dbi;
|
||||
|
||||
$db_alias = $db;
|
||||
$table_alias = $table;
|
||||
$this->initAlias($aliases, $db_alias, $table_alias);
|
||||
|
||||
if (
|
||||
! $this->export->outputHandler(
|
||||
$table_alias != ''
|
||||
? '== ' . __('Dumping data for table') . ' ' . $table_alias . "\n\n"
|
||||
: '==' . __('Dumping data for query result') . "\n\n"
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Gets the data from the database
|
||||
$result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED);
|
||||
$fields_cnt = $result->numFields();
|
||||
|
||||
// If required, get fields name at the first line
|
||||
if (isset($GLOBALS[$what . '_columns'])) {
|
||||
$text_output = "|------\n";
|
||||
foreach ($result->getFieldNames() as $col_as) {
|
||||
if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) {
|
||||
$col_as = $aliases[$db]['tables'][$table]['columns'][$col_as];
|
||||
}
|
||||
|
||||
$text_output .= '|'
|
||||
. htmlspecialchars(stripslashes($col_as));
|
||||
}
|
||||
|
||||
$text_output .= "\n|------\n";
|
||||
if (! $this->export->outputHandler($text_output)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Format the data
|
||||
while ($row = $result->fetchRow()) {
|
||||
$text_output = '';
|
||||
for ($j = 0; $j < $fields_cnt; $j++) {
|
||||
if (! isset($row[$j])) {
|
||||
$value = $GLOBALS[$what . '_null'];
|
||||
} elseif ($row[$j] == '0' || $row[$j] != '') {
|
||||
$value = $row[$j];
|
||||
} else {
|
||||
$value = ' ';
|
||||
}
|
||||
|
||||
$text_output .= '|'
|
||||
. str_replace(
|
||||
'|',
|
||||
'|',
|
||||
htmlspecialchars($value)
|
||||
);
|
||||
}
|
||||
|
||||
$text_output .= "\n";
|
||||
if (! $this->export->outputHandler($text_output)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs result raw query in TexyText format
|
||||
*
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string|null $db the database where the query is executed
|
||||
* @param string $sqlQuery the rawquery to output
|
||||
* @param string $crlf the end of line sequence
|
||||
*/
|
||||
public function exportRawQuery(string $errorUrl, ?string $db, string $sqlQuery, string $crlf): bool
|
||||
{
|
||||
global $dbi;
|
||||
|
||||
if ($db !== null) {
|
||||
$dbi->selectDb($db);
|
||||
}
|
||||
|
||||
return $this->exportData($db ?? '', '', $crlf, $errorUrl, $sqlQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a stand-in CREATE definition to resolve view dependencies
|
||||
*
|
||||
* @param string $db the database name
|
||||
* @param string $view the view name
|
||||
* @param string $crlf the end of line sequence
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*
|
||||
* @return string resulting definition
|
||||
*/
|
||||
public function getTableDefStandIn($db, $view, $crlf, $aliases = [])
|
||||
{
|
||||
global $dbi;
|
||||
|
||||
$text_output = '';
|
||||
|
||||
/**
|
||||
* Get the unique keys in the table
|
||||
*/
|
||||
$unique_keys = [];
|
||||
$keys = $dbi->getTableIndexes($db, $view);
|
||||
foreach ($keys as $key) {
|
||||
if ($key['Non_unique'] != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$unique_keys[] = $key['Column_name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets fields properties
|
||||
*/
|
||||
$dbi->selectDb($db);
|
||||
|
||||
/**
|
||||
* Displays the table structure
|
||||
*/
|
||||
|
||||
$text_output .= "|------\n"
|
||||
. '|' . __('Column')
|
||||
. '|' . __('Type')
|
||||
. '|' . __('Null')
|
||||
. '|' . __('Default')
|
||||
. "\n|------\n";
|
||||
|
||||
$columns = $dbi->getColumns($db, $view);
|
||||
foreach ($columns as $column) {
|
||||
$col_as = $column['Field'] ?? null;
|
||||
if (! empty($aliases[$db]['tables'][$view]['columns'][$col_as])) {
|
||||
$col_as = $aliases[$db]['tables'][$view]['columns'][$col_as];
|
||||
}
|
||||
|
||||
$text_output .= $this->formatOneColumnDefinition($column, $unique_keys, $col_as);
|
||||
$text_output .= "\n";
|
||||
}
|
||||
|
||||
return $text_output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns $table's CREATE definition
|
||||
*
|
||||
* @param string $db the database name
|
||||
* @param string $table the table name
|
||||
* @param string $crlf the end of line sequence
|
||||
* @param string $error_url the url to go back in case of error
|
||||
* @param bool $do_relation whether to include relation comments
|
||||
* @param bool $do_comments whether to include the pmadb-style column
|
||||
* comments as comments in the structure;
|
||||
* this is deprecated but the parameter is
|
||||
* left here because /export calls
|
||||
* $this->exportStructure() also for other
|
||||
* export types which use this parameter
|
||||
* @param bool $do_mime whether to include mime comments
|
||||
* @param bool $show_dates whether to include creation/update/check dates
|
||||
* @param bool $add_semicolon whether to add semicolon and end-of-line
|
||||
* at the end
|
||||
* @param bool $view whether we're handling a view
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*
|
||||
* @return string resulting schema
|
||||
*/
|
||||
public function getTableDef(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
$error_url,
|
||||
$do_relation,
|
||||
$do_comments,
|
||||
$do_mime,
|
||||
$show_dates = false,
|
||||
$add_semicolon = true,
|
||||
$view = false,
|
||||
array $aliases = []
|
||||
) {
|
||||
global $dbi;
|
||||
|
||||
$relationParameters = $this->relation->getRelationParameters();
|
||||
|
||||
$text_output = '';
|
||||
|
||||
/**
|
||||
* Get the unique keys in the table
|
||||
*/
|
||||
$unique_keys = [];
|
||||
$keys = $dbi->getTableIndexes($db, $table);
|
||||
foreach ($keys as $key) {
|
||||
if ($key['Non_unique'] != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$unique_keys[] = $key['Column_name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets fields properties
|
||||
*/
|
||||
$dbi->selectDb($db);
|
||||
|
||||
// Check if we can use Relations
|
||||
[$res_rel, $have_rel] = $this->relation->getRelationsAndStatus(
|
||||
$do_relation && $relationParameters->relationFeature !== null,
|
||||
$db,
|
||||
$table
|
||||
);
|
||||
|
||||
/**
|
||||
* Displays the table structure
|
||||
*/
|
||||
|
||||
$text_output .= "|------\n";
|
||||
$text_output .= '|' . __('Column');
|
||||
$text_output .= '|' . __('Type');
|
||||
$text_output .= '|' . __('Null');
|
||||
$text_output .= '|' . __('Default');
|
||||
if ($do_relation && $have_rel) {
|
||||
$text_output .= '|' . __('Links to');
|
||||
}
|
||||
|
||||
if ($do_comments) {
|
||||
$text_output .= '|' . __('Comments');
|
||||
$comments = $this->relation->getComments($db, $table);
|
||||
}
|
||||
|
||||
if ($do_mime && $relationParameters->browserTransformationFeature !== null) {
|
||||
$text_output .= '|' . __('Media type');
|
||||
$mime_map = $this->transformations->getMime($db, $table, true);
|
||||
}
|
||||
|
||||
$text_output .= "\n|------\n";
|
||||
|
||||
$columns = $dbi->getColumns($db, $table);
|
||||
foreach ($columns as $column) {
|
||||
$col_as = $column['Field'];
|
||||
if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) {
|
||||
$col_as = $aliases[$db]['tables'][$table]['columns'][$col_as];
|
||||
}
|
||||
|
||||
$text_output .= $this->formatOneColumnDefinition($column, $unique_keys, $col_as);
|
||||
$field_name = $column['Field'];
|
||||
if ($do_relation && $have_rel) {
|
||||
$text_output .= '|' . htmlspecialchars(
|
||||
$this->getRelationString(
|
||||
$res_rel,
|
||||
$field_name,
|
||||
$db,
|
||||
$aliases
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ($do_comments && $relationParameters->columnCommentsFeature !== null) {
|
||||
$text_output .= '|'
|
||||
. (isset($comments[$field_name])
|
||||
? htmlspecialchars($comments[$field_name])
|
||||
: '');
|
||||
}
|
||||
|
||||
if ($do_mime && $relationParameters->browserTransformationFeature !== null) {
|
||||
$text_output .= '|'
|
||||
. (isset($mime_map[$field_name])
|
||||
? htmlspecialchars(
|
||||
str_replace('_', '/', $mime_map[$field_name]['mimetype'])
|
||||
)
|
||||
: '');
|
||||
}
|
||||
|
||||
$text_output .= "\n";
|
||||
}
|
||||
|
||||
return $text_output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs triggers
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
*
|
||||
* @return string Formatted triggers list
|
||||
*/
|
||||
public function getTriggers($db, $table)
|
||||
{
|
||||
global $dbi;
|
||||
|
||||
$dump = "|------\n";
|
||||
$dump .= '|' . __('Name');
|
||||
$dump .= '|' . __('Time');
|
||||
$dump .= '|' . __('Event');
|
||||
$dump .= '|' . __('Definition');
|
||||
$dump .= "\n|------\n";
|
||||
|
||||
$triggers = $dbi->getTriggers($db, $table);
|
||||
|
||||
foreach ($triggers as $trigger) {
|
||||
$dump .= '|' . $trigger['name'];
|
||||
$dump .= '|' . $trigger['action_timing'];
|
||||
$dump .= '|' . $trigger['event_manipulation'];
|
||||
$dump .= '|' .
|
||||
str_replace(
|
||||
'|',
|
||||
'|',
|
||||
htmlspecialchars($trigger['definition'])
|
||||
);
|
||||
$dump .= "\n";
|
||||
}
|
||||
|
||||
return $dump;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs table's structure
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
* @param string $crlf the end of line sequence
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string $exportMode 'create_table', 'triggers', 'create_view',
|
||||
* 'stand_in'
|
||||
* @param string $exportType 'server', 'database', 'table'
|
||||
* @param bool $do_relation whether to include relation comments
|
||||
* @param bool $do_comments whether to include the pmadb-style column
|
||||
* comments as comments in the structure;
|
||||
* this is deprecated but the parameter is
|
||||
* left here because /export calls
|
||||
* $this->exportStructure() also for other
|
||||
* export types which use this parameter
|
||||
* @param bool $do_mime whether to include mime comments
|
||||
* @param bool $dates whether to include creation/update/check dates
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*/
|
||||
public function exportStructure(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$exportMode,
|
||||
$exportType,
|
||||
$do_relation = false,
|
||||
$do_comments = false,
|
||||
$do_mime = false,
|
||||
$dates = false,
|
||||
array $aliases = []
|
||||
): bool {
|
||||
global $dbi;
|
||||
|
||||
$db_alias = $db;
|
||||
$table_alias = $table;
|
||||
$this->initAlias($aliases, $db_alias, $table_alias);
|
||||
$dump = '';
|
||||
|
||||
switch ($exportMode) {
|
||||
case 'create_table':
|
||||
$dump .= '== ' . __('Table structure for table') . ' '
|
||||
. $table_alias . "\n\n";
|
||||
$dump .= $this->getTableDef(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$do_relation,
|
||||
$do_comments,
|
||||
$do_mime,
|
||||
$dates,
|
||||
true,
|
||||
false,
|
||||
$aliases
|
||||
);
|
||||
break;
|
||||
case 'triggers':
|
||||
$dump = '';
|
||||
$triggers = $dbi->getTriggers($db, $table);
|
||||
if ($triggers) {
|
||||
$dump .= '== ' . __('Triggers') . ' ' . $table_alias . "\n\n";
|
||||
$dump .= $this->getTriggers($db, $table);
|
||||
}
|
||||
|
||||
break;
|
||||
case 'create_view':
|
||||
$dump .= '== ' . __('Structure for view') . ' ' . $table_alias . "\n\n";
|
||||
$dump .= $this->getTableDef(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$do_relation,
|
||||
$do_comments,
|
||||
$do_mime,
|
||||
$dates,
|
||||
true,
|
||||
true,
|
||||
$aliases
|
||||
);
|
||||
break;
|
||||
case 'stand_in':
|
||||
$dump .= '== ' . __('Stand-in structure for view')
|
||||
. ' ' . $table . "\n\n";
|
||||
// export a stand-in definition to resolve view dependencies
|
||||
$dump .= $this->getTableDefStandIn($db, $table, $crlf, $aliases);
|
||||
}
|
||||
|
||||
return $this->export->outputHandler($dump);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the definition for one column
|
||||
*
|
||||
* @param array $column info about this column
|
||||
* @param array $unique_keys unique keys for this table
|
||||
* @param string $col_alias Column Alias
|
||||
*
|
||||
* @return string Formatted column definition
|
||||
*/
|
||||
public function formatOneColumnDefinition(
|
||||
$column,
|
||||
$unique_keys,
|
||||
$col_alias = ''
|
||||
) {
|
||||
if (empty($col_alias)) {
|
||||
$col_alias = $column['Field'];
|
||||
}
|
||||
|
||||
$extracted_columnspec = Util::extractColumnSpec($column['Type']);
|
||||
$type = $extracted_columnspec['print_type'];
|
||||
if (empty($type)) {
|
||||
$type = ' ';
|
||||
}
|
||||
|
||||
if (! isset($column['Default'])) {
|
||||
if ($column['Null'] !== 'NO') {
|
||||
$column['Default'] = 'NULL';
|
||||
}
|
||||
}
|
||||
|
||||
$fmt_pre = '';
|
||||
$fmt_post = '';
|
||||
if (in_array($column['Field'], $unique_keys)) {
|
||||
$fmt_pre = '**' . $fmt_pre;
|
||||
$fmt_post .= '**';
|
||||
}
|
||||
|
||||
if ($column['Key'] === 'PRI') {
|
||||
$fmt_pre = '//' . $fmt_pre;
|
||||
$fmt_post .= '//';
|
||||
}
|
||||
|
||||
$definition = '|'
|
||||
. $fmt_pre . htmlspecialchars($col_alias) . $fmt_post;
|
||||
$definition .= '|' . htmlspecialchars($type);
|
||||
$definition .= '|'
|
||||
. ($column['Null'] == '' || $column['Null'] === 'NO'
|
||||
? __('No') : __('Yes'));
|
||||
$definition .= '|'
|
||||
. htmlspecialchars($column['Default'] ?? '');
|
||||
|
||||
return $definition;
|
||||
}
|
||||
}
|
553
admin/phpMyAdmin/libraries/classes/Plugins/Export/ExportXml.php
Normal file
553
admin/phpMyAdmin/libraries/classes/Plugins/Export/ExportXml.php
Normal file
|
@ -0,0 +1,553 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Plugins\Export;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Plugins\ExportPlugin;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup;
|
||||
use PhpMyAdmin\Properties\Options\Items\BoolPropertyItem;
|
||||
use PhpMyAdmin\Properties\Options\Items\HiddenPropertyItem;
|
||||
use PhpMyAdmin\Properties\Plugins\ExportPluginProperties;
|
||||
use PhpMyAdmin\Util;
|
||||
use PhpMyAdmin\Version;
|
||||
|
||||
use function __;
|
||||
use function count;
|
||||
use function htmlspecialchars;
|
||||
use function is_array;
|
||||
use function mb_substr;
|
||||
use function rtrim;
|
||||
use function str_replace;
|
||||
use function stripslashes;
|
||||
use function strlen;
|
||||
|
||||
use const PHP_VERSION;
|
||||
|
||||
/**
|
||||
* Used to build XML dumps of tables
|
||||
*/
|
||||
class ExportXml extends ExportPlugin
|
||||
{
|
||||
/**
|
||||
* Table name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $table;
|
||||
/**
|
||||
* Table names
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $tables = [];
|
||||
|
||||
/**
|
||||
* @psalm-return non-empty-lowercase-string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'xml';
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the local variables that are used for export XML
|
||||
*/
|
||||
private function initSpecificVariables(): void
|
||||
{
|
||||
global $table, $tables;
|
||||
$this->setTable($table);
|
||||
if (! is_array($tables)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->setTables($tables);
|
||||
}
|
||||
|
||||
protected function setProperties(): ExportPluginProperties
|
||||
{
|
||||
// create the export plugin property item
|
||||
$exportPluginProperties = new ExportPluginProperties();
|
||||
$exportPluginProperties->setText('XML');
|
||||
$exportPluginProperties->setExtension('xml');
|
||||
$exportPluginProperties->setMimeType('text/xml');
|
||||
$exportPluginProperties->setOptionsText(__('Options'));
|
||||
|
||||
// create the root group that will be the options field for
|
||||
// $exportPluginProperties
|
||||
// this will be shown as "Format specific options"
|
||||
$exportSpecificOptions = new OptionsPropertyRootGroup('Format Specific Options');
|
||||
|
||||
// general options main group
|
||||
$generalOptions = new OptionsPropertyMainGroup('general_opts');
|
||||
// create primary items and add them to the group
|
||||
$leaf = new HiddenPropertyItem('structure_or_data');
|
||||
$generalOptions->addProperty($leaf);
|
||||
// add the main group to the root group
|
||||
$exportSpecificOptions->addProperty($generalOptions);
|
||||
|
||||
// export structure main group
|
||||
$structure = new OptionsPropertyMainGroup(
|
||||
'structure',
|
||||
__('Object creation options (all are recommended)')
|
||||
);
|
||||
|
||||
// create primary items and add them to the group
|
||||
$leaf = new BoolPropertyItem(
|
||||
'export_events',
|
||||
__('Events')
|
||||
);
|
||||
$structure->addProperty($leaf);
|
||||
$leaf = new BoolPropertyItem(
|
||||
'export_functions',
|
||||
__('Functions')
|
||||
);
|
||||
$structure->addProperty($leaf);
|
||||
$leaf = new BoolPropertyItem(
|
||||
'export_procedures',
|
||||
__('Procedures')
|
||||
);
|
||||
$structure->addProperty($leaf);
|
||||
$leaf = new BoolPropertyItem(
|
||||
'export_tables',
|
||||
__('Tables')
|
||||
);
|
||||
$structure->addProperty($leaf);
|
||||
$leaf = new BoolPropertyItem(
|
||||
'export_triggers',
|
||||
__('Triggers')
|
||||
);
|
||||
$structure->addProperty($leaf);
|
||||
$leaf = new BoolPropertyItem(
|
||||
'export_views',
|
||||
__('Views')
|
||||
);
|
||||
$structure->addProperty($leaf);
|
||||
$exportSpecificOptions->addProperty($structure);
|
||||
|
||||
// data main group
|
||||
$data = new OptionsPropertyMainGroup(
|
||||
'data',
|
||||
__('Data dump options')
|
||||
);
|
||||
// create primary items and add them to the group
|
||||
$leaf = new BoolPropertyItem(
|
||||
'export_contents',
|
||||
__('Export contents')
|
||||
);
|
||||
$data->addProperty($leaf);
|
||||
$exportSpecificOptions->addProperty($data);
|
||||
|
||||
// set the options for the export plugin property item
|
||||
$exportPluginProperties->setOptions($exportSpecificOptions);
|
||||
|
||||
return $exportPluginProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates output for SQL defintions of routines
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $type Item type to be used in XML output
|
||||
* @param string $dbitype Item type used in DBI queries
|
||||
*
|
||||
* @return string XML with definitions
|
||||
*/
|
||||
private function exportRoutinesDefinition($db, $type, $dbitype)
|
||||
{
|
||||
global $dbi;
|
||||
|
||||
// Export routines
|
||||
$routines = $dbi->getProceduresOrFunctions($db, $dbitype);
|
||||
|
||||
return $this->exportDefinitions($db, $type, $dbitype, $routines);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates output for SQL defintions
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $type Item type to be used in XML output
|
||||
* @param string $dbitype Item type used in DBI queries
|
||||
* @param array $names Names of items to export
|
||||
*
|
||||
* @return string XML with definitions
|
||||
*/
|
||||
private function exportDefinitions($db, $type, $dbitype, array $names)
|
||||
{
|
||||
global $crlf, $dbi;
|
||||
|
||||
$head = '';
|
||||
|
||||
if ($names) {
|
||||
foreach ($names as $name) {
|
||||
$head .= ' <pma:' . $type . ' name="'
|
||||
. htmlspecialchars($name) . '">' . $crlf;
|
||||
|
||||
// Do some formatting
|
||||
$sql = $dbi->getDefinition($db, $dbitype, $name);
|
||||
$sql = htmlspecialchars(rtrim($sql));
|
||||
$sql = str_replace("\n", "\n ", $sql);
|
||||
|
||||
$head .= ' ' . $sql . $crlf;
|
||||
$head .= ' </pma:' . $type . '>' . $crlf;
|
||||
}
|
||||
}
|
||||
|
||||
return $head;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export header. It is the first method to be called, so all
|
||||
* the required variables are initialized here.
|
||||
*/
|
||||
public function exportHeader(): bool
|
||||
{
|
||||
$this->initSpecificVariables();
|
||||
global $crlf, $cfg, $db, $dbi;
|
||||
$table = $this->getTable();
|
||||
$tables = $this->getTables();
|
||||
|
||||
$export_struct = isset($GLOBALS['xml_export_functions'])
|
||||
|| isset($GLOBALS['xml_export_procedures'])
|
||||
|| isset($GLOBALS['xml_export_tables'])
|
||||
|| isset($GLOBALS['xml_export_triggers'])
|
||||
|| isset($GLOBALS['xml_export_views']);
|
||||
$export_data = isset($GLOBALS['xml_export_contents']);
|
||||
|
||||
if ($GLOBALS['output_charset_conversion']) {
|
||||
$charset = $GLOBALS['charset'];
|
||||
} else {
|
||||
$charset = 'utf-8';
|
||||
}
|
||||
|
||||
$head = '<?xml version="1.0" encoding="' . $charset . '"?>' . $crlf
|
||||
. '<!--' . $crlf
|
||||
. '- phpMyAdmin XML Dump' . $crlf
|
||||
. '- version ' . Version::VERSION . $crlf
|
||||
. '- https://www.phpmyadmin.net' . $crlf
|
||||
. '-' . $crlf
|
||||
. '- ' . __('Host:') . ' ' . htmlspecialchars($cfg['Server']['host']);
|
||||
if (! empty($cfg['Server']['port'])) {
|
||||
$head .= ':' . $cfg['Server']['port'];
|
||||
}
|
||||
|
||||
$head .= $crlf
|
||||
. '- ' . __('Generation Time:') . ' '
|
||||
. Util::localisedDate() . $crlf
|
||||
. '- ' . __('Server version:') . ' ' . $dbi->getVersionString() . $crlf
|
||||
. '- ' . __('PHP Version:') . ' ' . PHP_VERSION . $crlf
|
||||
. '-->' . $crlf . $crlf;
|
||||
|
||||
$head .= '<pma_xml_export version="1.0"'
|
||||
. ($export_struct
|
||||
? ' xmlns:pma="https://www.phpmyadmin.net/some_doc_url/"'
|
||||
: '')
|
||||
. '>' . $crlf;
|
||||
|
||||
if ($export_struct) {
|
||||
$result = $dbi->fetchResult(
|
||||
'SELECT `DEFAULT_CHARACTER_SET_NAME`, `DEFAULT_COLLATION_NAME`'
|
||||
. ' FROM `information_schema`.`SCHEMATA` WHERE `SCHEMA_NAME`'
|
||||
. ' = \'' . $dbi->escapeString($db) . '\' LIMIT 1'
|
||||
);
|
||||
$db_collation = $result[0]['DEFAULT_COLLATION_NAME'];
|
||||
$db_charset = $result[0]['DEFAULT_CHARACTER_SET_NAME'];
|
||||
|
||||
$head .= ' <!--' . $crlf;
|
||||
$head .= ' - Structure schemas' . $crlf;
|
||||
$head .= ' -->' . $crlf;
|
||||
$head .= ' <pma:structure_schemas>' . $crlf;
|
||||
$head .= ' <pma:database name="' . htmlspecialchars($db)
|
||||
. '" collation="' . htmlspecialchars($db_collation) . '" charset="' . htmlspecialchars($db_charset)
|
||||
. '">' . $crlf;
|
||||
|
||||
if (count($tables) === 0) {
|
||||
$tables[] = $table;
|
||||
}
|
||||
|
||||
foreach ($tables as $table) {
|
||||
// Export tables and views
|
||||
$result = $dbi->fetchResult(
|
||||
'SHOW CREATE TABLE ' . Util::backquote($db) . '.'
|
||||
. Util::backquote($table),
|
||||
0
|
||||
);
|
||||
$tbl = (string) $result[$table][1];
|
||||
|
||||
$is_view = $dbi->getTable($db, $table)
|
||||
->isView();
|
||||
|
||||
if ($is_view) {
|
||||
$type = 'view';
|
||||
} else {
|
||||
$type = 'table';
|
||||
}
|
||||
|
||||
if ($is_view && ! isset($GLOBALS['xml_export_views'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $is_view && ! isset($GLOBALS['xml_export_tables'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$head .= ' <pma:' . $type . ' name="' . htmlspecialchars($table) . '">'
|
||||
. $crlf;
|
||||
|
||||
$tbl = ' ' . htmlspecialchars($tbl);
|
||||
$tbl = str_replace("\n", "\n ", $tbl);
|
||||
|
||||
$head .= $tbl . ';' . $crlf;
|
||||
$head .= ' </pma:' . $type . '>' . $crlf;
|
||||
|
||||
if (! isset($GLOBALS['xml_export_triggers']) || ! $GLOBALS['xml_export_triggers']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Export triggers
|
||||
$triggers = $dbi->getTriggers($db, $table);
|
||||
if (! $triggers) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($triggers as $trigger) {
|
||||
$code = $trigger['create'];
|
||||
$head .= ' <pma:trigger name="'
|
||||
. htmlspecialchars($trigger['name']) . '">' . $crlf;
|
||||
|
||||
// Do some formatting
|
||||
$code = mb_substr(rtrim($code), 0, -3);
|
||||
$code = ' ' . htmlspecialchars($code);
|
||||
$code = str_replace("\n", "\n ", $code);
|
||||
|
||||
$head .= $code . $crlf;
|
||||
$head .= ' </pma:trigger>' . $crlf;
|
||||
}
|
||||
|
||||
unset($trigger, $triggers);
|
||||
}
|
||||
|
||||
if (isset($GLOBALS['xml_export_functions']) && $GLOBALS['xml_export_functions']) {
|
||||
$head .= $this->exportRoutinesDefinition($db, 'function', 'FUNCTION');
|
||||
}
|
||||
|
||||
if (isset($GLOBALS['xml_export_procedures']) && $GLOBALS['xml_export_procedures']) {
|
||||
$head .= $this->exportRoutinesDefinition($db, 'procedure', 'PROCEDURE');
|
||||
}
|
||||
|
||||
if (isset($GLOBALS['xml_export_events']) && $GLOBALS['xml_export_events']) {
|
||||
// Export events
|
||||
$events = $dbi->fetchResult(
|
||||
'SELECT EVENT_NAME FROM information_schema.EVENTS '
|
||||
. "WHERE EVENT_SCHEMA='" . $dbi->escapeString($db)
|
||||
. "'"
|
||||
);
|
||||
$head .= $this->exportDefinitions($db, 'event', 'EVENT', $events);
|
||||
}
|
||||
|
||||
unset($result);
|
||||
|
||||
$head .= ' </pma:database>' . $crlf;
|
||||
$head .= ' </pma:structure_schemas>' . $crlf;
|
||||
|
||||
if ($export_data) {
|
||||
$head .= $crlf;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->export->outputHandler($head);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export footer
|
||||
*/
|
||||
public function exportFooter(): bool
|
||||
{
|
||||
$foot = '</pma_xml_export>';
|
||||
|
||||
return $this->export->outputHandler($foot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database header
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $dbAlias Aliases of db
|
||||
*/
|
||||
public function exportDBHeader($db, $dbAlias = ''): bool
|
||||
{
|
||||
global $crlf;
|
||||
|
||||
if (empty($dbAlias)) {
|
||||
$dbAlias = $db;
|
||||
}
|
||||
|
||||
if (isset($GLOBALS['xml_export_contents']) && $GLOBALS['xml_export_contents']) {
|
||||
$head = ' <!--' . $crlf
|
||||
. ' - ' . __('Database:') . ' \''
|
||||
. htmlspecialchars($dbAlias) . '\'' . $crlf
|
||||
. ' -->' . $crlf . ' <database name="'
|
||||
. htmlspecialchars($dbAlias) . '">' . $crlf;
|
||||
|
||||
return $this->export->outputHandler($head);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database footer
|
||||
*
|
||||
* @param string $db Database name
|
||||
*/
|
||||
public function exportDBFooter($db): bool
|
||||
{
|
||||
global $crlf;
|
||||
|
||||
if (isset($GLOBALS['xml_export_contents']) && $GLOBALS['xml_export_contents']) {
|
||||
return $this->export->outputHandler(' </database>' . $crlf);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs CREATE DATABASE statement
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $exportType 'server', 'database', 'table'
|
||||
* @param string $dbAlias Aliases of db
|
||||
*/
|
||||
public function exportDBCreate($db, $exportType, $dbAlias = ''): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the content of a table in XML format
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
* @param string $crlf the end of line sequence
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string $sqlQuery SQL query for obtaining data
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*/
|
||||
public function exportData(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$sqlQuery,
|
||||
array $aliases = []
|
||||
): bool {
|
||||
global $dbi;
|
||||
|
||||
// Do not export data for merge tables
|
||||
if ($dbi->getTable($db, $table)->isMerge()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$db_alias = $db;
|
||||
$table_alias = $table;
|
||||
$this->initAlias($aliases, $db_alias, $table_alias);
|
||||
if (isset($GLOBALS['xml_export_contents']) && $GLOBALS['xml_export_contents']) {
|
||||
$result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED);
|
||||
|
||||
$columns_cnt = $result->numFields();
|
||||
$columns = [];
|
||||
foreach ($result->getFieldNames() as $column) {
|
||||
$columns[] = stripslashes($column);
|
||||
}
|
||||
|
||||
$buffer = ' <!-- ' . __('Table') . ' '
|
||||
. htmlspecialchars($table_alias) . ' -->' . $crlf;
|
||||
if (! $this->export->outputHandler($buffer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while ($record = $result->fetchRow()) {
|
||||
$buffer = ' <table name="'
|
||||
. htmlspecialchars($table_alias) . '">' . $crlf;
|
||||
for ($i = 0; $i < $columns_cnt; $i++) {
|
||||
$col_as = $columns[$i];
|
||||
if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) {
|
||||
$col_as = $aliases[$db]['tables'][$table]['columns'][$col_as];
|
||||
}
|
||||
|
||||
// If a cell is NULL, still export it to preserve
|
||||
// the XML structure
|
||||
if (! isset($record[$i])) {
|
||||
$record[$i] = 'NULL';
|
||||
}
|
||||
|
||||
$buffer .= ' <column name="'
|
||||
. htmlspecialchars($col_as) . '">'
|
||||
. htmlspecialchars((string) $record[$i])
|
||||
. '</column>' . $crlf;
|
||||
}
|
||||
|
||||
$buffer .= ' </table>' . $crlf;
|
||||
|
||||
if (! $this->export->outputHandler($buffer)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
/**
|
||||
* Gets the table name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getTable()
|
||||
{
|
||||
return $this->table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the table name
|
||||
*
|
||||
* @param string $table table name
|
||||
*/
|
||||
private function setTable($table): void
|
||||
{
|
||||
$this->table = $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the table names
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getTables()
|
||||
{
|
||||
return $this->tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the table names
|
||||
*
|
||||
* @param array $tables table names
|
||||
*/
|
||||
private function setTables(array $tables): void
|
||||
{
|
||||
$this->tables = $tables;
|
||||
}
|
||||
|
||||
public static function isAvailable(): bool
|
||||
{
|
||||
global $db;
|
||||
|
||||
// Can't do server export.
|
||||
return isset($db) && strlen($db) > 0;
|
||||
}
|
||||
}
|
228
admin/phpMyAdmin/libraries/classes/Plugins/Export/ExportYaml.php
Normal file
228
admin/phpMyAdmin/libraries/classes/Plugins/Export/ExportYaml.php
Normal file
|
@ -0,0 +1,228 @@
|
|||
<?php
|
||||
/**
|
||||
* Set of functions used to build YAML dumps of tables
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Plugins\Export;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\FieldMetadata;
|
||||
use PhpMyAdmin\Plugins\ExportPlugin;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup;
|
||||
use PhpMyAdmin\Properties\Options\Items\HiddenPropertyItem;
|
||||
use PhpMyAdmin\Properties\Plugins\ExportPluginProperties;
|
||||
|
||||
use function __;
|
||||
use function array_key_exists;
|
||||
use function is_numeric;
|
||||
use function str_replace;
|
||||
use function stripslashes;
|
||||
|
||||
/**
|
||||
* Handles the export for the YAML format
|
||||
*/
|
||||
class ExportYaml extends ExportPlugin
|
||||
{
|
||||
/**
|
||||
* @psalm-return non-empty-lowercase-string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'yaml';
|
||||
}
|
||||
|
||||
protected function setProperties(): ExportPluginProperties
|
||||
{
|
||||
$exportPluginProperties = new ExportPluginProperties();
|
||||
$exportPluginProperties->setText('YAML');
|
||||
$exportPluginProperties->setExtension('yml');
|
||||
$exportPluginProperties->setMimeType('text/yaml');
|
||||
$exportPluginProperties->setForceFile(true);
|
||||
$exportPluginProperties->setOptionsText(__('Options'));
|
||||
|
||||
// create the root group that will be the options field for
|
||||
// $exportPluginProperties
|
||||
// this will be shown as "Format specific options"
|
||||
$exportSpecificOptions = new OptionsPropertyRootGroup('Format Specific Options');
|
||||
|
||||
// general options main group
|
||||
$generalOptions = new OptionsPropertyMainGroup('general_opts');
|
||||
// create primary items and add them to the group
|
||||
$leaf = new HiddenPropertyItem('structure_or_data');
|
||||
$generalOptions->addProperty($leaf);
|
||||
// add the main group to the root group
|
||||
$exportSpecificOptions->addProperty($generalOptions);
|
||||
|
||||
// set the options for the export plugin property item
|
||||
$exportPluginProperties->setOptions($exportSpecificOptions);
|
||||
|
||||
return $exportPluginProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export header
|
||||
*/
|
||||
public function exportHeader(): bool
|
||||
{
|
||||
$this->export->outputHandler('%YAML 1.1' . $GLOBALS['crlf'] . '---' . $GLOBALS['crlf']);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export footer
|
||||
*/
|
||||
public function exportFooter(): bool
|
||||
{
|
||||
$this->export->outputHandler('...' . $GLOBALS['crlf']);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database header
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $dbAlias Aliases of db
|
||||
*/
|
||||
public function exportDBHeader($db, $dbAlias = ''): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database footer
|
||||
*
|
||||
* @param string $db Database name
|
||||
*/
|
||||
public function exportDBFooter($db): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs CREATE DATABASE statement
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $exportType 'server', 'database', 'table'
|
||||
* @param string $dbAlias Aliases of db
|
||||
*/
|
||||
public function exportDBCreate($db, $exportType, $dbAlias = ''): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the content of a table in JSON format
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
* @param string $crlf the end of line sequence
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string $sqlQuery SQL query for obtaining data
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*/
|
||||
public function exportData(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$sqlQuery,
|
||||
array $aliases = []
|
||||
): bool {
|
||||
global $dbi;
|
||||
|
||||
$db_alias = $db;
|
||||
$table_alias = $table;
|
||||
$this->initAlias($aliases, $db_alias, $table_alias);
|
||||
$result = $dbi->query($sqlQuery, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED);
|
||||
|
||||
$columns_cnt = $result->numFields();
|
||||
$fieldsMeta = $dbi->getFieldsMeta($result);
|
||||
|
||||
$columns = [];
|
||||
foreach ($fieldsMeta as $i => $field) {
|
||||
$col_as = $field->name;
|
||||
if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) {
|
||||
$col_as = $aliases[$db]['tables'][$table]['columns'][$col_as];
|
||||
}
|
||||
|
||||
$columns[$i] = stripslashes($col_as);
|
||||
}
|
||||
|
||||
$record_cnt = 0;
|
||||
while ($record = $result->fetchRow()) {
|
||||
$record_cnt++;
|
||||
|
||||
// Output table name as comment if this is the first record of the table
|
||||
if ($record_cnt == 1) {
|
||||
$buffer = '# ' . $db_alias . '.' . $table_alias . $crlf;
|
||||
$buffer .= '-' . $crlf;
|
||||
} else {
|
||||
$buffer = '-' . $crlf;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $columns_cnt; $i++) {
|
||||
if (! array_key_exists($i, $record)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($record[$i] === null) {
|
||||
$buffer .= ' ' . $columns[$i] . ': null' . $crlf;
|
||||
continue;
|
||||
}
|
||||
|
||||
$isNotString = isset($fieldsMeta[$i]) && $fieldsMeta[$i]->isNotType(FieldMetadata::TYPE_STRING);
|
||||
if (is_numeric($record[$i]) && $isNotString) {
|
||||
$buffer .= ' ' . $columns[$i] . ': ' . $record[$i] . $crlf;
|
||||
continue;
|
||||
}
|
||||
|
||||
$record[$i] = str_replace(
|
||||
[
|
||||
'\\',
|
||||
'"',
|
||||
"\n",
|
||||
"\r",
|
||||
],
|
||||
[
|
||||
'\\\\',
|
||||
'\"',
|
||||
'\n',
|
||||
'\r',
|
||||
],
|
||||
$record[$i]
|
||||
);
|
||||
$buffer .= ' ' . $columns[$i] . ': "' . $record[$i] . '"' . $crlf;
|
||||
}
|
||||
|
||||
if (! $this->export->outputHandler($buffer)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs result raw query in YAML format
|
||||
*
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string|null $db the database where the query is executed
|
||||
* @param string $sqlQuery the rawquery to output
|
||||
* @param string $crlf the end of line sequence
|
||||
*/
|
||||
public function exportRawQuery(string $errorUrl, ?string $db, string $sqlQuery, string $crlf): bool
|
||||
{
|
||||
global $dbi;
|
||||
|
||||
if ($db !== null) {
|
||||
$dbi->selectDb($db);
|
||||
}
|
||||
|
||||
return $this->exportData($db ?? '', '', $crlf, $errorUrl, $sqlQuery);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,902 @@
|
|||
<?php
|
||||
/**
|
||||
* PhpMyAdmin\Plugins\Export\Helpers\Pdf class
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Plugins\Export\Helpers;
|
||||
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Dbal\ResultInterface;
|
||||
use PhpMyAdmin\FieldMetadata;
|
||||
use PhpMyAdmin\Pdf as PdfLib;
|
||||
use PhpMyAdmin\Transformations;
|
||||
use PhpMyAdmin\Util;
|
||||
use TCPDF_STATIC;
|
||||
|
||||
use function __;
|
||||
use function array_key_exists;
|
||||
use function count;
|
||||
use function ksort;
|
||||
|
||||
/**
|
||||
* Adapted from a LGPL script by Philip Clarke
|
||||
*/
|
||||
class Pdf extends PdfLib
|
||||
{
|
||||
/** @var array */
|
||||
public $tablewidths;
|
||||
|
||||
/** @var array */
|
||||
public $headerset;
|
||||
|
||||
/** @var int|float */
|
||||
private $dataY;
|
||||
|
||||
/** @var int|float */
|
||||
private $cellFontSize;
|
||||
|
||||
/** @var int */
|
||||
private $titleFontSize;
|
||||
|
||||
/** @var string */
|
||||
private $titleText;
|
||||
|
||||
/** @var string */
|
||||
private $dbAlias;
|
||||
|
||||
/** @var string */
|
||||
private $tableAlias;
|
||||
|
||||
/** @var string */
|
||||
private $purpose;
|
||||
|
||||
/** @var array */
|
||||
private $colTitles;
|
||||
|
||||
/** @var ResultInterface */
|
||||
private $results;
|
||||
|
||||
/** @var array */
|
||||
private $colAlign;
|
||||
|
||||
/** @var mixed */
|
||||
private $titleWidth;
|
||||
|
||||
/** @var mixed */
|
||||
private $colFits;
|
||||
|
||||
/** @var array */
|
||||
private $displayColumn;
|
||||
|
||||
/** @var int */
|
||||
private $numFields;
|
||||
|
||||
/** @var FieldMetadata[] */
|
||||
private $fields;
|
||||
|
||||
/** @var int|float */
|
||||
private $sColWidth;
|
||||
|
||||
/** @var string */
|
||||
private $currentDb;
|
||||
|
||||
/** @var string */
|
||||
private $currentTable;
|
||||
|
||||
/** @var array */
|
||||
private $aliases;
|
||||
|
||||
/** @var Relation */
|
||||
private $relation;
|
||||
|
||||
/** @var Transformations */
|
||||
private $transformations;
|
||||
|
||||
/**
|
||||
* Constructs PDF and configures standard parameters.
|
||||
*
|
||||
* @param string $orientation page orientation
|
||||
* @param string $unit unit
|
||||
* @param string $format the format used for pages
|
||||
* @param bool $unicode true means that the input text is unicode
|
||||
* @param string $encoding charset encoding; default is UTF-8.
|
||||
* @param bool $diskcache DEPRECATED TCPDF FEATURE
|
||||
* @param false|int $pdfa If not false, set the document to PDF/A mode and the good version (1 or 3)
|
||||
*/
|
||||
public function __construct(
|
||||
$orientation = 'P',
|
||||
$unit = 'mm',
|
||||
$format = 'A4',
|
||||
$unicode = true,
|
||||
$encoding = 'UTF-8',
|
||||
$diskcache = false,
|
||||
$pdfa = false
|
||||
) {
|
||||
global $dbi;
|
||||
|
||||
parent::__construct($orientation, $unit, $format, $unicode, $encoding, $diskcache, $pdfa);
|
||||
$this->relation = new Relation($dbi);
|
||||
$this->transformations = new Transformations();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add page if needed.
|
||||
*
|
||||
* @param float|int $h cell height. Default value: 0
|
||||
* @param mixed $y starting y position, leave empty for current
|
||||
* position
|
||||
* @param bool $addpage if true add a page, otherwise only return
|
||||
* the true/false state
|
||||
*/
|
||||
public function checkPageBreak($h = 0, $y = '', $addpage = true): bool
|
||||
{
|
||||
if (TCPDF_STATIC::empty_string($y)) {
|
||||
$y = $this->y;
|
||||
}
|
||||
|
||||
$current_page = $this->page;
|
||||
// phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
|
||||
if ($y + $h > $this->PageBreakTrigger && ! $this->InFooter && $this->AcceptPageBreak()) {
|
||||
if ($addpage) {
|
||||
//Automatic page break
|
||||
$x = $this->x;
|
||||
// phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
|
||||
$this->AddPage($this->CurOrientation);
|
||||
$this->y = $this->dataY;
|
||||
$oldpage = $this->page - 1;
|
||||
|
||||
$this_page_orm = $this->pagedim[$this->page]['orm'];
|
||||
$old_page_orm = $this->pagedim[$oldpage]['orm'];
|
||||
$this_page_olm = $this->pagedim[$this->page]['olm'];
|
||||
$old_page_olm = $this->pagedim[$oldpage]['olm'];
|
||||
if ($this->rtl) {
|
||||
if ($this_page_orm != $old_page_orm) {
|
||||
$this->x = $x - ($this_page_orm - $old_page_orm);
|
||||
} else {
|
||||
$this->x = $x;
|
||||
}
|
||||
} else {
|
||||
if ($this_page_olm != $old_page_olm) {
|
||||
$this->x = $x + $this_page_olm - $old_page_olm;
|
||||
} else {
|
||||
$this->x = $x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// account for columns mode
|
||||
return $current_page != $this->page;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to render the page header.
|
||||
*/
|
||||
// phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
|
||||
public function Header(): void
|
||||
{
|
||||
global $maxY;
|
||||
// We don't want automatic page breaks while generating header
|
||||
// as this can lead to infinite recursion as auto generated page
|
||||
// will want header as well causing another page break
|
||||
// FIXME: Better approach might be to try to compact the content
|
||||
$this->setAutoPageBreak(false);
|
||||
// Check if header for this page already exists
|
||||
// phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
|
||||
if (! isset($this->headerset[$this->page])) {
|
||||
$this->setY($this->tMargin - ($this->FontSizePt / $this->k) * 5);
|
||||
$this->cellFontSize = $this->FontSizePt;
|
||||
$this->setFont(PdfLib::PMA_PDF_FONT, '', ($this->titleFontSize ?: $this->FontSizePt));
|
||||
$this->Cell(0, $this->FontSizePt, $this->titleText, 0, 1, 'C');
|
||||
$this->setFont(PdfLib::PMA_PDF_FONT, '', $this->cellFontSize);
|
||||
$this->setY($this->tMargin - ($this->FontSizePt / $this->k) * 2.5);
|
||||
$this->Cell(
|
||||
0,
|
||||
$this->FontSizePt,
|
||||
__('Database:') . ' ' . $this->dbAlias . ', '
|
||||
. __('Table:') . ' ' . $this->tableAlias . ', '
|
||||
. __('Purpose:') . ' ' . $this->purpose,
|
||||
0,
|
||||
1,
|
||||
'L'
|
||||
);
|
||||
$l = $this->lMargin;
|
||||
foreach ($this->colTitles as $col => $txt) {
|
||||
$this->setXY($l, $this->tMargin);
|
||||
$this->MultiCell($this->tablewidths[$col], $this->FontSizePt, $txt);
|
||||
$l += $this->tablewidths[$col];
|
||||
$maxY = $maxY < $this->GetY() ? $this->GetY() : $maxY;
|
||||
}
|
||||
|
||||
$this->setXY($this->lMargin, $this->tMargin);
|
||||
$this->setFillColor(200, 200, 200);
|
||||
$l = $this->lMargin;
|
||||
foreach ($this->colTitles as $col => $txt) {
|
||||
$this->setXY($l, $this->tMargin);
|
||||
$this->Cell($this->tablewidths[$col], $maxY - $this->tMargin, '', 1, 0, 'L', true);
|
||||
$this->setXY($l, $this->tMargin);
|
||||
$this->MultiCell($this->tablewidths[$col], $this->FontSizePt, $txt, 0, 'C');
|
||||
$l += $this->tablewidths[$col];
|
||||
}
|
||||
|
||||
$this->setFillColor(255, 255, 255);
|
||||
// set headerset
|
||||
$this->headerset[$this->page] = 1;
|
||||
}
|
||||
|
||||
// phpcs:enable
|
||||
|
||||
$this->dataY = $maxY;
|
||||
$this->setAutoPageBreak(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate table
|
||||
*
|
||||
* @param int $lineheight Height of line
|
||||
*/
|
||||
public function morepagestable($lineheight = 8): void
|
||||
{
|
||||
// some things to set and 'remember'
|
||||
$l = $this->lMargin;
|
||||
$startheight = $h = $this->dataY;
|
||||
$startpage = $currpage = $this->page;
|
||||
|
||||
// calculate the whole width
|
||||
$fullwidth = 0;
|
||||
foreach ($this->tablewidths as $width) {
|
||||
$fullwidth += $width;
|
||||
}
|
||||
|
||||
// Now let's start to write the table
|
||||
$row = 0;
|
||||
$tmpheight = [];
|
||||
$maxpage = $this->page;
|
||||
|
||||
while ($data = $this->results->fetchRow()) {
|
||||
$this->page = $currpage;
|
||||
// write the horizontal borders
|
||||
$this->Line($l, $h, $fullwidth + $l, $h);
|
||||
// write the content and remember the height of the highest col
|
||||
foreach ($data as $col => $txt) {
|
||||
$this->page = $currpage;
|
||||
$this->setXY($l, $h);
|
||||
if ($this->tablewidths[$col] > 0) {
|
||||
$this->MultiCell($this->tablewidths[$col], $lineheight, $txt, 0, $this->colAlign[$col]);
|
||||
$l += $this->tablewidths[$col];
|
||||
}
|
||||
|
||||
if (! isset($tmpheight[$row . '-' . $this->page])) {
|
||||
$tmpheight[$row . '-' . $this->page] = 0;
|
||||
}
|
||||
|
||||
if ($tmpheight[$row . '-' . $this->page] < $this->GetY()) {
|
||||
$tmpheight[$row . '-' . $this->page] = $this->GetY();
|
||||
}
|
||||
|
||||
if ($this->page > $maxpage) {
|
||||
$maxpage = $this->page;
|
||||
}
|
||||
|
||||
unset($data[$col]);
|
||||
}
|
||||
|
||||
// get the height we were in the last used page
|
||||
$h = $tmpheight[$row . '-' . $maxpage];
|
||||
// set the "pointer" to the left margin
|
||||
$l = $this->lMargin;
|
||||
// set the $currpage to the last page
|
||||
$currpage = $maxpage;
|
||||
unset($data[$row]);
|
||||
$row++;
|
||||
}
|
||||
|
||||
// draw the borders
|
||||
// we start adding a horizontal line on the last page
|
||||
$this->page = $maxpage;
|
||||
$this->Line($l, $h, $fullwidth + $l, $h);
|
||||
// now we start at the top of the document and walk down
|
||||
for ($i = $startpage; $i <= $maxpage; $i++) {
|
||||
$this->page = $i;
|
||||
$l = $this->lMargin;
|
||||
$t = $i == $startpage ? $startheight : $this->tMargin;
|
||||
$lh = $i == $maxpage ? $h : $this->h - $this->bMargin;
|
||||
$this->Line($l, $t, $l, $lh);
|
||||
foreach ($this->tablewidths as $width) {
|
||||
$l += $width;
|
||||
$this->Line($l, $t, $l, $lh);
|
||||
}
|
||||
}
|
||||
|
||||
// set it to the last page, if not it'll cause some problems
|
||||
$this->page = $maxpage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the top margin.
|
||||
* The method can be called before creating the first page.
|
||||
*
|
||||
* @param float $topMargin the margin
|
||||
*/
|
||||
public function setTopMargin($topMargin): void
|
||||
{
|
||||
$this->tMargin = $topMargin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints triggers
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
*/
|
||||
public function getTriggers($db, $table): void
|
||||
{
|
||||
global $dbi;
|
||||
|
||||
$triggers = $dbi->getTriggers($db, $table);
|
||||
if ($triggers === []) {
|
||||
return; //prevents printing blank trigger list for any table
|
||||
}
|
||||
|
||||
unset(
|
||||
$this->tablewidths,
|
||||
$this->colTitles,
|
||||
$this->titleWidth,
|
||||
$this->colFits,
|
||||
$this->displayColumn,
|
||||
$this->colAlign
|
||||
);
|
||||
|
||||
/**
|
||||
* Making table heading
|
||||
* Keeping column width constant
|
||||
*/
|
||||
$this->colTitles[0] = __('Name');
|
||||
$this->tablewidths[0] = 90;
|
||||
$this->colTitles[1] = __('Time');
|
||||
$this->tablewidths[1] = 80;
|
||||
$this->colTitles[2] = __('Event');
|
||||
$this->tablewidths[2] = 40;
|
||||
$this->colTitles[3] = __('Definition');
|
||||
$this->tablewidths[3] = 240;
|
||||
|
||||
for ($columns_cnt = 0; $columns_cnt < 4; $columns_cnt++) {
|
||||
$this->colAlign[$columns_cnt] = 'L';
|
||||
$this->displayColumn[$columns_cnt] = true;
|
||||
}
|
||||
|
||||
// Starting to fill table with required info
|
||||
|
||||
$this->setY($this->tMargin);
|
||||
$this->AddPage();
|
||||
$this->setFont(PdfLib::PMA_PDF_FONT, '', 9);
|
||||
|
||||
$l = $this->lMargin;
|
||||
$startheight = $h = $this->dataY;
|
||||
$startpage = $currpage = $this->page;
|
||||
|
||||
// calculate the whole width
|
||||
$fullwidth = 0;
|
||||
foreach ($this->tablewidths as $width) {
|
||||
$fullwidth += $width;
|
||||
}
|
||||
|
||||
$row = 0;
|
||||
$tmpheight = [];
|
||||
$maxpage = $this->page;
|
||||
$data = [];
|
||||
|
||||
foreach ($triggers as $trigger) {
|
||||
$data[] = $trigger['name'];
|
||||
$data[] = $trigger['action_timing'];
|
||||
$data[] = $trigger['event_manipulation'];
|
||||
$data[] = $trigger['definition'];
|
||||
$this->page = $currpage;
|
||||
// write the horizontal borders
|
||||
$this->Line($l, $h, $fullwidth + $l, $h);
|
||||
// write the content and remember the height of the highest col
|
||||
foreach ($data as $col => $txt) {
|
||||
$this->page = $currpage;
|
||||
$this->setXY($l, $h);
|
||||
if ($this->tablewidths[$col] > 0) {
|
||||
$this->MultiCell(
|
||||
$this->tablewidths[$col],
|
||||
// phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
|
||||
$this->FontSizePt,
|
||||
$txt,
|
||||
0,
|
||||
$this->colAlign[$col]
|
||||
);
|
||||
$l += $this->tablewidths[$col];
|
||||
}
|
||||
|
||||
if (! isset($tmpheight[$row . '-' . $this->page])) {
|
||||
$tmpheight[$row . '-' . $this->page] = 0;
|
||||
}
|
||||
|
||||
if ($tmpheight[$row . '-' . $this->page] < $this->GetY()) {
|
||||
$tmpheight[$row . '-' . $this->page] = $this->GetY();
|
||||
}
|
||||
|
||||
if ($this->page <= $maxpage) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$maxpage = $this->page;
|
||||
}
|
||||
|
||||
// get the height we were in the last used page
|
||||
$h = $tmpheight[$row . '-' . $maxpage];
|
||||
// set the "pointer" to the left margin
|
||||
$l = $this->lMargin;
|
||||
// set the $currpage to the last page
|
||||
$currpage = $maxpage;
|
||||
unset($data);
|
||||
$row++;
|
||||
}
|
||||
|
||||
// draw the borders
|
||||
// we start adding a horizontal line on the last page
|
||||
$this->page = $maxpage;
|
||||
$this->Line($l, $h, $fullwidth + $l, $h);
|
||||
// now we start at the top of the document and walk down
|
||||
for ($i = $startpage; $i <= $maxpage; $i++) {
|
||||
$this->page = $i;
|
||||
$l = $this->lMargin;
|
||||
$t = $i == $startpage ? $startheight : $this->tMargin;
|
||||
$lh = $i == $maxpage ? $h : $this->h - $this->bMargin;
|
||||
$this->Line($l, $t, $l, $lh);
|
||||
foreach ($this->tablewidths as $width) {
|
||||
$l += $width;
|
||||
$this->Line($l, $t, $l, $lh);
|
||||
}
|
||||
}
|
||||
|
||||
// set it to the last page, if not it'll cause some problems
|
||||
$this->page = $maxpage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print $table's CREATE definition
|
||||
*
|
||||
* @param string $db the database name
|
||||
* @param string $table the table name
|
||||
* @param bool $do_relation whether to include relation comments
|
||||
* @param bool $do_comments whether to include the pmadb-style column
|
||||
* comments as comments in the structure;
|
||||
* this is deprecated but the parameter is
|
||||
* left here because /export calls
|
||||
* PMA_exportStructure() also for other
|
||||
* export types which use this parameter
|
||||
* @param bool $do_mime whether to include mime comments
|
||||
* @param bool $view whether we're handling a view
|
||||
* @param array $aliases aliases of db/table/columns
|
||||
*/
|
||||
public function getTableDef(
|
||||
$db,
|
||||
$table,
|
||||
$do_relation,
|
||||
$do_comments,
|
||||
$do_mime,
|
||||
$view = false,
|
||||
array $aliases = []
|
||||
): void {
|
||||
global $dbi;
|
||||
|
||||
$relationParameters = $this->relation->getRelationParameters();
|
||||
|
||||
unset(
|
||||
$this->tablewidths,
|
||||
$this->colTitles,
|
||||
$this->titleWidth,
|
||||
$this->colFits,
|
||||
$this->displayColumn,
|
||||
$this->colAlign
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets fields properties
|
||||
*/
|
||||
$dbi->selectDb($db);
|
||||
|
||||
/**
|
||||
* All these three checks do_relation, do_comment and do_mime is
|
||||
* not required. As presently all are set true by default.
|
||||
* But when, methods to take user input will be developed,
|
||||
* it will be of use
|
||||
*/
|
||||
// Check if we can use Relations
|
||||
if ($do_relation) {
|
||||
// Find which tables are related with the current one and write it in
|
||||
// an array
|
||||
$res_rel = $this->relation->getForeigners($db, $table);
|
||||
$have_rel = ! empty($res_rel);
|
||||
} else {
|
||||
$have_rel = false;
|
||||
}
|
||||
|
||||
//column count and table heading
|
||||
|
||||
$this->colTitles[0] = __('Column');
|
||||
$this->tablewidths[0] = 90;
|
||||
$this->colTitles[1] = __('Type');
|
||||
$this->tablewidths[1] = 80;
|
||||
$this->colTitles[2] = __('Null');
|
||||
$this->tablewidths[2] = 40;
|
||||
$this->colTitles[3] = __('Default');
|
||||
$this->tablewidths[3] = 120;
|
||||
|
||||
for ($columns_cnt = 0; $columns_cnt < 4; $columns_cnt++) {
|
||||
$this->colAlign[$columns_cnt] = 'L';
|
||||
$this->displayColumn[$columns_cnt] = true;
|
||||
}
|
||||
|
||||
if ($do_relation && $have_rel) {
|
||||
$this->colTitles[$columns_cnt] = __('Links to');
|
||||
$this->displayColumn[$columns_cnt] = true;
|
||||
$this->colAlign[$columns_cnt] = 'L';
|
||||
$this->tablewidths[$columns_cnt] = 120;
|
||||
}
|
||||
|
||||
if ($do_comments) {
|
||||
$columns_cnt++;
|
||||
$this->colTitles[$columns_cnt] = __('Comments');
|
||||
$this->displayColumn[$columns_cnt] = true;
|
||||
$this->colAlign[$columns_cnt] = 'L';
|
||||
$this->tablewidths[$columns_cnt] = 120;
|
||||
}
|
||||
|
||||
if ($do_mime && $relationParameters->browserTransformationFeature !== null) {
|
||||
$columns_cnt++;
|
||||
$this->colTitles[$columns_cnt] = __('Media type');
|
||||
$this->displayColumn[$columns_cnt] = true;
|
||||
$this->colAlign[$columns_cnt] = 'L';
|
||||
$this->tablewidths[$columns_cnt] = 120;
|
||||
}
|
||||
|
||||
// Starting to fill table with required info
|
||||
|
||||
$this->setY($this->tMargin);
|
||||
$this->AddPage();
|
||||
$this->setFont(PdfLib::PMA_PDF_FONT, '', 9);
|
||||
|
||||
// Now let's start to write the table structure
|
||||
|
||||
if ($do_comments) {
|
||||
$comments = $this->relation->getComments($db, $table);
|
||||
}
|
||||
|
||||
if ($do_mime && $relationParameters->browserTransformationFeature !== null) {
|
||||
$mime_map = $this->transformations->getMime($db, $table, true);
|
||||
}
|
||||
|
||||
$columns = $dbi->getColumns($db, $table);
|
||||
|
||||
// some things to set and 'remember'
|
||||
$l = $this->lMargin;
|
||||
$startheight = $h = $this->dataY;
|
||||
$startpage = $currpage = $this->page;
|
||||
// calculate the whole width
|
||||
$fullwidth = 0;
|
||||
foreach ($this->tablewidths as $width) {
|
||||
$fullwidth += $width;
|
||||
}
|
||||
|
||||
$row = 0;
|
||||
$tmpheight = [];
|
||||
$maxpage = $this->page;
|
||||
$data = [];
|
||||
|
||||
// fun begin
|
||||
foreach ($columns as $column) {
|
||||
$extracted_columnspec = Util::extractColumnSpec($column['Type']);
|
||||
|
||||
$type = $extracted_columnspec['print_type'];
|
||||
if (empty($type)) {
|
||||
$type = ' ';
|
||||
}
|
||||
|
||||
if (! isset($column['Default'])) {
|
||||
if ($column['Null'] !== 'NO') {
|
||||
$column['Default'] = 'NULL';
|
||||
}
|
||||
}
|
||||
|
||||
$data[] = $column['Field'];
|
||||
$data[] = $type;
|
||||
$data[] = $column['Null'] == '' || $column['Null'] === 'NO'
|
||||
? 'No'
|
||||
: 'Yes';
|
||||
$data[] = $column['Default'] ?? '';
|
||||
|
||||
$field_name = $column['Field'];
|
||||
|
||||
if ($do_relation && $have_rel) {
|
||||
$data[] = isset($res_rel[$field_name])
|
||||
? $res_rel[$field_name]['foreign_table']
|
||||
. ' (' . $res_rel[$field_name]['foreign_field']
|
||||
. ')'
|
||||
: '';
|
||||
}
|
||||
|
||||
if ($do_comments) {
|
||||
$data[] = $comments[$field_name] ?? '';
|
||||
}
|
||||
|
||||
if ($do_mime) {
|
||||
$data[] = isset($mime_map[$field_name])
|
||||
? $mime_map[$field_name]['mimetype']
|
||||
: '';
|
||||
}
|
||||
|
||||
$this->page = $currpage;
|
||||
// write the horizontal borders
|
||||
$this->Line($l, $h, $fullwidth + $l, $h);
|
||||
// write the content and remember the height of the highest col
|
||||
foreach ($data as $col => $txt) {
|
||||
$this->page = $currpage;
|
||||
$this->setXY($l, $h);
|
||||
if ($this->tablewidths[$col] > 0) {
|
||||
$this->MultiCell(
|
||||
$this->tablewidths[$col],
|
||||
// phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
|
||||
$this->FontSizePt,
|
||||
$txt,
|
||||
0,
|
||||
$this->colAlign[$col]
|
||||
);
|
||||
$l += $this->tablewidths[$col];
|
||||
}
|
||||
|
||||
if (! isset($tmpheight[$row . '-' . $this->page])) {
|
||||
$tmpheight[$row . '-' . $this->page] = 0;
|
||||
}
|
||||
|
||||
if ($tmpheight[$row . '-' . $this->page] < $this->GetY()) {
|
||||
$tmpheight[$row . '-' . $this->page] = $this->GetY();
|
||||
}
|
||||
|
||||
if ($this->page <= $maxpage) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$maxpage = $this->page;
|
||||
}
|
||||
|
||||
// get the height we were in the last used page
|
||||
$h = $tmpheight[$row . '-' . $maxpage];
|
||||
// set the "pointer" to the left margin
|
||||
$l = $this->lMargin;
|
||||
// set the $currpage to the last page
|
||||
$currpage = $maxpage;
|
||||
unset($data);
|
||||
$row++;
|
||||
}
|
||||
|
||||
// draw the borders
|
||||
// we start adding a horizontal line on the last page
|
||||
$this->page = $maxpage;
|
||||
$this->Line($l, $h, $fullwidth + $l, $h);
|
||||
// now we start at the top of the document and walk down
|
||||
for ($i = $startpage; $i <= $maxpage; $i++) {
|
||||
$this->page = $i;
|
||||
$l = $this->lMargin;
|
||||
$t = $i == $startpage ? $startheight : $this->tMargin;
|
||||
$lh = $i == $maxpage ? $h : $this->h - $this->bMargin;
|
||||
$this->Line($l, $t, $l, $lh);
|
||||
foreach ($this->tablewidths as $width) {
|
||||
$l += $width;
|
||||
$this->Line($l, $t, $l, $lh);
|
||||
}
|
||||
}
|
||||
|
||||
// set it to the last page, if not it'll cause some problems
|
||||
$this->page = $maxpage;
|
||||
}
|
||||
|
||||
/**
|
||||
* MySQL report
|
||||
*
|
||||
* @param string $query Query to execute
|
||||
*/
|
||||
public function mysqlReport($query): void
|
||||
{
|
||||
global $dbi;
|
||||
|
||||
unset(
|
||||
$this->tablewidths,
|
||||
$this->colTitles,
|
||||
$this->titleWidth,
|
||||
$this->colFits,
|
||||
$this->displayColumn,
|
||||
$this->colAlign
|
||||
);
|
||||
|
||||
/**
|
||||
* Pass 1 for column widths
|
||||
*/
|
||||
$this->results = $dbi->query($query, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED);
|
||||
$this->numFields = $this->results->numFields();
|
||||
$this->fields = $dbi->getFieldsMeta($this->results);
|
||||
|
||||
// sColWidth = starting col width (an average size width)
|
||||
$availableWidth = $this->w - $this->lMargin - $this->rMargin;
|
||||
$this->sColWidth = $availableWidth / $this->numFields;
|
||||
$totalTitleWidth = 0;
|
||||
|
||||
// loop through results header and set initial
|
||||
// col widths/ titles/ alignment
|
||||
// if a col title is less than the starting col width,
|
||||
// reduce that column size
|
||||
$colFits = [];
|
||||
$titleWidth = [];
|
||||
for ($i = 0; $i < $this->numFields; $i++) {
|
||||
$col_as = $this->fields[$i]->name;
|
||||
$db = $this->currentDb;
|
||||
$table = $this->currentTable;
|
||||
if (! empty($this->aliases[$db]['tables'][$table]['columns'][$col_as])) {
|
||||
$col_as = $this->aliases[$db]['tables'][$table]['columns'][$col_as];
|
||||
}
|
||||
|
||||
/** @var float $stringWidth */
|
||||
$stringWidth = $this->GetStringWidth($col_as);
|
||||
$stringWidth += 6;
|
||||
// save the real title's width
|
||||
$titleWidth[$i] = $stringWidth;
|
||||
$totalTitleWidth += $stringWidth;
|
||||
|
||||
// set any column titles less than the start width to
|
||||
// the column title width
|
||||
if ($stringWidth < $this->sColWidth) {
|
||||
$colFits[$i] = $stringWidth;
|
||||
}
|
||||
|
||||
$this->colTitles[$i] = $col_as;
|
||||
$this->displayColumn[$i] = true;
|
||||
|
||||
$this->colAlign[$i] = 'L';
|
||||
|
||||
if ($this->fields[$i]->isType(FieldMetadata::TYPE_INT)) {
|
||||
$this->colAlign[$i] = 'R';
|
||||
}
|
||||
|
||||
if (! $this->fields[$i]->isType(FieldMetadata::TYPE_BLOB)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo do not deactivate completely the display
|
||||
* but show the field's name and [BLOB]
|
||||
*/
|
||||
if ($this->fields[$i]->isBinary()) {
|
||||
$this->displayColumn[$i] = false;
|
||||
unset($this->colTitles[$i]);
|
||||
}
|
||||
|
||||
$this->colAlign[$i] = 'L';
|
||||
}
|
||||
|
||||
// title width verification
|
||||
if ($totalTitleWidth > $availableWidth) {
|
||||
$adjustingMode = true;
|
||||
} else {
|
||||
$adjustingMode = false;
|
||||
// we have enough space for all the titles at their
|
||||
// original width so use the true title's width
|
||||
foreach ($titleWidth as $key => $val) {
|
||||
$colFits[$key] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
// loop through the data; any column whose contents
|
||||
// is greater than the column size is resized
|
||||
/**
|
||||
* @todo force here a LIMIT to avoid reading all rows
|
||||
*/
|
||||
while ($row = $this->results->fetchRow()) {
|
||||
foreach ($colFits as $key => $val) {
|
||||
/** @var float $stringWidth */
|
||||
$stringWidth = $this->GetStringWidth($row[$key]);
|
||||
$stringWidth += 6;
|
||||
if ($adjustingMode && ($stringWidth > $this->sColWidth)) {
|
||||
// any column whose data's width is bigger than
|
||||
// the start width is now discarded
|
||||
unset($colFits[$key]);
|
||||
} else {
|
||||
// if data's width is bigger than the current column width,
|
||||
// enlarge the column (but avoid enlarging it if the
|
||||
// data's width is very big)
|
||||
if ($stringWidth > $val && $stringWidth < $this->sColWidth * 3) {
|
||||
$colFits[$key] = $stringWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$totAlreadyFitted = 0;
|
||||
foreach ($colFits as $key => $val) {
|
||||
// set fitted columns to smallest size
|
||||
$this->tablewidths[$key] = $val;
|
||||
// to work out how much (if any) space has been freed up
|
||||
$totAlreadyFitted += $val;
|
||||
}
|
||||
|
||||
if ($adjustingMode) {
|
||||
$surplus = (count($colFits) * $this->sColWidth) - $totAlreadyFitted;
|
||||
$surplusToAdd = $surplus / ($this->numFields - count($colFits));
|
||||
} else {
|
||||
$surplusToAdd = 0;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $this->numFields; $i++) {
|
||||
if (! array_key_exists($i, $colFits)) {
|
||||
$this->tablewidths[$i] = $this->sColWidth + $surplusToAdd;
|
||||
}
|
||||
|
||||
if ($this->displayColumn[$i] != false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->tablewidths[$i] = 0;
|
||||
}
|
||||
|
||||
ksort($this->tablewidths);
|
||||
|
||||
// Pass 2
|
||||
|
||||
$this->results = $dbi->query($query, DatabaseInterface::CONNECT_USER, DatabaseInterface::QUERY_UNBUFFERED);
|
||||
$this->setY($this->tMargin);
|
||||
$this->AddPage();
|
||||
$this->setFont(PdfLib::PMA_PDF_FONT, '', 9);
|
||||
// phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
|
||||
$this->morepagestable($this->FontSizePt);
|
||||
}
|
||||
|
||||
public function setTitleFontSize(int $titleFontSize): void
|
||||
{
|
||||
$this->titleFontSize = $titleFontSize;
|
||||
}
|
||||
|
||||
public function setTitleText(string $titleText): void
|
||||
{
|
||||
$this->titleText = $titleText;
|
||||
}
|
||||
|
||||
public function setCurrentDb(?string $currentDb): void
|
||||
{
|
||||
$this->currentDb = $currentDb ?? '';
|
||||
}
|
||||
|
||||
public function setCurrentTable(?string $currentTable): void
|
||||
{
|
||||
$this->currentTable = $currentTable ?? '';
|
||||
}
|
||||
|
||||
public function setDbAlias(?string $dbAlias): void
|
||||
{
|
||||
$this->dbAlias = $dbAlias ?? '';
|
||||
}
|
||||
|
||||
public function setTableAlias(?string $tableAlias): void
|
||||
{
|
||||
$this->tableAlias = $tableAlias ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aliases
|
||||
*/
|
||||
public function setAliases(array $aliases): void
|
||||
{
|
||||
$this->aliases = $aliases;
|
||||
}
|
||||
|
||||
public function setPurpose(string $purpose): void
|
||||
{
|
||||
$this->purpose = $purpose;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,294 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Plugins\Export\Helpers;
|
||||
|
||||
use PhpMyAdmin\Plugins\Export\ExportCodegen;
|
||||
|
||||
use function htmlspecialchars;
|
||||
use function mb_strpos;
|
||||
use function mb_substr;
|
||||
use function str_replace;
|
||||
use function strlen;
|
||||
use function trim;
|
||||
|
||||
use const ENT_COMPAT;
|
||||
|
||||
/**
|
||||
* PhpMyAdmin\Plugins\Export\Helpers\TableProperty class
|
||||
*/
|
||||
class TableProperty
|
||||
{
|
||||
/**
|
||||
* Name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* Type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type;
|
||||
|
||||
/**
|
||||
* Whether the key is nullable or not
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $nullable;
|
||||
|
||||
/**
|
||||
* The key
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $key;
|
||||
|
||||
/**
|
||||
* Default value
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $defaultValue;
|
||||
|
||||
/**
|
||||
* Extension
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $ext;
|
||||
|
||||
/**
|
||||
* @param array $row table row
|
||||
*/
|
||||
public function __construct(array $row)
|
||||
{
|
||||
$this->name = trim((string) $row[0]);
|
||||
$this->type = trim((string) $row[1]);
|
||||
$this->nullable = trim((string) $row[2]);
|
||||
$this->key = trim((string) $row[3]);
|
||||
$this->defaultValue = trim((string) $row[4]);
|
||||
$this->ext = trim((string) $row[5]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pure type
|
||||
*
|
||||
* @return string type
|
||||
*/
|
||||
public function getPureType()
|
||||
{
|
||||
$pos = (int) mb_strpos($this->type, '(');
|
||||
if ($pos > 0) {
|
||||
return mb_substr($this->type, 0, $pos);
|
||||
}
|
||||
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the key is null or not
|
||||
*
|
||||
* @return string true if the key is not null, false otherwise
|
||||
*/
|
||||
public function isNotNull()
|
||||
{
|
||||
return $this->nullable === 'NO' ? 'true' : 'false';
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the key is unique or not
|
||||
*
|
||||
* @return string "true" if the key is unique, "false" otherwise
|
||||
*/
|
||||
public function isUnique(): string
|
||||
{
|
||||
return $this->key === 'PRI' || $this->key === 'UNI' ? 'true' : 'false';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the .NET primitive type
|
||||
*
|
||||
* @return string type
|
||||
*/
|
||||
public function getDotNetPrimitiveType()
|
||||
{
|
||||
if (mb_strpos($this->type, 'int') === 0) {
|
||||
return 'int';
|
||||
}
|
||||
|
||||
if (mb_strpos($this->type, 'longtext') === 0) {
|
||||
return 'string';
|
||||
}
|
||||
|
||||
if (mb_strpos($this->type, 'long') === 0) {
|
||||
return 'long';
|
||||
}
|
||||
|
||||
if (mb_strpos($this->type, 'char') === 0) {
|
||||
return 'string';
|
||||
}
|
||||
|
||||
if (mb_strpos($this->type, 'varchar') === 0) {
|
||||
return 'string';
|
||||
}
|
||||
|
||||
if (mb_strpos($this->type, 'text') === 0) {
|
||||
return 'string';
|
||||
}
|
||||
|
||||
if (mb_strpos($this->type, 'tinyint') === 0) {
|
||||
return 'bool';
|
||||
}
|
||||
|
||||
if (mb_strpos($this->type, 'datetime') === 0) {
|
||||
return 'DateTime';
|
||||
}
|
||||
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the .NET object type
|
||||
*
|
||||
* @return string type
|
||||
*/
|
||||
public function getDotNetObjectType()
|
||||
{
|
||||
if (mb_strpos($this->type, 'int') === 0) {
|
||||
return 'Int32';
|
||||
}
|
||||
|
||||
if (mb_strpos($this->type, 'longtext') === 0) {
|
||||
return 'String';
|
||||
}
|
||||
|
||||
if (mb_strpos($this->type, 'long') === 0) {
|
||||
return 'Long';
|
||||
}
|
||||
|
||||
if (mb_strpos($this->type, 'char') === 0) {
|
||||
return 'String';
|
||||
}
|
||||
|
||||
if (mb_strpos($this->type, 'varchar') === 0) {
|
||||
return 'String';
|
||||
}
|
||||
|
||||
if (mb_strpos($this->type, 'text') === 0) {
|
||||
return 'String';
|
||||
}
|
||||
|
||||
if (mb_strpos($this->type, 'tinyint') === 0) {
|
||||
return 'Boolean';
|
||||
}
|
||||
|
||||
if (mb_strpos($this->type, 'datetime') === 0) {
|
||||
return 'DateTime';
|
||||
}
|
||||
|
||||
return 'Unknown';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index name
|
||||
*
|
||||
* @return string containing the name of the index
|
||||
*/
|
||||
public function getIndexName()
|
||||
{
|
||||
if (strlen($this->key) > 0) {
|
||||
return 'index="'
|
||||
. htmlspecialchars($this->name, ENT_COMPAT, 'UTF-8')
|
||||
. '"';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the key is primary or not
|
||||
*/
|
||||
public function isPK(): bool
|
||||
{
|
||||
return $this->key === 'PRI';
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a string for C#
|
||||
*
|
||||
* @param string $text string to be formatted
|
||||
*
|
||||
* @return string formatted text
|
||||
*/
|
||||
public function formatCs($text)
|
||||
{
|
||||
$text = str_replace(
|
||||
'#name#',
|
||||
ExportCodegen::cgMakeIdentifier($this->name, false),
|
||||
$text
|
||||
);
|
||||
|
||||
return $this->format($text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a string for XML
|
||||
*
|
||||
* @param string $text string to be formatted
|
||||
*
|
||||
* @return string formatted text
|
||||
*/
|
||||
public function formatXml($text)
|
||||
{
|
||||
$text = str_replace(
|
||||
[
|
||||
'#name#',
|
||||
'#indexName#',
|
||||
],
|
||||
[
|
||||
htmlspecialchars($this->name, ENT_COMPAT, 'UTF-8'),
|
||||
$this->getIndexName(),
|
||||
],
|
||||
$text
|
||||
);
|
||||
|
||||
return $this->format($text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a string
|
||||
*
|
||||
* @param string $text string to be formatted
|
||||
*
|
||||
* @return string formatted text
|
||||
*/
|
||||
public function format($text)
|
||||
{
|
||||
$text = str_replace(
|
||||
[
|
||||
'#ucfirstName#',
|
||||
'#dotNetPrimitiveType#',
|
||||
'#dotNetObjectType#',
|
||||
'#type#',
|
||||
'#notNull#',
|
||||
'#unique#',
|
||||
],
|
||||
[
|
||||
ExportCodegen::cgMakeIdentifier($this->name),
|
||||
$this->getDotNetPrimitiveType(),
|
||||
$this->getDotNetObjectType(),
|
||||
$this->getPureType(),
|
||||
$this->isNotNull(),
|
||||
$this->isUnique(),
|
||||
],
|
||||
$text
|
||||
);
|
||||
|
||||
return $text;
|
||||
}
|
||||
}
|
247
admin/phpMyAdmin/libraries/classes/Plugins/Export/README.md
Normal file
247
admin/phpMyAdmin/libraries/classes/Plugins/Export/README.md
Normal file
|
@ -0,0 +1,247 @@
|
|||
# Export plugin creation
|
||||
|
||||
This directory holds export plugins for phpMyAdmin. Any new plugin should
|
||||
basically follow the structure presented here. Official plugins need to
|
||||
have str* messages with their definition in language files, but if you build
|
||||
some plugins for your use, you can directly use texts in plugin.
|
||||
|
||||
```php
|
||||
<?php
|
||||
/**
|
||||
* [Name] export plugin for phpMyAdmin
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Handles the export for the [Name] format
|
||||
*/
|
||||
class Export[Name] extends PhpMyAdmin\Plugins\ExportPlugin
|
||||
{
|
||||
/**
|
||||
* optional - declare variables and descriptions
|
||||
*
|
||||
* @var VariableType
|
||||
*/
|
||||
private $myOptionalVariable;
|
||||
|
||||
/**
|
||||
* optional - declare global variables and descriptions
|
||||
*
|
||||
* @var VariableType
|
||||
*/
|
||||
private $globalVariableName;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->setProperties();
|
||||
}
|
||||
|
||||
// optional - declare global variables and use getters later
|
||||
|
||||
/**
|
||||
* Initialize the local variables that are used specific for export SQL
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @global VariableType $global_variable_name
|
||||
* [..]
|
||||
*/
|
||||
protected function initSpecificVariables()
|
||||
{
|
||||
global $global_variable_name;
|
||||
$this->setGlobalVariableName($global_variable_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the export plugin properties.
|
||||
* Called in the constructor.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function setProperties()
|
||||
{
|
||||
$exportPluginProperties = new PhpMyAdmin\Properties\Plugins\ExportPluginProperties();
|
||||
$exportPluginProperties->setText('[name]'); // the name of your plug-in
|
||||
$exportPluginProperties->setExtension('[ext]'); // extension this plug-in can handle
|
||||
$exportPluginProperties->setOptionsText(__('Options'));
|
||||
|
||||
// create the root group that will be the options field for
|
||||
// $exportPluginProperties
|
||||
// this will be shown as "Format specific options"
|
||||
$exportSpecificOptions = new PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup(
|
||||
'Format Specific Options'
|
||||
);
|
||||
|
||||
// general options main group
|
||||
$generalOptions = new PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup(
|
||||
'general_opts'
|
||||
);
|
||||
|
||||
// optional :
|
||||
// create primary items and add them to the group
|
||||
// type - one of the classes listed in libraries/properties/options/items/
|
||||
// name - form element name
|
||||
// text - description in GUI
|
||||
// size - size of text element
|
||||
// len - maximal size of input
|
||||
// values - possible values of the item
|
||||
$leaf = new PhpMyAdmin\Properties\Options\Items\RadioPropertyItem(
|
||||
'structure_or_data'
|
||||
);
|
||||
$leaf->setValues(
|
||||
[
|
||||
'structure' => __('structure'),
|
||||
'data' => __('data'),
|
||||
'structure_and_data' => __('structure and data'),
|
||||
]
|
||||
);
|
||||
$generalOptions->addProperty($leaf);
|
||||
|
||||
// add the main group to the root group
|
||||
$exportSpecificOptions->addProperty($generalOptions);
|
||||
|
||||
// set the options for the export plugin property item
|
||||
$exportPluginProperties->setOptions($exportSpecificOptions);
|
||||
$this->properties = $exportPluginProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export header
|
||||
*
|
||||
* @return bool Whether it succeeded
|
||||
*/
|
||||
public function exportHeader()
|
||||
{
|
||||
// implementation
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs export footer
|
||||
*
|
||||
* @return bool Whether it succeeded
|
||||
*/
|
||||
public function exportFooter()
|
||||
{
|
||||
// implementation
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database header
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $dbAlias Aliases of db
|
||||
*
|
||||
* @return bool Whether it succeeded
|
||||
*/
|
||||
public function exportDBHeader($db, $dbAlias = '')
|
||||
{
|
||||
// implementation
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs database footer
|
||||
*
|
||||
* @param string $db Database name
|
||||
*
|
||||
* @return bool Whether it succeeded
|
||||
*/
|
||||
public function exportDBFooter($db)
|
||||
{
|
||||
// implementation
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs CREATE DATABASE statement
|
||||
*
|
||||
* @param string $db Database name
|
||||
* @param string $exportType 'server', 'database', 'table'
|
||||
* @param string $dbAlias Aliases of db
|
||||
*
|
||||
* @return bool Whether it succeeded
|
||||
*/
|
||||
public function exportDBCreate($db, $exportType, $dbAlias = '')
|
||||
{
|
||||
// implementation
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the content of a table in [Name] format
|
||||
*
|
||||
* @param string $db database name
|
||||
* @param string $table table name
|
||||
* @param string $crlf the end of line sequence
|
||||
* @param string $errorUrl the url to go back in case of error
|
||||
* @param string $sqlQuery SQL query for obtaining data
|
||||
* @param array $aliases Aliases of db/table/columns
|
||||
*
|
||||
* @return bool Whether it succeeded
|
||||
*/
|
||||
public function exportData(
|
||||
$db,
|
||||
$table,
|
||||
$crlf,
|
||||
$errorUrl,
|
||||
$sqlQuery,
|
||||
array $aliases = []
|
||||
) {
|
||||
// implementation;
|
||||
return true;
|
||||
}
|
||||
|
||||
// optional - implement other methods defined in PhpMyAdmin\Plugins\ExportPlugin.php:
|
||||
// - exportRoutines()
|
||||
// - exportStructure()
|
||||
// - getTableDefStandIn()
|
||||
// - getTriggers()
|
||||
|
||||
// optional - implement other private methods in order to avoid
|
||||
// having huge methods or avoid duplicate code. Make use of them
|
||||
// as well as of the getters and setters declared both here
|
||||
// and in the PhpMyAdmin\Plugins\ExportPlugin class
|
||||
|
||||
|
||||
// optional:
|
||||
/* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
/**
|
||||
* Getter description
|
||||
*/
|
||||
private function getMyOptionalVariable(): VariableType
|
||||
{
|
||||
return $this->myOptionalVariable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter description
|
||||
*/
|
||||
private function setMyOptionalVariable(VariableType $my_optional_variable): void
|
||||
{
|
||||
$this->myOptionalVariable = $my_optional_variable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter description
|
||||
*/
|
||||
private function getGlobalVariableName(): VariableType
|
||||
{
|
||||
return $this->globalVariableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter description
|
||||
*/
|
||||
private function setGlobalVariableName(VariableType $global_variable_name): void
|
||||
{
|
||||
$this->globalVariableName = $global_variable_name;
|
||||
}
|
||||
}
|
||||
```
|
Loading…
Add table
Add a link
Reference in a new issue