aboutsummaryrefslogtreecommitdiff
path: root/srcs/phpmyadmin/libraries/classes/Plugins/Export
diff options
context:
space:
mode:
authorCharles <sircharlesaze@gmail.com>2020-01-09 10:55:03 +0100
committerCharles <sircharlesaze@gmail.com>2020-01-09 13:09:38 +0100
commit04d6d5ca99ebfd1cebb8ce06618fb3811fc1a8aa (patch)
tree5c691241355c943a3c68ddb06b8cf8c60aa11319 /srcs/phpmyadmin/libraries/classes/Plugins/Export
parent7e0d85db834d6351ed85d01e5126ac31dc510b86 (diff)
downloadft_server-04d6d5ca99ebfd1cebb8ce06618fb3811fc1a8aa.tar.gz
ft_server-04d6d5ca99ebfd1cebb8ce06618fb3811fc1a8aa.tar.bz2
ft_server-04d6d5ca99ebfd1cebb8ce06618fb3811fc1a8aa.zip
phpmyadmin working
Diffstat (limited to 'srcs/phpmyadmin/libraries/classes/Plugins/Export')
-rw-r--r--srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportCodegen.php447
-rw-r--r--srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportCsv.php347
-rw-r--r--srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportExcel.php90
-rw-r--r--srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportHtmlword.php670
-rw-r--r--srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportJson.php295
-rw-r--r--srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportLatex.php709
-rw-r--r--srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportMediawiki.php386
-rw-r--r--srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportOds.php345
-rw-r--r--srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportOdt.php813
-rw-r--r--srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportPdf.php395
-rw-r--r--srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportPhparray.php259
-rw-r--r--srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportSql.php2915
-rw-r--r--srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportTexytext.php624
-rw-r--r--srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportXml.php593
-rw-r--r--srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportYaml.php230
-rw-r--r--srcs/phpmyadmin/libraries/classes/Plugins/Export/Helpers/Pdf.php855
-rw-r--r--srcs/phpmyadmin/libraries/classes/Plugins/Export/Helpers/TableProperty.php277
-rw-r--r--srcs/phpmyadmin/libraries/classes/Plugins/Export/README255
18 files changed, 10505 insertions, 0 deletions
diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportCodegen.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportCodegen.php
new file mode 100644
index 0000000..8a29538
--- /dev/null
+++ b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportCodegen.php
@@ -0,0 +1,447 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * Set of functions used to build NHibernate dumps of tables
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage CodeGen
+ */
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Plugins\Export;
+
+use PhpMyAdmin\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;
+
+/**
+ * Handles the export for the CodeGen class
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage CodeGen
+ */
+class ExportCodegen extends ExportPlugin
+{
+ /**
+ * CodeGen Formats
+ *
+ * @var array
+ */
+ private $_cgFormats;
+ /**
+ * CodeGen Handlers
+ *
+ * @var array
+ */
+ private $_cgHandlers;
+
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ // initialize the specific export CodeGen variables
+ $this->initSpecificVariables();
+ $this->setProperties();
+ }
+
+ /**
+ * Initialize the local variables that are used for export CodeGen
+ *
+ * @return void
+ */
+ protected function initSpecificVariables()
+ {
+ $this->_setCgFormats(
+ [
+ "NHibernate C# DO",
+ "NHibernate XML",
+ ]
+ );
+
+ $this->_setCgHandlers(
+ [
+ "_handleNHibernateCSBody",
+ "_handleNHibernateXMLBody",
+ ]
+ );
+ }
+
+ /**
+ * Sets the export CodeGen properties
+ *
+ * @return void
+ */
+ protected function setProperties()
+ {
+ $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);
+ $this->properties = $exportPluginProperties;
+ }
+
+ /**
+ * Outputs export header
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportHeader()
+ {
+ return true;
+ }
+
+ /**
+ * Outputs export footer
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportFooter()
+ {
+ return true;
+ }
+
+ /**
+ * Outputs database header
+ *
+ * @param string $db Database name
+ * @param string $db_alias Aliases of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBHeader($db, $db_alias = '')
+ {
+ return true;
+ }
+
+ /**
+ * Outputs database footer
+ *
+ * @param string $db Database name
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBFooter($db)
+ {
+ return true;
+ }
+
+ /**
+ * Outputs CREATE DATABASE statement
+ *
+ * @param string $db Database name
+ * @param string $export_type 'server', 'database', 'table'
+ * @param string $db_alias Aliases of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBCreate($db, $export_type, $db_alias = '')
+ {
+ 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 $error_url the url to go back in case of error
+ * @param string $sql_query SQL query for obtaining data
+ * @param array $aliases Aliases of db/table/columns
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportData(
+ $db,
+ $table,
+ $crlf,
+ $error_url,
+ $sql_query,
+ array $aliases = []
+ ) {
+ $CG_FORMATS = $this->_getCgFormats();
+ $CG_HANDLERS = $this->_getCgHandlers();
+
+ $format = $GLOBALS['codegen_format'];
+ if (isset($CG_FORMATS[$format])) {
+ $method = $CG_HANDLERS[$format];
+
+ return $this->export->outputHandler(
+ $this->$method($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 = 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 = [])
+ {
+ $db_alias = $db;
+ $table_alias = $table;
+ $this->initAlias($aliases, $db_alias, $table_alias);
+ $lines = [];
+
+ $result = $GLOBALS['dbi']->query(
+ sprintf(
+ 'DESC %s.%s',
+ Util::backquote($db),
+ Util::backquote($table)
+ )
+ );
+ if ($result) {
+ /** @var TableProperty[] $tableProperties */
+ $tableProperties = [];
+ while ($row = $GLOBALS['dbi']->fetchRow($result)) {
+ $col_as = $this->getAlias($aliases, $row[0], 'col', $db, $table);
+ if (! empty($col_as)) {
+ $row[0] = $col_as;
+ }
+ $tableProperties[] = new TableProperty($row);
+ }
+ $GLOBALS['dbi']->freeResult($result);
+ $lines[] = 'using System;';
+ $lines[] = 'using System.Collections;';
+ $lines[] = 'using System.Collections.Generic;';
+ $lines[] = 'using System.Text;';
+ $lines[] = 'namespace ' . ExportCodegen::cgMakeIdentifier($db_alias);
+ $lines[] = '{';
+ $lines[] = ' #region '
+ . ExportCodegen::cgMakeIdentifier($table_alias);
+ $lines[] = ' public class '
+ . ExportCodegen::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 '
+ . ExportCodegen::cgMakeIdentifier($table_alias) . '() { }';
+ $temp = [];
+ foreach ($tableProperties as $tableProperty) {
+ if (! $tableProperty->isPK()) {
+ $temp[] = $tableProperty->formatCs(
+ '#dotNetPrimitiveType# #name#'
+ );
+ }
+ }
+ $lines[] = ' public '
+ . ExportCodegen::cgMakeIdentifier($table_alias)
+ . '('
+ . implode(', ', $temp)
+ . ')';
+ $lines[] = ' {';
+ foreach ($tableProperties as $tableProperty) {
+ if (! $tableProperty->isPK()) {
+ $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 = []
+ ) {
+ $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="' . ExportCodegen::cgMakeIdentifier($db_alias) . '" '
+ . 'assembly="' . ExportCodegen::cgMakeIdentifier($db_alias) . '">';
+ $lines[] = ' <class '
+ . 'name="' . ExportCodegen::cgMakeIdentifier($table_alias) . '" '
+ . 'table="' . ExportCodegen::cgMakeIdentifier($table_alias) . '">';
+ $result = $GLOBALS['dbi']->query(
+ sprintf(
+ "DESC %s.%s",
+ Util::backquote($db),
+ Util::backquote($table)
+ )
+ );
+ if ($result) {
+ while ($row = $GLOBALS['dbi']->fetchRow($result)) {
+ $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>'
+ );
+ }
+ }
+ $GLOBALS['dbi']->freeResult($result);
+ }
+ $lines[] = ' </class>';
+ $lines[] = '</hibernate-mapping>';
+
+ return implode($crlf, $lines);
+ }
+
+
+ /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */
+
+ /**
+ * Getter for CodeGen formats
+ *
+ * @return array
+ */
+ private function _getCgFormats()
+ {
+ return $this->_cgFormats;
+ }
+
+ /**
+ * Setter for CodeGen formats
+ *
+ * @param array $CG_FORMATS contains CodeGen Formats
+ *
+ * @return void
+ */
+ private function _setCgFormats(array $CG_FORMATS)
+ {
+ $this->_cgFormats = $CG_FORMATS;
+ }
+
+ /**
+ * Getter for CodeGen handlers
+ *
+ * @return array
+ */
+ private function _getCgHandlers()
+ {
+ return $this->_cgHandlers;
+ }
+
+ /**
+ * Setter for CodeGen handlers
+ *
+ * @param array $CG_HANDLERS contains CodeGen handler methods
+ *
+ * @return void
+ */
+ private function _setCgHandlers(array $CG_HANDLERS)
+ {
+ $this->_cgHandlers = $CG_HANDLERS;
+ }
+}
diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportCsv.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportCsv.php
new file mode 100644
index 0000000..8e5a319
--- /dev/null
+++ b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportCsv.php
@@ -0,0 +1,347 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * CSV export code
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage CSV
+ */
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Plugins\Export;
+
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\Export;
+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\SelectPropertyItem;
+use PhpMyAdmin\Properties\Options\Items\TextPropertyItem;
+use PhpMyAdmin\Properties\Plugins\ExportPluginProperties;
+
+/**
+ * Handles the export for the CSV format
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage CSV
+ */
+class ExportCsv extends ExportPlugin
+{
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setProperties();
+ }
+
+ /**
+ * Sets the export CSV properties
+ *
+ * @return void
+ */
+ protected function setProperties()
+ {
+ $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);
+ $this->properties = $exportPluginProperties;
+ }
+
+ /**
+ * Outputs export header
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportHeader()
+ {
+ global $what, $csv_terminated, $csv_separator, $csv_enclosed, $csv_escaped;
+ //Enable columns names by default for CSV
+ if ($what == 'csv') {
+ $GLOBALS['csv_columns'] = 'yes';
+ }
+ // 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'] = 'yes';
+ }
+ } 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
+ );
+ } // end if
+ $csv_separator = str_replace('\\t', "\011", $csv_separator);
+ }
+
+ return true;
+ }
+
+ /**
+ * Outputs export footer
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportFooter()
+ {
+ return true;
+ }
+
+ /**
+ * Outputs database header
+ *
+ * @param string $db Database name
+ * @param string $db_alias Alias of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBHeader($db, $db_alias = '')
+ {
+ return true;
+ }
+
+ /**
+ * Outputs database footer
+ *
+ * @param string $db Database name
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBFooter($db)
+ {
+ return true;
+ }
+
+ /**
+ * Outputs CREATE DATABASE statement
+ *
+ * @param string $db Database name
+ * @param string $export_type 'server', 'database', 'table'
+ * @param string $db_alias Aliases of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBCreate($db, $export_type, $db_alias = '')
+ {
+ 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 $error_url the url to go back in case of error
+ * @param string $sql_query SQL query for obtaining data
+ * @param array $aliases Aliases of db/table/columns
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportData(
+ $db,
+ $table,
+ $crlf,
+ $error_url,
+ $sql_query,
+ array $aliases = []
+ ) {
+ global $what, $csv_terminated, $csv_separator, $csv_enclosed, $csv_escaped;
+
+ $db_alias = $db;
+ $table_alias = $table;
+ $this->initAlias($aliases, $db_alias, $table_alias);
+
+ // Gets the data from the database
+ $result = $GLOBALS['dbi']->query(
+ $sql_query,
+ DatabaseInterface::CONNECT_USER,
+ DatabaseInterface::QUERY_UNBUFFERED
+ );
+ $fields_cnt = $GLOBALS['dbi']->numFields($result);
+
+ // If required, get fields name at the first line
+ if (isset($GLOBALS['csv_columns'])) {
+ $schema_insert = '';
+ for ($i = 0; $i < $fields_cnt; $i++) {
+ $col_as = $GLOBALS['dbi']->fieldName($result, $i);
+ 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;
+ } // end for
+ $schema_insert = trim(mb_substr($schema_insert, 0, -1));
+ if (! $this->export->outputHandler($schema_insert . $csv_terminated)) {
+ return false;
+ }
+ } // end if
+
+ // Format the data
+ while ($row = $GLOBALS['dbi']->fetchRow($result)) {
+ $schema_insert = '';
+ for ($j = 0; $j < $fields_cnt; $j++) {
+ if (! isset($row[$j]) || $row[$j] === null) {
+ $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) {
+ $schema_insert .= $csv_separator;
+ }
+ } // end for
+
+ if (! $this->export->outputHandler($schema_insert . $csv_terminated)) {
+ return false;
+ }
+ } // end while
+ $GLOBALS['dbi']->freeResult($result);
+
+ return true;
+ }
+}
diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportExcel.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportExcel.php
new file mode 100644
index 0000000..e778d20
--- /dev/null
+++ b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportExcel.php
@@ -0,0 +1,90 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * Class for exporting CSV dumps of tables for excel
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage CSV-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;
+
+/**
+ * Handles the export for the CSV-Excel format
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage CSV-Excel
+ */
+class ExportExcel extends ExportCsv
+{
+ /**
+ * Sets the export CSV for Excel properties
+ *
+ * @return void
+ */
+ protected function setProperties()
+ {
+ $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);
+ $this->properties = $exportPluginProperties;
+ }
+}
diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportHtmlword.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportHtmlword.php
new file mode 100644
index 0000000..cbf4fce
--- /dev/null
+++ b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportHtmlword.php
@@ -0,0 +1,670 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * HTML-Word export code
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage HTML-Word
+ */
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Plugins\Export;
+
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\Export;
+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\Relation;
+use PhpMyAdmin\Transformations;
+use PhpMyAdmin\Util;
+
+/**
+ * Handles the export for the HTML-Word format
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage HTML-Word
+ */
+class ExportHtmlword extends ExportPlugin
+{
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setProperties();
+ }
+
+ /**
+ * Sets the export HTML-Word properties
+ *
+ * @return void
+ */
+ protected function setProperties()
+ {
+ $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);
+ $this->properties = $exportPluginProperties;
+ }
+
+ /**
+ * Outputs export header
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportHeader()
+ {
+ 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='
+ . (isset($charset) ? $charset : 'utf-8') . '" />
+ </head>
+ <body>'
+ );
+ }
+
+ /**
+ * Outputs export footer
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportFooter()
+ {
+ return $this->export->outputHandler('</body></html>');
+ }
+
+ /**
+ * Outputs database header
+ *
+ * @param string $db Database name
+ * @param string $db_alias Aliases of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBHeader($db, $db_alias = '')
+ {
+ if (empty($db_alias)) {
+ $db_alias = $db;
+ }
+
+ return $this->export->outputHandler(
+ '<h1>' . __('Database') . ' ' . htmlspecialchars($db_alias) . '</h1>'
+ );
+ }
+
+ /**
+ * Outputs database footer
+ *
+ * @param string $db Database name
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBFooter($db)
+ {
+ return true;
+ }
+
+ /**
+ * Outputs CREATE DATABASE statement
+ *
+ * @param string $db Database name
+ * @param string $export_type 'server', 'database', 'table'
+ * @param string $db_alias Aliases of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBCreate($db, $export_type, $db_alias = '')
+ {
+ 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 $error_url the url to go back in case of error
+ * @param string $sql_query SQL query for obtaining data
+ * @param array $aliases Aliases of db/table/columns
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportData(
+ $db,
+ $table,
+ $crlf,
+ $error_url,
+ $sql_query,
+ array $aliases = []
+ ) {
+ global $what;
+
+ $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 class="width100" cellspacing="1">'
+ )
+ ) {
+ return false;
+ }
+
+ // Gets the data from the database
+ $result = $GLOBALS['dbi']->query(
+ $sql_query,
+ DatabaseInterface::CONNECT_USER,
+ DatabaseInterface::QUERY_UNBUFFERED
+ );
+ $fields_cnt = $GLOBALS['dbi']->numFields($result);
+
+ // If required, get fields name at the first line
+ if (isset($GLOBALS['htmlword_columns'])) {
+ $schema_insert = '<tr class="print-category">';
+ for ($i = 0; $i < $fields_cnt; $i++) {
+ $col_as = $GLOBALS['dbi']->fieldName($result, $i);
+ 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>';
+ } // end for
+ $schema_insert .= '</tr>';
+ if (! $this->export->outputHandler($schema_insert)) {
+ return false;
+ }
+ } // end if
+
+ // Format the data
+ while ($row = $GLOBALS['dbi']->fetchRow($result)) {
+ $schema_insert = '<tr class="print-category">';
+ for ($j = 0; $j < $fields_cnt; $j++) {
+ if (! isset($row[$j]) || $row[$j] === null) {
+ $value = $GLOBALS[$what . '_null'];
+ } elseif ($row[$j] == '0' || $row[$j] != '') {
+ $value = $row[$j];
+ } else {
+ $value = '';
+ }
+ $schema_insert .= '<td class="print">'
+ . htmlspecialchars((string) $value)
+ . '</td>';
+ } // end for
+ $schema_insert .= '</tr>';
+ if (! $this->export->outputHandler($schema_insert)) {
+ return false;
+ }
+ } // end while
+ $GLOBALS['dbi']->freeResult($result);
+
+ 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 = [])
+ {
+ $schema_insert = '<table class="width100" 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 = $GLOBALS['dbi']->getTableIndexes($db, $view);
+ foreach ($keys as $key) {
+ if ($key['Non_unique'] == 0) {
+ $unique_keys[] = $key['Column_name'];
+ }
+ }
+
+ $columns = $GLOBALS['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.php 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 = []
+ ) {
+ // set $cfgRelation here, because there is a chance that it's modified
+ // since the class initialization
+ global $cfgRelation;
+
+ $schema_insert = '';
+
+ /**
+ * Gets fields properties
+ */
+ $GLOBALS['dbi']->selectDb($db);
+
+ // Check if we can use Relations
+ list($res_rel, $have_rel) = $this->relation->getRelationsAndStatus(
+ $do_relation && ! empty($cfgRelation['relation']),
+ $db,
+ $table
+ );
+
+ /**
+ * Displays the table structure
+ */
+ $schema_insert .= '<table class="width100" 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 && $cfgRelation['mimework']) {
+ $schema_insert .= '<td class="print"><strong>'
+ . __('Media (MIME) type')
+ . '</strong></td>';
+ $mime_map = $this->transformations->getMime($db, $table, true);
+ }
+ $schema_insert .= '</tr>';
+
+ $columns = $GLOBALS['dbi']->getColumns($db, $table);
+ /**
+ * Get the unique keys in the table
+ */
+ $unique_keys = [];
+ $keys = $GLOBALS['dbi']->getTableIndexes($db, $table);
+ foreach ($keys as $key) {
+ if ($key['Non_unique'] == 0) {
+ $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 && $cfgRelation['commwork']) {
+ $schema_insert .= '<td class="print">'
+ . (isset($comments[$field_name])
+ ? htmlspecialchars($comments[$field_name])
+ : '') . '</td>';
+ }
+ if ($do_mime && $cfgRelation['mimework']) {
+ $schema_insert .= '<td class="print">'
+ . (isset($mime_map[$field_name]) ?
+ htmlspecialchars(
+ str_replace('_', '/', $mime_map[$field_name]['mimetype'])
+ )
+ : '') . '</td>';
+ }
+
+ $schema_insert .= '</tr>';
+ } // end foreach
+
+ $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)
+ {
+ $dump = '<table class="width100" 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 = $GLOBALS['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 $error_url the url to go back in case of error
+ * @param string $export_mode 'create_table', 'triggers', 'create_view',
+ * 'stand_in'
+ * @param string $export_type '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.php 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
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportStructure(
+ $db,
+ $table,
+ $crlf,
+ $error_url,
+ $export_mode,
+ $export_type,
+ $do_relation = false,
+ $do_comments = false,
+ $do_mime = false,
+ $dates = false,
+ array $aliases = []
+ ) {
+ $db_alias = $db;
+ $table_alias = $table;
+ $this->initAlias($aliases, $db_alias, $table_alias);
+
+ $dump = '';
+
+ switch ($export_mode) {
+ 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 = $GLOBALS['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);
+ } // end switch
+
+ 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 = '&nbsp;';
+ }
+
+ 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(isset($column['Default']) ? $column['Default'] : '')
+ . '</td>';
+
+ return $definition;
+ }
+}
diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportJson.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportJson.php
new file mode 100644
index 0000000..4ebfbbe
--- /dev/null
+++ b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportJson.php
@@ -0,0 +1,295 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * Set of methods used to build dumps of tables as JSON
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage JSON
+ */
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Plugins\Export;
+
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\Export;
+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;
+
+/**
+ * Handles the export for the JSON format
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage JSON
+ */
+class ExportJson extends ExportPlugin
+{
+ private $first = true;
+
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setProperties();
+ }
+
+ /**
+ * Encodes the data into JSON
+ *
+ * @param mixed $data Data to encode
+ *
+ * @return string
+ */
+ 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);
+ }
+
+ /**
+ * Sets the export JSON properties
+ *
+ * @return void
+ */
+ protected function setProperties()
+ {
+ $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);
+ $this->properties = $exportPluginProperties;
+ }
+
+ /**
+ * Outputs export header
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportHeader()
+ {
+ global $crlf;
+
+ $meta = [
+ 'type' => 'header',
+ 'version' => PMA_VERSION,
+ 'comment' => 'Export to JSON plugin for PHPMyAdmin',
+ ];
+
+ return $this->export->outputHandler(
+ '[' . $crlf . $this->encode($meta) . ',' . $crlf
+ );
+ }
+
+ /**
+ * Outputs export footer
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportFooter()
+ {
+ global $crlf;
+
+ return $this->export->outputHandler(']' . $crlf);
+ }
+
+ /**
+ * Outputs database header
+ *
+ * @param string $db Database name
+ * @param string $db_alias Aliases of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBHeader($db, $db_alias = '')
+ {
+ global $crlf;
+
+ if (empty($db_alias)) {
+ $db_alias = $db;
+ }
+
+ $meta = [
+ 'type' => 'database',
+ 'name' => $db_alias,
+ ];
+
+ return $this->export->outputHandler(
+ $this->encode($meta) . ',' . $crlf
+ );
+ }
+
+ /**
+ * Outputs database footer
+ *
+ * @param string $db Database name
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBFooter($db)
+ {
+ return true;
+ }
+
+ /**
+ * Outputs CREATE DATABASE statement
+ *
+ * @param string $db Database name
+ * @param string $export_type 'server', 'database', 'table'
+ * @param string $db_alias Aliases of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBCreate($db, $export_type, $db_alias = '')
+ {
+ 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 $error_url the url to go back in case of error
+ * @param string $sql_query SQL query for obtaining data
+ * @param array $aliases Aliases of db/table/columns
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportData(
+ $db,
+ $table,
+ $crlf,
+ $error_url,
+ $sql_query,
+ array $aliases = []
+ ) {
+ $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@@",
+ ]
+ );
+ list($header, $footer) = explode('"@@DATA@@"', $buffer);
+
+ if (! $this->export->outputHandler($header . $crlf . '[' . $crlf)) {
+ return false;
+ }
+
+ $result = $GLOBALS['dbi']->query(
+ $sql_query,
+ DatabaseInterface::CONNECT_USER,
+ DatabaseInterface::QUERY_UNBUFFERED
+ );
+ $columns_cnt = $GLOBALS['dbi']->numFields($result);
+ $fieldsMeta = $GLOBALS['dbi']->getFieldsMeta($result);
+
+ $columns = [];
+ for ($i = 0; $i < $columns_cnt; $i++) {
+ $col_as = $GLOBALS['dbi']->fieldName($result, $i);
+ 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 = $GLOBALS['dbi']->fetchRow($result)) {
+ $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++) {
+ if ($fieldsMeta[$i]->type === 'geometry') {
+ // export GIS 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;
+ }
+ }
+
+ if (! $this->export->outputHandler($crlf . ']' . $crlf . $footer . $crlf)) {
+ return false;
+ }
+
+ $GLOBALS['dbi']->freeResult($result);
+
+ return true;
+ }
+}
diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportLatex.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportLatex.php
new file mode 100644
index 0000000..e215300
--- /dev/null
+++ b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportLatex.php
@@ -0,0 +1,709 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * Set of methods used to build dumps of tables as Latex
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage Latex
+ */
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Plugins\Export;
+
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\Export;
+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\Relation;
+use PhpMyAdmin\Transformations;
+use PhpMyAdmin\Util;
+
+/**
+ * Handles the export for the Latex format
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage Latex
+ */
+class ExportLatex extends ExportPlugin
+{
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ // initialize the specific export sql variables
+ $this->initSpecificVariables();
+ $this->setProperties();
+ }
+
+ /**
+ * Initialize the local variables that are used for export Latex
+ *
+ * @return void
+ */
+ protected function initSpecificVariables()
+ {
+ /* Messages used in default captions */
+ $GLOBALS['strLatexContent'] = __('Content of table @TABLE@');
+ $GLOBALS['strLatexContinued'] = __('(continued)');
+ $GLOBALS['strLatexStructure'] = __('Structure of table @TABLE@');
+ }
+
+ /**
+ * Sets the export Latex properties
+ *
+ * @return void
+ */
+ protected function setProperties()
+ {
+ 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);
+ if (! empty($GLOBALS['cfgRelation']['relation'])) {
+ $leaf = new BoolPropertyItem(
+ "relation",
+ __('Display foreign key relationships')
+ );
+ $structureOptions->addProperty($leaf);
+ }
+ $leaf = new BoolPropertyItem(
+ "comments",
+ __('Display comments')
+ );
+ $structureOptions->addProperty($leaf);
+ if (! empty($GLOBALS['cfgRelation']['mimework'])) {
+ $leaf = new BoolPropertyItem(
+ "mime",
+ __('Display media (MIME) 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);
+ $this->properties = $exportPluginProperties;
+ }
+
+ /**
+ * Outputs export header
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportHeader()
+ {
+ global $crlf;
+ global $cfg;
+
+ $head = '% phpMyAdmin LaTeX Dump' . $crlf
+ . '% version ' . PMA_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:') . ' ' . $GLOBALS['dbi']->getVersionString() . $crlf
+ . '% ' . __('PHP Version:') . ' ' . PHP_VERSION . $crlf;
+
+ return $this->export->outputHandler($head);
+ }
+
+ /**
+ * Outputs export footer
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportFooter()
+ {
+ return true;
+ }
+
+ /**
+ * Outputs database header
+ *
+ * @param string $db Database name
+ * @param string $db_alias Aliases of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBHeader($db, $db_alias = '')
+ {
+ if (empty($db_alias)) {
+ $db_alias = $db;
+ }
+ global $crlf;
+ $head = '% ' . $crlf
+ . '% ' . __('Database:') . ' \'' . $db_alias . '\'' . $crlf
+ . '% ' . $crlf;
+
+ return $this->export->outputHandler($head);
+ }
+
+ /**
+ * Outputs database footer
+ *
+ * @param string $db Database name
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBFooter($db)
+ {
+ return true;
+ }
+
+ /**
+ * Outputs CREATE DATABASE statement
+ *
+ * @param string $db Database name
+ * @param string $export_type 'server', 'database', 'table'
+ * @param string $db_alias Aliases of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBCreate($db, $export_type, $db_alias = '')
+ {
+ 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 $error_url the url to go back in case of error
+ * @param string $sql_query SQL query for obtaining data
+ * @param array $aliases Aliases of db/table/columns
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportData(
+ $db,
+ $table,
+ $crlf,
+ $error_url,
+ $sql_query,
+ array $aliases = []
+ ) {
+ $db_alias = $db;
+ $table_alias = $table;
+ $this->initAlias($aliases, $db_alias, $table_alias);
+
+ $result = $GLOBALS['dbi']->tryQuery(
+ $sql_query,
+ DatabaseInterface::CONNECT_USER,
+ DatabaseInterface::QUERY_UNBUFFERED
+ );
+
+ $columns_cnt = $GLOBALS['dbi']->numFields($result);
+ $columns = [];
+ $columns_alias = [];
+ for ($i = 0; $i < $columns_cnt; $i++) {
+ $columns[$i] = $col_as = $GLOBALS['dbi']->fieldName($result, $i);
+ 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 = $GLOBALS['dbi']->fetchAssoc($result)) {
+ $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;
+ if (! $this->export->outputHandler($buffer)) {
+ return false;
+ }
+
+ $GLOBALS['dbi']->freeResult($result);
+
+ return true;
+ } // end getTableLaTeX
+
+ /**
+ * Outputs table's structure
+ *
+ * @param string $db database name
+ * @param string $table table name
+ * @param string $crlf the end of line sequence
+ * @param string $error_url the url to go back in case of error
+ * @param string $export_mode 'create_table', 'triggers', 'create_view',
+ * 'stand_in'
+ * @param string $export_type '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.php 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
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportStructure(
+ $db,
+ $table,
+ $crlf,
+ $error_url,
+ $export_mode,
+ $export_type,
+ $do_relation = false,
+ $do_comments = false,
+ $do_mime = false,
+ $dates = false,
+ array $aliases = []
+ ) {
+ $db_alias = $db;
+ $table_alias = $table;
+ $this->initAlias($aliases, $db_alias, $table_alias);
+
+ global $cfgRelation;
+
+ /* We do not export triggers */
+ if ($export_mode == 'triggers') {
+ return true;
+ }
+
+ /**
+ * Get the unique keys in the table
+ */
+ $unique_keys = [];
+ $keys = $GLOBALS['dbi']->getTableIndexes($db, $table);
+ foreach ($keys as $key) {
+ if ($key['Non_unique'] == 0) {
+ $unique_keys[] = $key['Column_name'];
+ }
+ }
+
+ /**
+ * Gets fields properties
+ */
+ $GLOBALS['dbi']->selectDb($db);
+
+ // Check if we can use Relations
+ list($res_rel, $have_rel) = $this->relation->getRelationsAndStatus(
+ $do_relation && ! empty($cfgRelation['relation']),
+ $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 && $cfgRelation['mimework']) {
+ $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 && $cfgRelation['mimework']) {
+ $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 = $GLOBALS['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" . (isset($row['Default']) ? $row['Default'] : '');
+
+ if ($do_relation && $have_rel) {
+ $local_buffer .= "\000";
+ $local_buffer .= $this->getRelationString(
+ $res_rel,
+ $field_name,
+ $db,
+ $aliases
+ );
+ }
+ if ($do_comments && $cfgRelation['commwork']) {
+ $local_buffer .= "\000";
+ if (isset($comments[$field_name])) {
+ $local_buffer .= $comments[$field_name];
+ }
+ }
+ if ($do_mime && $cfgRelation['mimework']) {
+ $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 = 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 = 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;
+ }
+ } // end while
+
+ $buffer = ' \\end{longtable}' . $crlf;
+
+ return $this->export->outputHandler($buffer);
+ } // end of the 'exportStructure' method
+
+ /**
+ * 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;
+ }
+}
diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportMediawiki.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportMediawiki.php
new file mode 100644
index 0000000..9d971cb
--- /dev/null
+++ b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportMediawiki.php
@@ -0,0 +1,386 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * Set of functions used to build MediaWiki dumps of tables
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage MediaWiki
+ */
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Plugins\Export;
+
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\Export;
+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;
+
+/**
+ * Handles the export for the MediaWiki class
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage MediaWiki
+ */
+class ExportMediawiki extends ExportPlugin
+{
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setProperties();
+ }
+
+ /**
+ * Sets the export MediaWiki properties
+ *
+ * @return void
+ */
+ protected function setProperties()
+ {
+ $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);
+ $this->properties = $exportPluginProperties;
+ }
+
+ /**
+ * Outputs export header
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportHeader()
+ {
+ return true;
+ }
+
+ /**
+ * Outputs export footer
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportFooter()
+ {
+ return true;
+ }
+
+ /**
+ * Outputs database header
+ *
+ * @param string $db Database name
+ * @param string $db_alias Alias of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBHeader($db, $db_alias = '')
+ {
+ return true;
+ }
+
+ /**
+ * Outputs database footer
+ *
+ * @param string $db Database name
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBFooter($db)
+ {
+ return true;
+ }
+
+ /**
+ * Outputs CREATE DATABASE statement
+ *
+ * @param string $db Database name
+ * @param string $export_type 'server', 'database', 'table'
+ * @param string $db_alias Aliases of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBCreate($db, $export_type, $db_alias = '')
+ {
+ 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 $error_url the url to go back in case of error
+ * @param string $export_mode 'create_table','triggers','create_view',
+ * 'stand_in'
+ * @param string $export_type '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.php 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
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportStructure(
+ $db,
+ $table,
+ $crlf,
+ $error_url,
+ $export_mode,
+ $export_type,
+ $do_relation = false,
+ $do_comments = false,
+ $do_mime = false,
+ $dates = false,
+ array $aliases = []
+ ) {
+ $db_alias = $db;
+ $table_alias = $table;
+ $this->initAlias($aliases, $db_alias, $table_alias);
+
+ $output = '';
+ switch ($export_mode) {
+ case 'create_table':
+ $columns = $GLOBALS['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;
+ } // end switch
+
+ 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 $error_url the url to go back in case of error
+ * @param string $sql_query SQL query for obtaining data
+ * @param array $aliases Aliases of db/table/columns
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportData(
+ $db,
+ $table,
+ $crlf,
+ $error_url,
+ $sql_query,
+ array $aliases = []
+ ) {
+ $db_alias = $db;
+ $table_alias = $table;
+ $this->initAlias($aliases, $db_alias, $table_alias);
+
+ // Print data comment
+ $output = $this->_exportComment(
+ "Table data for " . Util::backquote($table_alias)
+ );
+
+ // 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 = $GLOBALS['dbi']->getColumnNames($db, $table);
+
+ // Add column names as table headers
+ if ($column_names !== null) {
+ // 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 = $GLOBALS['dbi']->query(
+ $sql_query,
+ DatabaseInterface::CONNECT_USER,
+ DatabaseInterface::QUERY_UNBUFFERED
+ );
+ $fields_cnt = $GLOBALS['dbi']->numFields($result);
+
+ while ($row = $GLOBALS['dbi']->fetchRow($result)) {
+ $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 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";
+ }
+}
diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportOds.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportOds.php
new file mode 100644
index 0000000..bc062da
--- /dev/null
+++ b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportOds.php
@@ -0,0 +1,345 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * Set of functions used to build OpenDocument Spreadsheet dumps of tables
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage ODS
+ */
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Plugins\Export;
+
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\Export;
+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;
+
+/**
+ * Handles the export for the ODS class
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage ODS
+ */
+class ExportOds extends ExportPlugin
+{
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $GLOBALS['ods_buffer'] = '';
+ $this->setProperties();
+ }
+
+ /**
+ * Sets the export ODS properties
+ *
+ * @return void
+ */
+ protected function setProperties()
+ {
+ $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);
+ $this->properties = $exportPluginProperties;
+ }
+
+ /**
+ * Outputs export header
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportHeader()
+ {
+ $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
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportFooter()
+ {
+ $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 $db_alias Aliases of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBHeader($db, $db_alias = '')
+ {
+ return true;
+ }
+
+ /**
+ * Outputs database footer
+ *
+ * @param string $db Database name
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBFooter($db)
+ {
+ return true;
+ }
+
+ /**
+ * Outputs CREATE DATABASE statement
+ *
+ * @param string $db Database name
+ * @param string $export_type 'server', 'database', 'table'
+ * @param string $db_alias Aliases of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBCreate($db, $export_type, $db_alias = '')
+ {
+ 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 $error_url the url to go back in case of error
+ * @param string $sql_query SQL query for obtaining data
+ * @param array $aliases Aliases of db/table/columns
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportData(
+ $db,
+ $table,
+ $crlf,
+ $error_url,
+ $sql_query,
+ array $aliases = []
+ ) {
+ global $what;
+
+ $db_alias = $db;
+ $table_alias = $table;
+ $this->initAlias($aliases, $db_alias, $table_alias);
+ // Gets the data from the database
+ $result = $GLOBALS['dbi']->query(
+ $sql_query,
+ DatabaseInterface::CONNECT_USER,
+ DatabaseInterface::QUERY_UNBUFFERED
+ );
+ $fields_cnt = $GLOBALS['dbi']->numFields($result);
+ $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result);
+ $field_flags = [];
+ for ($j = 0; $j < $fields_cnt; $j++) {
+ $field_flags[$j] = $GLOBALS['dbi']->fieldFlags($result, $j);
+ }
+
+ $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>';
+ for ($i = 0; $i < $fields_cnt; $i++) {
+ $col_as = $GLOBALS['dbi']->fieldName($result, $i);
+ 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>';
+ } // end for
+ $GLOBALS['ods_buffer'] .= '</table:table-row>';
+ } // end if
+
+ // Format the data
+ while ($row = $GLOBALS['dbi']->fetchRow($result)) {
+ $GLOBALS['ods_buffer'] .= '<table:table-row>';
+ for ($j = 0; $j < $fields_cnt; $j++) {
+ if ($fields_meta[$j]->type === 'geometry') {
+ // export GIS types as hex
+ $row[$j] = '0x' . bin2hex($row[$j]);
+ }
+ if (! isset($row[$j]) || $row[$j] === null) {
+ $GLOBALS['ods_buffer']
+ .= '<table:table-cell office:value-type="string">'
+ . '<text:p>'
+ . htmlspecialchars($GLOBALS[$what . '_null'])
+ . '</text:p>'
+ . '</table:table-cell>';
+ } elseif (false !== stripos($field_flags[$j], 'BINARY')
+ && $fields_meta[$j]->blob
+ ) {
+ // ignore BLOB
+ $GLOBALS['ods_buffer']
+ .= '<table:table-cell office:value-type="string">'
+ . '<text:p></text:p>'
+ . '</table:table-cell>';
+ } elseif ($fields_meta[$j]->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 ($fields_meta[$j]->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 ($fields_meta[$j]->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 (($fields_meta[$j]->numeric
+ && $fields_meta[$j]->type != 'timestamp'
+ && ! $fields_meta[$j]->blob)
+ || $fields_meta[$j]->type == 'real'
+ ) {
+ $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>';
+ }
+ } // end for
+ $GLOBALS['ods_buffer'] .= '</table:table-row>';
+ } // end while
+ $GLOBALS['dbi']->freeResult($result);
+
+ $GLOBALS['ods_buffer'] .= '</table:table>';
+
+ return true;
+ }
+}
diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportOdt.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportOdt.php
new file mode 100644
index 0000000..8173afb
--- /dev/null
+++ b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportOdt.php
@@ -0,0 +1,813 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * Set of functions used to build OpenDocument Text dumps of tables
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage ODT
+ */
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Plugins\Export;
+
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\Export;
+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\Transformations;
+use PhpMyAdmin\Util;
+
+/**
+ * Handles the export for the ODT class
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage ODT
+ */
+class ExportOdt extends ExportPlugin
+{
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $GLOBALS['odt_buffer'] = '';
+ $this->setProperties();
+ }
+
+ /**
+ * Sets the export ODT properties
+ *
+ * @return void
+ */
+ protected function setProperties()
+ {
+ 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');
+ // create primary items and add them to the group
+ if (! empty($GLOBALS['cfgRelation']['relation'])) {
+ $leaf = new BoolPropertyItem(
+ "relation",
+ __('Display foreign key relationships')
+ );
+ $structureOptions->addProperty($leaf);
+ }
+ $leaf = new BoolPropertyItem(
+ "comments",
+ __('Display comments')
+ );
+ $structureOptions->addProperty($leaf);
+ if (! empty($GLOBALS['cfgRelation']['mimework'])) {
+ $leaf = new BoolPropertyItem(
+ "mime",
+ __('Display media (MIME) 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);
+ $this->properties = $exportPluginProperties;
+ }
+
+ /**
+ * Outputs export header
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportHeader()
+ {
+ $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
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportFooter()
+ {
+ $GLOBALS['odt_buffer'] .= '</office:text>'
+ . '</office:body>'
+ . '</office:document-content>';
+ if (! $this->export->outputHandler(
+ OpenDocument::create(
+ 'application/vnd.oasis.opendocument.text',
+ $GLOBALS['odt_buffer']
+ )
+ )
+ ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Outputs database header
+ *
+ * @param string $db Database name
+ * @param string $db_alias Aliases of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBHeader($db, $db_alias = '')
+ {
+ if (empty($db_alias)) {
+ $db_alias = $db;
+ }
+ $GLOBALS['odt_buffer']
+ .= '<text:h text:outline-level="1" text:style-name="Heading_1"'
+ . ' text:is-list-header="true">'
+ . __('Database') . ' ' . htmlspecialchars($db_alias)
+ . '</text:h>';
+
+ return true;
+ }
+
+ /**
+ * Outputs database footer
+ *
+ * @param string $db Database name
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBFooter($db)
+ {
+ return true;
+ }
+
+ /**
+ * Outputs CREATE DATABASE statement
+ *
+ * @param string $db Database name
+ * @param string $export_type 'server', 'database', 'table'
+ * @param string $db_alias Aliases of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBCreate($db, $export_type, $db_alias = '')
+ {
+ 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 $error_url the url to go back in case of error
+ * @param string $sql_query SQL query for obtaining data
+ * @param array $aliases Aliases of db/table/columns
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportData(
+ $db,
+ $table,
+ $crlf,
+ $error_url,
+ $sql_query,
+ array $aliases = []
+ ) {
+ global $what;
+
+ $db_alias = $db;
+ $table_alias = $table;
+ $this->initAlias($aliases, $db_alias, $table_alias);
+ // Gets the data from the database
+ $result = $GLOBALS['dbi']->query(
+ $sql_query,
+ DatabaseInterface::CONNECT_USER,
+ DatabaseInterface::QUERY_UNBUFFERED
+ );
+ $fields_cnt = $GLOBALS['dbi']->numFields($result);
+ $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result);
+ $field_flags = [];
+ for ($j = 0; $j < $fields_cnt; $j++) {
+ $field_flags[$j] = $GLOBALS['dbi']->fieldFlags($result, $j);
+ }
+
+ $GLOBALS['odt_buffer']
+ .= '<text:h text:outline-level="2" text:style-name="Heading_2"'
+ . ' text:is-list-header="true">'
+ . __('Dumping data for table') . ' ' . htmlspecialchars($table_alias)
+ . '</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>';
+ for ($i = 0; $i < $fields_cnt; $i++) {
+ $col_as = $GLOBALS['dbi']->fieldName($result, $i);
+ 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>';
+ } // end for
+ $GLOBALS['odt_buffer'] .= '</table:table-row>';
+ } // end if
+
+ // Format the data
+ while ($row = $GLOBALS['dbi']->fetchRow($result)) {
+ $GLOBALS['odt_buffer'] .= '<table:table-row>';
+ for ($j = 0; $j < $fields_cnt; $j++) {
+ if ($fields_meta[$j]->type === 'geometry') {
+ // export GIS types as hex
+ $row[$j] = '0x' . bin2hex($row[$j]);
+ }
+ if (! isset($row[$j]) || $row[$j] === null) {
+ $GLOBALS['odt_buffer']
+ .= '<table:table-cell office:value-type="string">'
+ . '<text:p>'
+ . htmlspecialchars($GLOBALS[$what . '_null'])
+ . '</text:p>'
+ . '</table:table-cell>';
+ } elseif (false !== stripos($field_flags[$j], 'BINARY')
+ && $fields_meta[$j]->blob
+ ) {
+ // ignore BLOB
+ $GLOBALS['odt_buffer']
+ .= '<table:table-cell office:value-type="string">'
+ . '<text:p></text:p>'
+ . '</table:table-cell>';
+ } elseif ($fields_meta[$j]->numeric
+ && $fields_meta[$j]->type != 'timestamp'
+ && ! $fields_meta[$j]->blob
+ ) {
+ $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>';
+ }
+ } // end for
+ $GLOBALS['odt_buffer'] .= '</table:table-row>';
+ } // end while
+ $GLOBALS['dbi']->freeResult($result);
+
+ $GLOBALS['odt_buffer'] .= '</table:table>';
+
+ return true;
+ }
+
+ /**
+ * 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 = [])
+ {
+ $db_alias = $db;
+ $view_alias = $view;
+ $this->initAlias($aliases, $db_alias, $view_alias);
+ /**
+ * Gets fields properties
+ */
+ $GLOBALS['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 = $GLOBALS['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>';
+ } // end foreach
+
+ $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.php 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
+ *
+ * @return bool true
+ */
+ 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 $cfgRelation;
+
+ $db_alias = $db;
+ $table_alias = $table;
+ $this->initAlias($aliases, $db_alias, $table_alias);
+ /**
+ * Gets fields properties
+ */
+ $GLOBALS['dbi']->selectDb($db);
+
+ // Check if we can use Relations
+ list($res_rel, $have_rel) = $this->relation->getRelationsAndStatus(
+ $do_relation && ! empty($cfgRelation['relation']),
+ $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 && $cfgRelation['mimework']) {
+ $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 && $cfgRelation['mimework']) {
+ $GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">'
+ . '<text:p>' . __('Media (MIME) type') . '</text:p>'
+ . '</table:table-cell>';
+ $mime_map = $this->transformations->getMime($db, $table, true);
+ }
+ $GLOBALS['odt_buffer'] .= '</table:table-row>';
+
+ $columns = $GLOBALS['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 && $cfgRelation['mimework']) {
+ 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>';
+ } // end foreach
+
+ $GLOBALS['odt_buffer'] .= '</table:table>';
+
+ return true;
+ } // end of the '$this->getTableDef()' function
+
+ /**
+ * Outputs triggers
+ *
+ * @param string $db database name
+ * @param string $table table name
+ * @param array $aliases Aliases of db/table/columns
+ *
+ * @return bool true
+ */
+ protected function getTriggers($db, $table, array $aliases = [])
+ {
+ $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 = $GLOBALS['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 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 $error_url the url to go back in case of error
+ * @param string $export_mode 'create_table', 'triggers', 'create_view',
+ * 'stand_in'
+ * @param string $export_type '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.php 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
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportStructure(
+ $db,
+ $table,
+ $crlf,
+ $error_url,
+ $export_mode,
+ $export_type,
+ $do_relation = false,
+ $do_comments = false,
+ $do_mime = false,
+ $dates = false,
+ array $aliases = []
+ ) {
+ $db_alias = $db;
+ $table_alias = $table;
+ $this->initAlias($aliases, $db_alias, $table_alias);
+ switch ($export_mode) {
+ 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,
+ $error_url,
+ $do_relation,
+ $do_comments,
+ $do_mime,
+ $dates,
+ true,
+ false,
+ $aliases
+ );
+ break;
+ case 'triggers':
+ $triggers = $GLOBALS['dbi']->getTriggers($db, $table, $aliases);
+ 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,
+ $error_url,
+ $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);
+ } // end switch
+
+ return true;
+ } // end of the '$this->exportStructure' function
+
+ /**
+ * 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 = '&nbsp;';
+ }
+
+ $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;
+ }
+}
diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportPdf.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportPdf.php
new file mode 100644
index 0000000..49e74b3
--- /dev/null
+++ b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportPdf.php
@@ -0,0 +1,395 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * Produce a PDF report (export) from a query
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage PDF
+ */
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Plugins\Export;
+
+use PhpMyAdmin\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;
+
+/**
+ * Skip the plugin if TCPDF is not available.
+ */
+if (! class_exists('TCPDF')) {
+ $GLOBALS['skip_import'] = true;
+ return;
+}
+
+/**
+ * Handles the export for the PDF class
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage PDF
+ */
+class ExportPdf extends ExportPlugin
+{
+ /**
+ * PhpMyAdmin\Plugins\Export\Helpers\Pdf instance
+ *
+ * @var Pdf
+ */
+ private $_pdf;
+
+ /**
+ * PDF Report Title
+ *
+ * @var string
+ */
+ private $_pdfReportTitle;
+
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ parent::__construct();
+
+ // initialize the specific export PDF variables
+ $this->initSpecificVariables();
+
+ $this->setProperties();
+ }
+
+ /**
+ * Initialize the local variables that are used for export PDF
+ *
+ * @return void
+ */
+ protected function initSpecificVariables()
+ {
+ if (! empty($_POST['pdf_report_title'])) {
+ $this->_setPdfReportTitle($_POST['pdf_report_title']);
+ }
+ $this->_setPdf(new Pdf('L', 'pt', 'A3'));
+ }
+
+ /**
+ * Sets the export PDF properties
+ *
+ * @return void
+ */
+ protected function setProperties()
+ {
+ $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);
+ $this->properties = $exportPluginProperties;
+ }
+
+ /**
+ * Outputs export header
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportHeader()
+ {
+ $pdf_report_title = $this->_getPdfReportTitle();
+ $pdf = $this->_getPdf();
+ $pdf->Open();
+
+ $attr = [
+ 'titleFontSize' => 18,
+ 'titleText' => $pdf_report_title,
+ ];
+ $pdf->setAttributes($attr);
+ $pdf->setTopMargin(30);
+
+ return true;
+ }
+
+ /**
+ * Outputs export footer
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportFooter()
+ {
+ $pdf = $this->_getPdf();
+
+ // instead of $pdf->Output():
+ return $this->export->outputHandler($pdf->getPDFData());
+ }
+
+ /**
+ * Outputs database header
+ *
+ * @param string $db Database name
+ * @param string $db_alias Aliases of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBHeader($db, $db_alias = '')
+ {
+ return true;
+ }
+
+ /**
+ * Outputs database footer
+ *
+ * @param string $db Database name
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBFooter($db)
+ {
+ return true;
+ }
+
+ /**
+ * Outputs CREATE DATABASE statement
+ *
+ * @param string $db Database name
+ * @param string $export_type 'server', 'database', 'table'
+ * @param string $db_alias Aliases of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBCreate($db, $export_type, $db_alias = '')
+ {
+ 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 $error_url the url to go back in case of error
+ * @param string $sql_query SQL query for obtaining data
+ * @param array $aliases Aliases of db/table/columns
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportData(
+ $db,
+ $table,
+ $crlf,
+ $error_url,
+ $sql_query,
+ array $aliases = []
+ ) {
+ $db_alias = $db;
+ $table_alias = $table;
+ $this->initAlias($aliases, $db_alias, $table_alias);
+ $pdf = $this->_getPdf();
+ $attr = [
+ 'currentDb' => $db,
+ 'currentTable' => $table,
+ 'dbAlias' => $db_alias,
+ 'tableAlias' => $table_alias,
+ 'aliases' => $aliases,
+ 'purpose' => __('Dumping data'),
+ ];
+ $pdf->setAttributes($attr);
+ $pdf->mysqlReport($sql_query);
+
+ return true;
+ } // end of the 'PMA_exportData()' function
+
+ /**
+ * Outputs table structure
+ *
+ * @param string $db database name
+ * @param string $table table name
+ * @param string $crlf the end of line sequence
+ * @param string $error_url the url to go back in case of error
+ * @param string $export_mode 'create_table', 'triggers', 'create_view',
+ * 'stand_in'
+ * @param string $export_type '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.php 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
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportStructure(
+ $db,
+ $table,
+ $crlf,
+ $error_url,
+ $export_mode,
+ $export_type,
+ $do_relation = false,
+ $do_comments = false,
+ $do_mime = false,
+ $dates = false,
+ array $aliases = []
+ ) {
+ $db_alias = $db;
+ $table_alias = $table;
+ $purpose = null;
+ $this->initAlias($aliases, $db_alias, $table_alias);
+ $pdf = $this->_getPdf();
+ // getting purpose to show at top
+ switch ($export_mode) {
+ 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');
+ } // end switch
+
+ $attr = [
+ 'currentDb' => $db,
+ 'currentTable' => $table,
+ 'dbAlias' => $db_alias,
+ 'tableAlias' => $table_alias,
+ 'aliases' => $aliases,
+ 'purpose' => $purpose,
+ ];
+ $pdf->setAttributes($attr);
+ /**
+ * comment display set true as presently in pdf
+ * format, no option is present to take user input.
+ */
+ $do_comments = true;
+ switch ($export_mode) {
+ 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);
+ */
+ } // end switch
+
+ 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
+ *
+ * @return void
+ */
+ private function _setPdf($pdf)
+ {
+ $this->_pdf = $pdf;
+ }
+
+ /**
+ * Gets the PDF report title
+ *
+ * @return string
+ */
+ private function _getPdfReportTitle()
+ {
+ return $this->_pdfReportTitle;
+ }
+
+ /**
+ * Sets the PDF report title
+ *
+ * @param string $pdfReportTitle PDF report title
+ *
+ * @return void
+ */
+ private function _setPdfReportTitle($pdfReportTitle)
+ {
+ $this->_pdfReportTitle = $pdfReportTitle;
+ }
+}
diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportPhparray.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportPhparray.php
new file mode 100644
index 0000000..3fe9bd1
--- /dev/null
+++ b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportPhparray.php
@@ -0,0 +1,259 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * Set of functions used to build dumps of tables as PHP Arrays
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage PHP
+ */
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Plugins\Export;
+
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\Export;
+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;
+
+/**
+ * Handles the export for the PHP Array class
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage PHP
+ */
+class ExportPhparray extends ExportPlugin
+{
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setProperties();
+ }
+
+ /**
+ * Sets the export PHP Array properties
+ *
+ * @return void
+ */
+ protected function setProperties()
+ {
+ $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);
+ $this->properties = $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
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportHeader()
+ {
+ $this->export->outputHandler(
+ '<?php' . $GLOBALS['crlf']
+ . '/**' . $GLOBALS['crlf']
+ . ' * Export to PHP Array plugin for PHPMyAdmin' . $GLOBALS['crlf']
+ . ' * @version ' . PMA_VERSION . $GLOBALS['crlf']
+ . ' */' . $GLOBALS['crlf'] . $GLOBALS['crlf']
+ );
+
+ return true;
+ }
+
+ /**
+ * Outputs export footer
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportFooter()
+ {
+ return true;
+ }
+
+ /**
+ * Outputs database header
+ *
+ * @param string $db Database name
+ * @param string $db_alias Aliases of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBHeader($db, $db_alias = '')
+ {
+ if (empty($db_alias)) {
+ $db_alias = $db;
+ }
+ $this->export->outputHandler(
+ '/**' . $GLOBALS['crlf']
+ . ' * Database ' . $this->commentString(Util::backquote($db_alias))
+ . $GLOBALS['crlf'] . ' */' . $GLOBALS['crlf']
+ );
+
+ return true;
+ }
+
+ /**
+ * Outputs database footer
+ *
+ * @param string $db Database name
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBFooter($db)
+ {
+ return true;
+ }
+
+ /**
+ * Outputs CREATE DATABASE statement
+ *
+ * @param string $db Database name
+ * @param string $export_type 'server', 'database', 'table'
+ * @param string $db_alias Aliases of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBCreate($db, $export_type, $db_alias = '')
+ {
+ 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 $error_url the url to go back in case of error
+ * @param string $sql_query SQL query for obtaining data
+ * @param array $aliases Aliases of db/table/columns
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportData(
+ $db,
+ $table,
+ $crlf,
+ $error_url,
+ $sql_query,
+ array $aliases = []
+ ) {
+ $db_alias = $db;
+ $table_alias = $table;
+ $this->initAlias($aliases, $db_alias, $table_alias);
+
+ $result = $GLOBALS['dbi']->query(
+ $sql_query,
+ DatabaseInterface::CONNECT_USER,
+ DatabaseInterface::QUERY_UNBUFFERED
+ );
+
+ $columns_cnt = $GLOBALS['dbi']->numFields($result);
+ $columns = [];
+ for ($i = 0; $i < $columns_cnt; $i++) {
+ $col_as = $GLOBALS['dbi']->fieldName($result, $i);
+ if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) {
+ $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as];
+ }
+ $columns[$i] = stripslashes($col_as);
+ }
+
+ // 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;
+ }
+ } else {
+ $tablefixed = $table;
+ }
+
+ $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(';
+
+ while ($record = $GLOBALS['dbi']->fetchRow($result)) {
+ $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 .= ')';
+ }
+
+ $buffer .= $crlf . ');' . $crlf;
+ if (! $this->export->outputHandler($buffer)) {
+ return false;
+ }
+
+ $GLOBALS['dbi']->freeResult($result);
+
+ return true;
+ }
+}
diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportSql.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportSql.php
new file mode 100644
index 0000000..9c5b1a2
--- /dev/null
+++ b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportSql.php
@@ -0,0 +1,2915 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * Set of functions used to build SQL dumps of tables
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage SQL
+ */
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Plugins\Export;
+
+use PhpMyAdmin\Charsets;
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\Export;
+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\MessageOnlyPropertyItem;
+use PhpMyAdmin\Properties\Options\Items\NumberPropertyItem;
+use PhpMyAdmin\Properties\Options\Items\RadioPropertyItem;
+use PhpMyAdmin\Properties\Options\Items\SelectPropertyItem;
+use PhpMyAdmin\Properties\Options\Items\TextPropertyItem;
+use PhpMyAdmin\Properties\Plugins\ExportPluginProperties;
+use PhpMyAdmin\SqlParser\Components\CreateDefinition;
+use PhpMyAdmin\SqlParser\Context;
+use PhpMyAdmin\SqlParser\Parser;
+use PhpMyAdmin\SqlParser\Statements\CreateStatement;
+use PhpMyAdmin\SqlParser\Token;
+use PhpMyAdmin\Util;
+
+/**
+ * Handles the export for the SQL class
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage SQL
+ */
+class ExportSql extends ExportPlugin
+{
+ /**
+ * Whether charset header was sent.
+ *
+ * @var boolean
+ */
+ private $_sent_charset = false;
+
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setProperties();
+
+ // Avoids undefined variables, use NULL so isset() returns false
+ if (! isset($GLOBALS['sql_backquotes'])) {
+ $GLOBALS['sql_backquotes'] = null;
+ }
+ }
+
+ /**
+ * Sets the export SQL properties
+ *
+ * @return void
+ */
+ protected function setProperties()
+ {
+ global $plugin_param;
+
+ $hide_sql = false;
+ $hide_structure = false;
+ if ($plugin_param['export_type'] == 'table'
+ && ! $plugin_param['single_table']
+ ) {
+ $hide_structure = true;
+ $hide_sql = true;
+ }
+
+ if (! $hide_sql) {
+ $exportPluginProperties = new ExportPluginProperties();
+ $exportPluginProperties->setText('SQL');
+ $exportPluginProperties->setExtension('sql');
+ $exportPluginProperties->setMimeType('text/x-sql');
+ $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");
+
+ // comments
+ $subgroup = new OptionsPropertySubgroup("include_comments");
+ $leaf = new BoolPropertyItem(
+ 'include_comments',
+ __(
+ 'Display comments <i>(includes info such as export'
+ . ' timestamp, PHP version, and server version)</i>'
+ )
+ );
+ $subgroup->setSubgroupHeader($leaf);
+
+ $leaf = new TextPropertyItem(
+ 'header_comment',
+ __('Additional custom header comment (\n splits lines):')
+ );
+ $subgroup->addProperty($leaf);
+ $leaf = new BoolPropertyItem(
+ 'dates',
+ __(
+ 'Include a timestamp of when databases were created, last'
+ . ' updated, and last checked'
+ )
+ );
+ $subgroup->addProperty($leaf);
+ if (! empty($GLOBALS['cfgRelation']['relation'])) {
+ $leaf = new BoolPropertyItem(
+ 'relation',
+ __('Display foreign key relationships')
+ );
+ $subgroup->addProperty($leaf);
+ }
+ if (! empty($GLOBALS['cfgRelation']['mimework'])) {
+ $leaf = new BoolPropertyItem(
+ 'mime',
+ __('Display media (MIME) types')
+ );
+ $subgroup->addProperty($leaf);
+ }
+ $generalOptions->addProperty($subgroup);
+
+ // enclose in a transaction
+ $leaf = new BoolPropertyItem(
+ "use_transaction",
+ __('Enclose export in a transaction')
+ );
+ $leaf->setDoc(
+ [
+ 'programs',
+ 'mysqldump',
+ 'option_mysqldump_single-transaction',
+ ]
+ );
+ $generalOptions->addProperty($leaf);
+
+ // disable foreign key checks
+ $leaf = new BoolPropertyItem(
+ "disable_fk",
+ __('Disable foreign key checks')
+ );
+ $leaf->setDoc(
+ [
+ 'manual_MySQL_Database_Administration',
+ 'server-system-variables',
+ 'sysvar_foreign_key_checks',
+ ]
+ );
+ $generalOptions->addProperty($leaf);
+
+ // export views as tables
+ $leaf = new BoolPropertyItem(
+ "views_as_tables",
+ __('Export views as tables')
+ );
+ $generalOptions->addProperty($leaf);
+
+ // export metadata
+ $leaf = new BoolPropertyItem(
+ "metadata",
+ __('Export metadata')
+ );
+ $generalOptions->addProperty($leaf);
+
+ // compatibility maximization
+ $compats = $GLOBALS['dbi']->getCompatibilities();
+ if (count($compats) > 0) {
+ $values = [];
+ foreach ($compats as $val) {
+ $values[$val] = $val;
+ }
+
+ $leaf = new SelectPropertyItem(
+ "compatibility",
+ __(
+ 'Database system or older MySQL server to maximize output'
+ . ' compatibility with:'
+ )
+ );
+ $leaf->setValues($values);
+ $leaf->setDoc(
+ [
+ 'manual_MySQL_Database_Administration',
+ 'Server_SQL_mode',
+ ]
+ );
+ $generalOptions->addProperty($leaf);
+
+ unset($values);
+ }
+
+ // 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);
+
+ // add the main group to the root group
+ $exportSpecificOptions->addProperty($generalOptions);
+
+ // structure options main group
+ if (! $hide_structure) {
+ $structureOptions = new OptionsPropertyMainGroup(
+ "structure",
+ __('Object creation options')
+ );
+ $structureOptions->setForce('data');
+
+ // begin SQL Statements
+ $subgroup = new OptionsPropertySubgroup();
+ $leaf = new MessageOnlyPropertyItem(
+ 'add_statements',
+ __('Add statements:')
+ );
+ $subgroup->setSubgroupHeader($leaf);
+
+ // server export options
+ if ($plugin_param['export_type'] == 'server') {
+ $leaf = new BoolPropertyItem(
+ "drop_database",
+ sprintf(__('Add %s statement'), '<code>DROP DATABASE IF EXISTS</code>')
+ );
+ $subgroup->addProperty($leaf);
+ }
+
+ if ($plugin_param['export_type'] == 'database') {
+ $create_clause = '<code>CREATE DATABASE / USE</code>';
+ $leaf = new BoolPropertyItem(
+ 'create_database',
+ sprintf(__('Add %s statement'), $create_clause)
+ );
+ $subgroup->addProperty($leaf);
+ }
+
+ if ($plugin_param['export_type'] == 'table') {
+ $drop_clause = $GLOBALS['dbi']->getTable(
+ $GLOBALS['db'],
+ $GLOBALS['table']
+ )->isView()
+ ? '<code>DROP VIEW</code>'
+ : '<code>DROP TABLE</code>';
+ } else {
+ $drop_clause = '<code>DROP TABLE / VIEW / PROCEDURE'
+ . ' / FUNCTION / EVENT</code>';
+ }
+
+ $drop_clause .= '<code> / TRIGGER</code>';
+
+ $leaf = new BoolPropertyItem(
+ 'drop_table',
+ sprintf(__('Add %s statement'), $drop_clause)
+ );
+ $subgroup->addProperty($leaf);
+
+ $subgroup_create_table = new OptionsPropertySubgroup();
+
+ // Add table structure option
+ $leaf = new BoolPropertyItem(
+ 'create_table',
+ sprintf(__('Add %s statement'), '<code>CREATE TABLE</code>')
+ );
+ $subgroup_create_table->setSubgroupHeader($leaf);
+
+ $leaf = new BoolPropertyItem(
+ 'if_not_exists',
+ '<code>IF NOT EXISTS</code> ' . __(
+ '(less efficient as indexes will be generated during table '
+ . 'creation)'
+ )
+ );
+ $subgroup_create_table->addProperty($leaf);
+
+ $leaf = new BoolPropertyItem(
+ 'auto_increment',
+ sprintf(__('%s value'), '<code>AUTO_INCREMENT</code>')
+ );
+ $subgroup_create_table->addProperty($leaf);
+
+ $subgroup->addProperty($subgroup_create_table);
+
+ // Add view option
+ $subgroup_create_view = new OptionsPropertySubgroup();
+ $leaf = new BoolPropertyItem(
+ 'create_view',
+ sprintf(__('Add %s statement'), '<code>CREATE VIEW</code>')
+ );
+ $subgroup_create_view->setSubgroupHeader($leaf);
+
+ $leaf = new BoolPropertyItem(
+ 'view_current_user',
+ __('Exclude definition of current user')
+ );
+ $subgroup_create_view->addProperty($leaf);
+
+ $leaf = new BoolPropertyItem(
+ 'or_replace_view',
+ sprintf(__('%s view'), '<code>OR REPLACE</code>')
+ );
+ $subgroup_create_view->addProperty($leaf);
+
+ $subgroup->addProperty($subgroup_create_view);
+
+ $leaf = new BoolPropertyItem(
+ 'procedure_function',
+ sprintf(
+ __('Add %s statement'),
+ '<code>CREATE PROCEDURE / FUNCTION / EVENT</code>'
+ )
+ );
+ $subgroup->addProperty($leaf);
+
+ // Add triggers option
+ $leaf = new BoolPropertyItem(
+ 'create_trigger',
+ sprintf(__('Add %s statement'), '<code>CREATE TRIGGER</code>')
+ );
+ $subgroup->addProperty($leaf);
+
+ $structureOptions->addProperty($subgroup);
+
+ $leaf = new BoolPropertyItem(
+ "backquotes",
+ __(
+ 'Enclose table and column names with backquotes '
+ . '<i>(Protects column and table names formed with'
+ . ' special characters or keywords)</i>'
+ )
+ );
+
+ $structureOptions->addProperty($leaf);
+
+ // add the main group to the root group
+ $exportSpecificOptions->addProperty($structureOptions);
+ }
+
+ // begin Data options
+ $dataOptions = new OptionsPropertyMainGroup(
+ "data",
+ __('Data creation options')
+ );
+ $dataOptions->setForce('structure');
+ $leaf = new BoolPropertyItem(
+ "truncate",
+ __('Truncate table before insert')
+ );
+ $dataOptions->addProperty($leaf);
+
+ // begin SQL Statements
+ $subgroup = new OptionsPropertySubgroup();
+ $leaf = new MessageOnlyPropertyItem(
+ __('Instead of <code>INSERT</code> statements, use:')
+ );
+ $subgroup->setSubgroupHeader($leaf);
+
+ $leaf = new BoolPropertyItem(
+ "delayed",
+ __('<code>INSERT DELAYED</code> statements')
+ );
+ $leaf->setDoc(
+ [
+ 'manual_MySQL_Database_Administration',
+ 'insert_delayed',
+ ]
+ );
+ $subgroup->addProperty($leaf);
+
+ $leaf = new BoolPropertyItem(
+ "ignore",
+ __('<code>INSERT IGNORE</code> statements')
+ );
+ $leaf->setDoc(
+ [
+ 'manual_MySQL_Database_Administration',
+ 'insert',
+ ]
+ );
+ $subgroup->addProperty($leaf);
+ $dataOptions->addProperty($subgroup);
+
+ // Function to use when dumping dat
+ $leaf = new SelectPropertyItem(
+ "type",
+ __('Function to use when dumping data:')
+ );
+ $leaf->setValues(
+ [
+ 'INSERT' => 'INSERT',
+ 'UPDATE' => 'UPDATE',
+ 'REPLACE' => 'REPLACE',
+ ]
+ );
+ $dataOptions->addProperty($leaf);
+
+ /* Syntax to use when inserting data */
+ $subgroup = new OptionsPropertySubgroup();
+ $leaf = new MessageOnlyPropertyItem(
+ null,
+ __('Syntax to use when inserting data:')
+ );
+ $subgroup->setSubgroupHeader($leaf);
+ $leaf = new RadioPropertyItem(
+ "insert_syntax",
+ __('<code>INSERT IGNORE</code> statements')
+ );
+ $leaf->setValues(
+ [
+ 'complete' => __(
+ 'include column names in every <code>INSERT</code> statement'
+ . ' <br> &nbsp; &nbsp; &nbsp; Example: <code>INSERT INTO'
+ . ' tbl_name (col_A,col_B,col_C) VALUES (1,2,3)</code>'
+ ),
+ 'extended' => __(
+ 'insert multiple rows in every <code>INSERT</code> statement'
+ . '<br> &nbsp; &nbsp; &nbsp; Example: <code>INSERT INTO'
+ . ' tbl_name VALUES (1,2,3), (4,5,6), (7,8,9)</code>'
+ ),
+ 'both' => __(
+ 'both of the above<br> &nbsp; &nbsp; &nbsp; Example:'
+ . ' <code>INSERT INTO tbl_name (col_A,col_B,col_C) VALUES'
+ . ' (1,2,3), (4,5,6), (7,8,9)</code>'
+ ),
+ 'none' => __(
+ 'neither of the above<br> &nbsp; &nbsp; &nbsp; Example:'
+ . ' <code>INSERT INTO tbl_name VALUES (1,2,3)</code>'
+ ),
+ ]
+ );
+ $subgroup->addProperty($leaf);
+ $dataOptions->addProperty($subgroup);
+
+ // Max length of query
+ $leaf = new NumberPropertyItem(
+ "max_query_size",
+ __('Maximal length of created query')
+ );
+ $dataOptions->addProperty($leaf);
+
+ // Dump binary columns in hexadecimal
+ $leaf = new BoolPropertyItem(
+ "hex_for_binary",
+ __(
+ 'Dump binary columns in hexadecimal notation'
+ . ' <i>(for example, "abc" becomes 0x616263)</i>'
+ )
+ );
+ $dataOptions->addProperty($leaf);
+
+ // Dump time in UTC
+ $leaf = new BoolPropertyItem(
+ "utc_time",
+ __(
+ 'Dump TIMESTAMP columns in UTC <i>(enables TIMESTAMP columns'
+ . ' to be dumped and reloaded between servers in different'
+ . ' time zones)</i>'
+ )
+ );
+ $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);
+ $this->properties = $exportPluginProperties;
+ }
+ }
+
+ /**
+ * Generates SQL for routines export
+ *
+ * @param string $db Database
+ * @param array $aliases Aliases of db/table/columns
+ * @param string $type Type of exported routine
+ * @param string $name Verbose name of exported routine
+ * @param array $routines List of routines to export
+ * @param string $delimiter Delimiter to use in SQL
+ *
+ * @return string SQL query
+ */
+ protected function _exportRoutineSQL(
+ $db,
+ array $aliases,
+ $type,
+ $name,
+ array $routines,
+ $delimiter
+ ) {
+ global $crlf;
+
+ $text = $this->_exportComment()
+ . $this->_exportComment($name)
+ . $this->_exportComment();
+
+ $used_alias = false;
+ $proc_query = '';
+
+ foreach ($routines as $routine) {
+ if (! empty($GLOBALS['sql_drop_table'])) {
+ $proc_query .= 'DROP ' . $type . ' IF EXISTS '
+ . Util::backquote($routine)
+ . $delimiter . $crlf;
+ }
+ $create_query = $this->replaceWithAliases(
+ $GLOBALS['dbi']->getDefinition($db, $type, $routine),
+ $aliases,
+ $db,
+ '',
+ $flag
+ );
+ // One warning per database
+ if ($flag) {
+ $used_alias = true;
+ }
+ $proc_query .= $create_query . $delimiter . $crlf . $crlf;
+ }
+ if ($used_alias) {
+ $text .= $this->_exportComment(
+ __('It appears your database uses routines;')
+ )
+ . $this->_exportComment(
+ __('alias export may not work reliably in all cases.')
+ )
+ . $this->_exportComment();
+ }
+ $text .= $proc_query;
+
+ return $text;
+ }
+
+ /**
+ * Exports routines (procedures and functions)
+ *
+ * @param string $db Database
+ * @param array $aliases Aliases of db/table/columns
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportRoutines($db, array $aliases = [])
+ {
+ global $crlf;
+
+ $db_alias = $db;
+ $this->initAlias($aliases, $db_alias);
+
+ $text = '';
+ $delimiter = '$$';
+
+ $procedure_names = $GLOBALS['dbi']
+ ->getProceduresOrFunctions($db, 'PROCEDURE');
+ $function_names = $GLOBALS['dbi']->getProceduresOrFunctions($db, 'FUNCTION');
+
+ if ($procedure_names || $function_names) {
+ $text .= $crlf
+ . 'DELIMITER ' . $delimiter . $crlf;
+
+ if ($procedure_names) {
+ $text .= $this->_exportRoutineSQL(
+ $db,
+ $aliases,
+ 'PROCEDURE',
+ __('Procedures'),
+ $procedure_names,
+ $delimiter
+ );
+ }
+
+ if ($function_names) {
+ $text .= $this->_exportRoutineSQL(
+ $db,
+ $aliases,
+ 'FUNCTION',
+ __('Functions'),
+ $function_names,
+ $delimiter
+ );
+ }
+
+ $text .= 'DELIMITER ;' . $crlf;
+ }
+
+ if (! empty($text)) {
+ return $this->export->outputHandler($text);
+ }
+
+ return false;
+ }
+
+ /**
+ * Possibly outputs comment
+ *
+ * @param string $text Text of comment
+ *
+ * @return string The formatted comment
+ */
+ private function _exportComment($text = '')
+ {
+ if (isset($GLOBALS['sql_include_comments'])
+ && $GLOBALS['sql_include_comments']
+ ) {
+ // see https://dev.mysql.com/doc/refman/5.0/en/ansi-diff-comments.html
+ if (empty($text)) {
+ return '--' . $GLOBALS['crlf'];
+ }
+
+ $lines = preg_split("/\\r\\n|\\r|\\n/", $text);
+ $result = [];
+ foreach ($lines as $line) {
+ $result[] = '-- ' . $line . $GLOBALS['crlf'];
+ }
+ return implode('', $result);
+ }
+
+ return '';
+ }
+
+ /**
+ * Possibly outputs CRLF
+ *
+ * @return string crlf or nothing
+ */
+ private function _possibleCRLF()
+ {
+ if (isset($GLOBALS['sql_include_comments'])
+ && $GLOBALS['sql_include_comments']
+ ) {
+ return $GLOBALS['crlf'];
+ }
+
+ return '';
+ }
+
+ /**
+ * Outputs export footer
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportFooter()
+ {
+ global $crlf;
+
+ $foot = '';
+
+ if (isset($GLOBALS['sql_disable_fk'])) {
+ $foot .= 'SET FOREIGN_KEY_CHECKS=1;' . $crlf;
+ }
+
+ if (isset($GLOBALS['sql_use_transaction'])) {
+ $foot .= 'COMMIT;' . $crlf;
+ }
+
+ // restore connection settings
+ if ($this->_sent_charset) {
+ $foot .= $crlf
+ . '/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;'
+ . $crlf
+ . '/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;'
+ . $crlf
+ . '/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;'
+ . $crlf;
+ $this->_sent_charset = false;
+ }
+
+ /* Restore timezone */
+ if (isset($GLOBALS['sql_utc_time']) && $GLOBALS['sql_utc_time']) {
+ $GLOBALS['dbi']->query('SET time_zone = "' . $GLOBALS['old_tz'] . '"');
+ }
+
+ return $this->export->outputHandler($foot);
+ }
+
+ /**
+ * Outputs export header. It is the first method to be called, so all
+ * the required variables are initialized here.
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportHeader()
+ {
+ global $crlf, $cfg;
+
+ if (isset($GLOBALS['sql_compatibility'])) {
+ $tmp_compat = $GLOBALS['sql_compatibility'];
+ if ($tmp_compat == 'NONE') {
+ $tmp_compat = '';
+ }
+ $GLOBALS['dbi']->tryQuery('SET SQL_MODE="' . $tmp_compat . '"');
+ unset($tmp_compat);
+ }
+ $head = $this->_exportComment('phpMyAdmin SQL Dump')
+ . $this->_exportComment('version ' . PMA_VERSION)
+ . $this->_exportComment('https://www.phpmyadmin.net/')
+ . $this->_exportComment();
+ $host_string = __('Host:') . ' ' . $cfg['Server']['host'];
+ if (! empty($cfg['Server']['port'])) {
+ $host_string .= ':' . $cfg['Server']['port'];
+ }
+ $head .= $this->_exportComment($host_string);
+ $head .= $this->_exportComment(
+ __('Generation Time:') . ' '
+ . Util::localisedDate()
+ )
+ . $this->_exportComment(
+ __('Server version:') . ' ' . $GLOBALS['dbi']->getVersionString()
+ )
+ . $this->_exportComment(__('PHP Version:') . ' ' . PHP_VERSION)
+ . $this->_possibleCRLF();
+
+ if (isset($GLOBALS['sql_header_comment'])
+ && ! empty($GLOBALS['sql_header_comment'])
+ ) {
+ // '\n' is not a newline (like "\n" would be), it's the characters
+ // backslash and n, as explained on the export interface
+ $lines = explode('\n', $GLOBALS['sql_header_comment']);
+ $head .= $this->_exportComment();
+ foreach ($lines as $one_line) {
+ $head .= $this->_exportComment($one_line);
+ }
+ $head .= $this->_exportComment();
+ }
+
+ if (isset($GLOBALS['sql_disable_fk'])) {
+ $head .= 'SET FOREIGN_KEY_CHECKS=0;' . $crlf;
+ }
+
+ // We want exported AUTO_INCREMENT columns to have still same value,
+ // do this only for recent MySQL exports
+ if (! isset($GLOBALS['sql_compatibility'])
+ || $GLOBALS['sql_compatibility'] == 'NONE'
+ ) {
+ $head .= 'SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";' . $crlf;
+ }
+
+ if (isset($GLOBALS['sql_use_transaction'])) {
+ $head .= 'SET AUTOCOMMIT = 0;' . $crlf
+ . 'START TRANSACTION;' . $crlf;
+ }
+
+ /* Change timezone if we should export timestamps in UTC */
+ if (isset($GLOBALS['sql_utc_time']) && $GLOBALS['sql_utc_time']) {
+ $head .= 'SET time_zone = "+00:00";' . $crlf;
+ $GLOBALS['old_tz'] = $GLOBALS['dbi']
+ ->fetchValue('SELECT @@session.time_zone');
+ $GLOBALS['dbi']->query('SET time_zone = "+00:00"');
+ }
+
+ $head .= $this->_possibleCRLF();
+
+ if (! empty($GLOBALS['asfile'])) {
+ // we are saving as file, therefore we provide charset information
+ // so that a utility like the mysql client can interpret
+ // the file correctly
+ if (isset($GLOBALS['charset'])
+ && isset(Charsets::$mysqlCharsetMap[$GLOBALS['charset']])
+ ) {
+ // we got a charset from the export dialog
+ $set_names = Charsets::$mysqlCharsetMap[$GLOBALS['charset']];
+ } else {
+ // by default we use the connection charset
+ $set_names = Charsets::$mysqlCharsetMap['utf-8'];
+ }
+ if ($set_names == 'utf8' && $GLOBALS['dbi']->getVersion() > 50503) {
+ $set_names = 'utf8mb4';
+ }
+ $head .= $crlf
+ . '/*!40101 SET @OLD_CHARACTER_SET_CLIENT='
+ . '@@CHARACTER_SET_CLIENT */;' . $crlf
+ . '/*!40101 SET @OLD_CHARACTER_SET_RESULTS='
+ . '@@CHARACTER_SET_RESULTS */;' . $crlf
+ . '/*!40101 SET @OLD_COLLATION_CONNECTION='
+ . '@@COLLATION_CONNECTION */;' . $crlf
+ . '/*!40101 SET NAMES ' . $set_names . ' */;' . $crlf . $crlf;
+ $this->_sent_charset = true;
+ }
+
+ return $this->export->outputHandler($head);
+ }
+
+ /**
+ * Outputs CREATE DATABASE statement
+ *
+ * @param string $db Database name
+ * @param string $export_type 'server', 'database', 'table'
+ * @param string $db_alias Aliases of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBCreate($db, $export_type, $db_alias = '')
+ {
+ global $crlf;
+
+ if (empty($db_alias)) {
+ $db_alias = $db;
+ }
+ if (isset($GLOBALS['sql_compatibility'])) {
+ $compat = $GLOBALS['sql_compatibility'];
+ } else {
+ $compat = 'NONE';
+ }
+ if (isset($GLOBALS['sql_drop_database'])) {
+ if (! $this->export->outputHandler(
+ 'DROP DATABASE IF EXISTS '
+ . Util::backquoteCompat(
+ $db_alias,
+ $compat,
+ isset($GLOBALS['sql_backquotes'])
+ )
+ . ';' . $crlf
+ )
+ ) {
+ return false;
+ }
+ }
+ if ($export_type == 'database' && ! isset($GLOBALS['sql_create_database'])) {
+ return true;
+ }
+
+ $create_query = 'CREATE DATABASE IF NOT EXISTS '
+ . Util::backquoteCompat(
+ $db_alias,
+ $compat,
+ isset($GLOBALS['sql_backquotes'])
+ );
+ $collation = $GLOBALS['dbi']->getDbCollation($db);
+ if (mb_strpos($collation, '_')) {
+ $create_query .= ' DEFAULT CHARACTER SET '
+ . mb_substr(
+ $collation,
+ 0,
+ mb_strpos($collation, '_')
+ )
+ . ' COLLATE ' . $collation;
+ } else {
+ $create_query .= ' DEFAULT CHARACTER SET ' . $collation;
+ }
+ $create_query .= ';' . $crlf;
+ if (! $this->export->outputHandler($create_query)) {
+ return false;
+ }
+
+ return $this->_exportUseStatement($db_alias, $compat);
+ }
+
+ /**
+ * Outputs USE statement
+ *
+ * @param string $db db to use
+ * @param string $compat sql compatibility
+ *
+ * @return bool Whether it succeeded
+ */
+ private function _exportUseStatement($db, $compat)
+ {
+ global $crlf;
+
+ if (isset($GLOBALS['sql_compatibility'])
+ && $GLOBALS['sql_compatibility'] == 'NONE'
+ ) {
+ $result = $this->export->outputHandler(
+ 'USE '
+ . Util::backquoteCompat(
+ $db,
+ $compat,
+ isset($GLOBALS['sql_backquotes'])
+ )
+ . ';' . $crlf
+ );
+ } else {
+ $result = $this->export->outputHandler('USE ' . $db . ';' . $crlf);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Outputs database header
+ *
+ * @param string $db Database name
+ * @param string $db_alias Alias of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBHeader($db, $db_alias = '')
+ {
+ if (empty($db_alias)) {
+ $db_alias = $db;
+ }
+ if (isset($GLOBALS['sql_compatibility'])) {
+ $compat = $GLOBALS['sql_compatibility'];
+ } else {
+ $compat = 'NONE';
+ }
+ $head = $this->_exportComment()
+ . $this->_exportComment(
+ __('Database:') . ' '
+ . Util::backquoteCompat(
+ $db_alias,
+ $compat,
+ isset($GLOBALS['sql_backquotes'])
+ )
+ )
+ . $this->_exportComment();
+
+ return $this->export->outputHandler($head);
+ }
+
+ /**
+ * Outputs database footer
+ *
+ * @param string $db Database name
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBFooter($db)
+ {
+ global $crlf;
+
+ $result = true;
+
+ //add indexes to the sql dump file
+ if (isset($GLOBALS['sql_indexes'])) {
+ $result = $this->export->outputHandler($GLOBALS['sql_indexes']);
+ unset($GLOBALS['sql_indexes']);
+ }
+ //add auto increments to the sql dump file
+ if (isset($GLOBALS['sql_auto_increments'])) {
+ $result = $this->export->outputHandler($GLOBALS['sql_auto_increments']);
+ unset($GLOBALS['sql_auto_increments']);
+ }
+ //add constraints to the sql dump file
+ if (isset($GLOBALS['sql_constraints'])) {
+ $result = $this->export->outputHandler($GLOBALS['sql_constraints']);
+ unset($GLOBALS['sql_constraints']);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Exports events
+ *
+ * @param string $db Database
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportEvents($db)
+ {
+ global $crlf;
+
+ $text = '';
+ $delimiter = '$$';
+
+ $event_names = $GLOBALS['dbi']->fetchResult(
+ "SELECT EVENT_NAME FROM information_schema.EVENTS WHERE"
+ . " EVENT_SCHEMA= '" . $GLOBALS['dbi']->escapeString($db)
+ . "';"
+ );
+
+ if ($event_names) {
+ $text .= $crlf
+ . "DELIMITER " . $delimiter . $crlf;
+
+ $text .= $this->_exportComment()
+ . $this->_exportComment(__('Events'))
+ . $this->_exportComment();
+
+ foreach ($event_names as $event_name) {
+ if (! empty($GLOBALS['sql_drop_table'])) {
+ $text .= "DROP EVENT "
+ . Util::backquote($event_name)
+ . $delimiter . $crlf;
+ }
+ $text .= $GLOBALS['dbi']->getDefinition($db, 'EVENT', $event_name)
+ . $delimiter . $crlf . $crlf;
+ }
+
+ $text .= "DELIMITER ;" . $crlf;
+ }
+
+ if (! empty($text)) {
+ return $this->export->outputHandler($text);
+ }
+
+ return false;
+ }
+
+ /**
+ * Exports metadata from Configuration Storage
+ *
+ * @param string $db database being exported
+ * @param string|array $tables table(s) being exported
+ * @param array $metadataTypes types of metadata to export
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportMetadata(
+ $db,
+ $tables,
+ array $metadataTypes
+ ) {
+ $cfgRelation = $this->relation->getRelationsParam();
+ if (! isset($cfgRelation['db'])) {
+ return true;
+ }
+
+ $comment = $this->_possibleCRLF()
+ . $this->_possibleCRLF()
+ . $this->_exportComment()
+ . $this->_exportComment(__('Metadata'))
+ . $this->_exportComment();
+ if (! $this->export->outputHandler($comment)) {
+ return false;
+ }
+
+ if (! $this->_exportUseStatement(
+ $cfgRelation['db'],
+ $GLOBALS['sql_compatibility']
+ )
+ ) {
+ return false;
+ }
+
+ $r = true;
+ if (is_array($tables)) {
+ // export metadata for each table
+ foreach ($tables as $table) {
+ $r &= $this->_exportMetadata($db, $table, $metadataTypes);
+ }
+ // export metadata for the database
+ $r &= $this->_exportMetadata($db, null, $metadataTypes);
+ } else {
+ // export metadata for single table
+ $r &= $this->_exportMetadata($db, $tables, $metadataTypes);
+ }
+
+ return $r;
+ }
+
+ /**
+ * Exports metadata from Configuration Storage
+ *
+ * @param string $db database being exported
+ * @param string $table table being exported
+ * @param array $metadataTypes types of metadata to export
+ *
+ * @return bool Whether it succeeded
+ */
+ private function _exportMetadata(
+ $db,
+ $table,
+ array $metadataTypes
+ ) {
+ $cfgRelation = $this->relation->getRelationsParam();
+
+ if (isset($table)) {
+ $types = [
+ 'column_info' => 'db_name',
+ 'table_uiprefs' => 'db_name',
+ 'tracking' => 'db_name',
+ ];
+ } else {
+ $types = [
+ 'bookmark' => 'dbase',
+ 'relation' => 'master_db',
+ 'pdf_pages' => 'db_name',
+ 'savedsearches' => 'db_name',
+ 'central_columns' => 'db_name',
+ ];
+ }
+
+ $aliases = [];
+
+ $comment = $this->_possibleCRLF()
+ . $this->_exportComment();
+
+ if (isset($table)) {
+ $comment .= $this->_exportComment(
+ sprintf(
+ __('Metadata for table %s'),
+ $table
+ )
+ );
+ } else {
+ $comment .= $this->_exportComment(
+ sprintf(
+ __('Metadata for database %s'),
+ $db
+ )
+ );
+ }
+
+ $comment .= $this->_exportComment();
+
+ if (! $this->export->outputHandler($comment)) {
+ return false;
+ }
+
+ foreach ($types as $type => $dbNameColumn) {
+ if (in_array($type, $metadataTypes) && isset($cfgRelation[$type])) {
+ // special case, designer pages and their coordinates
+ if ($type == 'pdf_pages') {
+ $sql_query = "SELECT `page_nr`, `page_descr` FROM "
+ . Util::backquote($cfgRelation['db'])
+ . "." . Util::backquote($cfgRelation[$type])
+ . " WHERE " . Util::backquote($dbNameColumn)
+ . " = '" . $GLOBALS['dbi']->escapeString($db) . "'";
+
+ $result = $GLOBALS['dbi']->fetchResult(
+ $sql_query,
+ 'page_nr',
+ 'page_descr'
+ );
+
+ foreach ($result as $page => $name) {
+ // insert row for pdf_page
+ $sql_query_row = "SELECT `db_name`, `page_descr` FROM "
+ . Util::backquote($cfgRelation['db'])
+ . "." . Util::backquote(
+ $cfgRelation[$type]
+ )
+ . " WHERE " . Util::backquote(
+ $dbNameColumn
+ )
+ . " = '" . $GLOBALS['dbi']->escapeString($db) . "'"
+ . " AND `page_nr` = '" . intval($page) . "'";
+
+ if (! $this->exportData(
+ $cfgRelation['db'],
+ $cfgRelation[$type],
+ $GLOBALS['crlf'],
+ '',
+ $sql_query_row,
+ $aliases
+ )
+ ) {
+ return false;
+ }
+
+ $lastPage = $GLOBALS['crlf']
+ . "SET @LAST_PAGE = LAST_INSERT_ID();"
+ . $GLOBALS['crlf'];
+ if (! $this->export->outputHandler($lastPage)) {
+ return false;
+ }
+
+ $sql_query_coords = "SELECT `db_name`, `table_name`, "
+ . "'@LAST_PAGE' AS `pdf_page_number`, `x`, `y` FROM "
+ . Util::backquote($cfgRelation['db'])
+ . "." . Util::backquote(
+ $cfgRelation['table_coords']
+ )
+ . " WHERE `pdf_page_number` = '" . $page . "'";
+
+ $GLOBALS['exporting_metadata'] = true;
+ if (! $this->exportData(
+ $cfgRelation['db'],
+ $cfgRelation['table_coords'],
+ $GLOBALS['crlf'],
+ '',
+ $sql_query_coords,
+ $aliases
+ )
+ ) {
+ $GLOBALS['exporting_metadata'] = false;
+
+ return false;
+ }
+ $GLOBALS['exporting_metadata'] = false;
+ }
+ continue;
+ }
+
+ // remove auto_incrementing id field for some tables
+ if ($type == 'bookmark') {
+ $sql_query = "SELECT `dbase`, `user`, `label`, `query` FROM ";
+ } elseif ($type == 'column_info') {
+ $sql_query = "SELECT `db_name`, `table_name`, `column_name`,"
+ . " `comment`, `mimetype`, `transformation`,"
+ . " `transformation_options`, `input_transformation`,"
+ . " `input_transformation_options` FROM";
+ } elseif ($type == 'savedsearches') {
+ $sql_query = "SELECT `username`, `db_name`, `search_name`,"
+ . " `search_data` FROM";
+ } else {
+ $sql_query = "SELECT * FROM ";
+ }
+ $sql_query .= Util::backquote($cfgRelation['db'])
+ . '.' . Util::backquote($cfgRelation[$type])
+ . " WHERE " . Util::backquote($dbNameColumn)
+ . " = '" . $GLOBALS['dbi']->escapeString($db) . "'";
+ if (isset($table)) {
+ $sql_query .= " AND `table_name` = '"
+ . $GLOBALS['dbi']->escapeString($table) . "'";
+ }
+
+ if (! $this->exportData(
+ $cfgRelation['db'],
+ $cfgRelation[$type],
+ $GLOBALS['crlf'],
+ '',
+ $sql_query,
+ $aliases
+ )
+ ) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * 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 = [])
+ {
+ $db_alias = $db;
+ $view_alias = $view;
+ $this->initAlias($aliases, $db_alias, $view_alias);
+ $create_query = '';
+ if (! empty($GLOBALS['sql_drop_table'])) {
+ $create_query .= 'DROP VIEW IF EXISTS '
+ . Util::backquote($view_alias)
+ . ';' . $crlf;
+ }
+
+ $create_query .= 'CREATE TABLE ';
+
+ if (isset($GLOBALS['sql_if_not_exists'])
+ && $GLOBALS['sql_if_not_exists']
+ ) {
+ $create_query .= 'IF NOT EXISTS ';
+ }
+ $create_query .= Util::backquote($view_alias) . ' (' . $crlf;
+ $tmp = [];
+ $columns = $GLOBALS['dbi']->getColumnsFull($db, $view);
+ foreach ($columns as $column_name => $definition) {
+ $col_alias = $column_name;
+ if (! empty($aliases[$db]['tables'][$view]['columns'][$col_alias])) {
+ $col_alias = $aliases[$db]['tables'][$view]['columns'][$col_alias];
+ }
+ $tmp[] = Util::backquote($col_alias) . ' ' .
+ $definition['Type'] . $crlf;
+ }
+ $create_query .= implode(',', $tmp) . ');' . $crlf;
+
+ return $create_query;
+ }
+
+ /**
+ * Returns CREATE definition that matches $view's structure
+ *
+ * @param string $db the database name
+ * @param string $view the view name
+ * @param string $crlf the end of line sequence
+ * @param bool $add_semicolon whether to add semicolon and end-of-line at
+ * the end
+ * @param array $aliases Aliases of db/table/columns
+ *
+ * @return string resulting schema
+ */
+ private function _getTableDefForView(
+ $db,
+ $view,
+ $crlf,
+ $add_semicolon = true,
+ array $aliases = []
+ ) {
+ $db_alias = $db;
+ $view_alias = $view;
+ $this->initAlias($aliases, $db_alias, $view_alias);
+ $create_query = "CREATE TABLE";
+ if (isset($GLOBALS['sql_if_not_exists'])) {
+ $create_query .= " IF NOT EXISTS ";
+ }
+ $create_query .= Util::backquote($view_alias) . "(" . $crlf;
+
+ $columns = $GLOBALS['dbi']->getColumns($db, $view, null, true);
+
+ $firstCol = true;
+ foreach ($columns as $column) {
+ $col_alias = $column['Field'];
+ if (! empty($aliases[$db]['tables'][$view]['columns'][$col_alias])) {
+ $col_alias = $aliases[$db]['tables'][$view]['columns'][$col_alias];
+ }
+ $extracted_columnspec = Util::extractColumnSpec(
+ $column['Type']
+ );
+
+ if (! $firstCol) {
+ $create_query .= "," . $crlf;
+ }
+ $create_query .= " " . Util::backquote($col_alias);
+ $create_query .= " " . $column['Type'];
+ if ($extracted_columnspec['can_contain_collation']
+ && ! empty($column['Collation'])
+ ) {
+ $create_query .= " COLLATE " . $column['Collation'];
+ }
+ if ($column['Null'] == 'NO') {
+ $create_query .= " NOT NULL";
+ }
+ if (isset($column['Default'])) {
+ $create_query .= " DEFAULT '"
+ . $GLOBALS['dbi']->escapeString($column['Default']) . "'";
+ } else {
+ if ($column['Null'] == 'YES') {
+ $create_query .= " DEFAULT NULL";
+ }
+ }
+ if (! empty($column['Comment'])) {
+ $create_query .= " COMMENT '"
+ . $GLOBALS['dbi']->escapeString($column['Comment']) . "'";
+ }
+ $firstCol = false;
+ }
+ $create_query .= $crlf . ")" . ($add_semicolon ? ';' : '') . $crlf;
+
+ if (isset($GLOBALS['sql_compatibility'])) {
+ $compat = $GLOBALS['sql_compatibility'];
+ } else {
+ $compat = 'NONE';
+ }
+ if ($compat == 'MSSQL') {
+ $create_query = $this->_makeCreateTableMSSQLCompatible(
+ $create_query
+ );
+ }
+
+ return $create_query;
+ }
+
+ /**
+ * 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 $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 bool $update_indexes_increments whether we need to update
+ * two global variables
+ * @param array $aliases Aliases of db/table/columns
+ *
+ * @return string resulting schema
+ */
+ public function getTableDef(
+ $db,
+ $table,
+ $crlf,
+ $error_url,
+ $show_dates = false,
+ $add_semicolon = true,
+ $view = false,
+ $update_indexes_increments = true,
+ array $aliases = []
+ ) {
+ global $sql_drop_table, $sql_backquotes, $sql_constraints,
+ $sql_constraints_query, $sql_indexes, $sql_indexes_query,
+ $sql_auto_increments, $sql_drop_foreign_keys;
+
+ $db_alias = $db;
+ $table_alias = $table;
+ $this->initAlias($aliases, $db_alias, $table_alias);
+
+ $schema_create = '';
+ $auto_increment = '';
+ $new_crlf = $crlf;
+
+ if (isset($GLOBALS['sql_compatibility'])) {
+ $compat = $GLOBALS['sql_compatibility'];
+ } else {
+ $compat = 'NONE';
+ }
+
+ // need to use PhpMyAdmin\DatabaseInterface::QUERY_STORE
+ // with $GLOBALS['dbi']->numRows() in mysqli
+ $result = $GLOBALS['dbi']->tryQuery(
+ 'SHOW TABLE STATUS FROM ' . Util::backquote($db)
+ . ' WHERE Name = \'' . $GLOBALS['dbi']->escapeString((string) $table) . '\'',
+ DatabaseInterface::CONNECT_USER,
+ DatabaseInterface::QUERY_STORE
+ );
+ if ($result != false) {
+ if ($GLOBALS['dbi']->numRows($result) > 0) {
+ $tmpres = $GLOBALS['dbi']->fetchAssoc($result);
+
+ // Here we optionally add the AUTO_INCREMENT next value,
+ // but starting with MySQL 5.0.24, the clause is already included
+ // in SHOW CREATE TABLE so we'll remove it below
+ if (isset($GLOBALS['sql_auto_increment'])
+ && ! empty($tmpres['Auto_increment'])
+ ) {
+ $auto_increment .= ' AUTO_INCREMENT='
+ . $tmpres['Auto_increment'] . ' ';
+ }
+
+ if ($show_dates
+ && isset($tmpres['Create_time'])
+ && ! empty($tmpres['Create_time'])
+ ) {
+ $schema_create .= $this->_exportComment(
+ __('Creation:') . ' '
+ . Util::localisedDate(
+ strtotime($tmpres['Create_time'])
+ )
+ );
+ $new_crlf = $this->_exportComment() . $crlf;
+ }
+
+ if ($show_dates
+ && isset($tmpres['Update_time'])
+ && ! empty($tmpres['Update_time'])
+ ) {
+ $schema_create .= $this->_exportComment(
+ __('Last update:') . ' '
+ . Util::localisedDate(
+ strtotime($tmpres['Update_time'])
+ )
+ );
+ $new_crlf = $this->_exportComment() . $crlf;
+ }
+
+ if ($show_dates
+ && isset($tmpres['Check_time'])
+ && ! empty($tmpres['Check_time'])
+ ) {
+ $schema_create .= $this->_exportComment(
+ __('Last check:') . ' '
+ . Util::localisedDate(
+ strtotime($tmpres['Check_time'])
+ )
+ );
+ $new_crlf = $this->_exportComment() . $crlf;
+ }
+ }
+ $GLOBALS['dbi']->freeResult($result);
+ }
+
+ $schema_create .= $new_crlf;
+
+ if (! empty($sql_drop_table)
+ && $GLOBALS['dbi']->getTable($db, $table)->isView()
+ ) {
+ $schema_create .= 'DROP VIEW IF EXISTS '
+ . Util::backquote($table_alias, $sql_backquotes) . ';'
+ . $crlf;
+ }
+
+ // no need to generate a DROP VIEW here, it was done earlier
+ if (! empty($sql_drop_table)
+ && ! $GLOBALS['dbi']->getTable($db, $table)->isView()
+ ) {
+ $schema_create .= 'DROP TABLE IF EXISTS '
+ . Util::backquote($table_alias, $sql_backquotes) . ';'
+ . $crlf;
+ }
+
+ // Complete table dump,
+ // Whether to quote table and column names or not
+ if ($sql_backquotes) {
+ $GLOBALS['dbi']->query('SET SQL_QUOTE_SHOW_CREATE = 1');
+ } else {
+ $GLOBALS['dbi']->query('SET SQL_QUOTE_SHOW_CREATE = 0');
+ }
+
+ // I don't see the reason why this unbuffered query could cause problems,
+ // because SHOW CREATE TABLE returns only one row, and we free the
+ // results below. Nonetheless, we got 2 user reports about this
+ // (see bug 1562533) so I removed the unbuffered mode.
+ // $result = $GLOBALS['dbi']->query('SHOW CREATE TABLE ' . backquote($db)
+ // . '.' . backquote($table), null, DatabaseInterface::QUERY_UNBUFFERED);
+ //
+ // Note: SHOW CREATE TABLE, at least in MySQL 5.1.23, does not
+ // produce a displayable result for the default value of a BIT
+ // column, nor does the mysqldump command. See MySQL bug 35796
+ $GLOBALS['dbi']->tryQuery('USE ' . Util::backquote($db));
+ $result = $GLOBALS['dbi']->tryQuery(
+ 'SHOW CREATE TABLE ' . Util::backquote($db) . '.'
+ . Util::backquote($table)
+ );
+ // an error can happen, for example the table is crashed
+ $tmp_error = $GLOBALS['dbi']->getError();
+ if ($tmp_error) {
+ $message = sprintf(__('Error reading structure for table %s:'), "$db.$table");
+ $message .= ' ' . $tmp_error;
+ if (! defined('TESTSUITE')) {
+ trigger_error($message, E_USER_ERROR);
+ }
+ return $this->_exportComment($message);
+ }
+
+ // Old mode is stored so it can be restored once exporting is done.
+ $old_mode = Context::$MODE;
+
+ $warning = '';
+ if ($result != false && ($row = $GLOBALS['dbi']->fetchRow($result))) {
+ $create_query = $row[1];
+ unset($row);
+
+ // Convert end of line chars to one that we want (note that MySQL
+ // doesn't return query it will accept in all cases)
+ if (mb_strpos($create_query, "(\r\n ")) {
+ $create_query = str_replace("\r\n", $crlf, $create_query);
+ } elseif (mb_strpos($create_query, "(\n ")) {
+ $create_query = str_replace("\n", $crlf, $create_query);
+ } elseif (mb_strpos($create_query, "(\r ")) {
+ $create_query = str_replace("\r", $crlf, $create_query);
+ }
+
+ /*
+ * Drop database name from VIEW creation.
+ *
+ * This is a bit tricky, but we need to issue SHOW CREATE TABLE with
+ * database name, but we don't want name to show up in CREATE VIEW
+ * statement.
+ */
+ if ($view) {
+ $create_query = preg_replace(
+ '/' . preg_quote(Util::backquote($db), '/') . '\./',
+ '',
+ $create_query
+ );
+
+ // exclude definition of current user
+ if (isset($GLOBALS['sql_view_current_user'])) {
+ $create_query = preg_replace(
+ '/(^|\s)DEFINER=([\S]+)/',
+ '',
+ $create_query
+ );
+ }
+
+ // whether to replace existing view or not
+ if (isset($GLOBALS['sql_or_replace_view'])) {
+ $create_query = preg_replace(
+ '/^CREATE/',
+ 'CREATE OR REPLACE',
+ $create_query
+ );
+ }
+ }
+
+ // Substitute aliases in `CREATE` query.
+ $create_query = $this->replaceWithAliases(
+ $create_query,
+ $aliases,
+ $db,
+ $table,
+ $flag
+ );
+
+ // One warning per view.
+ if ($flag && $view) {
+ $warning = $this->_exportComment()
+ . $this->_exportComment(
+ __('It appears your database uses views;')
+ )
+ . $this->_exportComment(
+ __('alias export may not work reliably in all cases.')
+ )
+ . $this->_exportComment();
+ }
+
+ // Adding IF NOT EXISTS, if required.
+ if (isset($GLOBALS['sql_if_not_exists'])) {
+ $create_query = preg_replace(
+ '/^CREATE TABLE/',
+ 'CREATE TABLE IF NOT EXISTS',
+ $create_query
+ );
+ }
+
+ // Making the query MSSQL compatible.
+ if ($compat == 'MSSQL') {
+ $create_query = $this->_makeCreateTableMSSQLCompatible(
+ $create_query
+ );
+ }
+
+ // Views have no constraints, indexes, etc. They do not require any
+ // analysis.
+ if (! $view) {
+ if (empty($sql_backquotes)) {
+ // Option "Enclose table and column names with backquotes"
+ // was checked.
+ Context::$MODE |= Context::SQL_MODE_NO_ENCLOSING_QUOTES;
+ }
+
+ // Using appropriate quotes.
+ if (($compat === 'MSSQL') || ($sql_backquotes === '"')) {
+ Context::$MODE |= Context::SQL_MODE_ANSI_QUOTES;
+ }
+ }
+
+ /**
+ * Parser used for analysis.
+ *
+ * @var Parser
+ */
+ $parser = new Parser($create_query);
+
+ /**
+ * `CREATE TABLE` statement.
+ *
+ * @var CreateStatement
+ */
+ $statement = $parser->statements[0];
+
+ if (! empty($statement->entityOptions)) {
+ $engine = $statement->entityOptions->has('ENGINE');
+ } else {
+ $engine = '';
+ }
+
+ /* Avoid operation on ARCHIVE tables as those can not be altered */
+ if (! empty($statement->fields) && (empty($engine) || strtoupper($engine) != 'ARCHIVE')) {
+
+ /**
+ * Fragments containining definition of each constraint.
+ *
+ * @var array
+ */
+ $constraints = [];
+
+ /**
+ * Fragments containining definition of each index.
+ *
+ * @var array
+ */
+ $indexes = [];
+
+ /**
+ * Fragments containining definition of each FULLTEXT index.
+ *
+ * @var array
+ */
+ $indexes_fulltext = [];
+
+ /**
+ * Fragments containining definition of each foreign key that will
+ * be dropped.
+ *
+ * @var array
+ */
+ $dropped = [];
+
+ /**
+ * Fragment containining definition of the `AUTO_INCREMENT`.
+ *
+ * @var array
+ */
+ $auto_increment = [];
+
+ // Scanning each field of the `CREATE` statement to fill the arrays
+ // above.
+ // If the field is used in any of the arrays above, it is removed
+ // from the original definition.
+ // Also, AUTO_INCREMENT attribute is removed.
+ /** @var CreateDefinition $field */
+ foreach ($statement->fields as $key => $field) {
+ if ($field->isConstraint) {
+ // Creating the parts that add constraints.
+ $constraints[] = $field::build($field);
+ unset($statement->fields[$key]);
+ } elseif (! empty($field->key)) {
+ // Creating the parts that add indexes (must not be
+ // constraints).
+ if ($field->key->type === 'FULLTEXT KEY') {
+ $indexes_fulltext[] = $field->build($field);
+ unset($statement->fields[$key]);
+ } else {
+ if (empty($GLOBALS['sql_if_not_exists'])) {
+ $indexes[] = str_replace(
+ 'COMMENT=\'',
+ 'COMMENT \'',
+ $field::build($field)
+ );
+ unset($statement->fields[$key]);
+ }
+ }
+ }
+
+ // Creating the parts that drop foreign keys.
+ if (! empty($field->key)) {
+ if ($field->key->type === 'FOREIGN KEY') {
+ $dropped[] = 'FOREIGN KEY ' . Context::escape(
+ $field->name
+ );
+ unset($statement->fields[$key]);
+ }
+ }
+
+ // Dropping AUTO_INCREMENT.
+ if (! empty($field->options)) {
+ if ($field->options->has('AUTO_INCREMENT')
+ && empty($GLOBALS['sql_if_not_exists'])
+ ) {
+ $auto_increment[] = $field::build($field);
+ $field->options->remove('AUTO_INCREMENT');
+ }
+ }
+ }
+
+ /**
+ * The header of the `ALTER` statement (`ALTER TABLE tbl`).
+ *
+ * @var string
+ */
+ $alter_header = 'ALTER TABLE ' .
+ Util::backquoteCompat(
+ $table_alias,
+ $compat,
+ $sql_backquotes
+ );
+
+ /**
+ * The footer of the `ALTER` statement (usually ';')
+ *
+ * @var string
+ */
+ $alter_footer = ';' . $crlf;
+
+ // Generating constraints-related query.
+ if (! empty($constraints)) {
+ $sql_constraints_query = $alter_header . $crlf . ' ADD '
+ . implode(',' . $crlf . ' ADD ', $constraints)
+ . $alter_footer;
+
+ $sql_constraints = $this->generateComment(
+ $crlf,
+ $sql_constraints,
+ __('Constraints for dumped tables'),
+ __('Constraints for table'),
+ $table_alias,
+ $compat
+ ) . $sql_constraints_query;
+ }
+
+ // Generating indexes-related query.
+ $sql_indexes_query = '';
+
+ if (! empty($indexes)) {
+ $sql_indexes_query .= $alter_header . $crlf . ' ADD '
+ . implode(',' . $crlf . ' ADD ', $indexes)
+ . $alter_footer;
+ }
+
+ if (! empty($indexes_fulltext)) {
+ // InnoDB supports one FULLTEXT index creation at a time.
+ // So FULLTEXT indexes are created one-by-one after other
+ // indexes where created.
+ $sql_indexes_query .= $alter_header .
+ ' ADD ' . implode(
+ $alter_footer . $alter_header . ' ADD ',
+ $indexes_fulltext
+ ) . $alter_footer;
+ }
+
+ if (! empty($indexes) || ! empty($indexes_fulltext)) {
+ $sql_indexes = $this->generateComment(
+ $crlf,
+ $sql_indexes,
+ __('Indexes for dumped tables'),
+ __('Indexes for table'),
+ $table_alias,
+ $compat
+ ) . $sql_indexes_query;
+ }
+
+ // Generating drop foreign keys-related query.
+ if (! empty($dropped)) {
+ $sql_drop_foreign_keys = $alter_header . $crlf . ' DROP '
+ . implode(',' . $crlf . ' DROP ', $dropped)
+ . $alter_footer;
+ }
+
+ // Generating auto-increment-related query.
+ if (! empty($auto_increment) && $update_indexes_increments) {
+ $sql_auto_increments_query = $alter_header . $crlf . ' MODIFY '
+ . implode(',' . $crlf . ' MODIFY ', $auto_increment);
+ if (isset($GLOBALS['sql_auto_increment'])
+ && ($statement->entityOptions->has('AUTO_INCREMENT') !== false)
+ ) {
+ if (! isset($GLOBALS['table_data'])
+ || (isset($GLOBALS['table_data'])
+ && in_array($table, $GLOBALS['table_data']))
+ ) {
+ $sql_auto_increments_query .= ', AUTO_INCREMENT='
+ . $statement->entityOptions->has('AUTO_INCREMENT');
+ }
+ }
+ $sql_auto_increments_query .= ';' . $crlf;
+
+ $sql_auto_increments = $this->generateComment(
+ $crlf,
+ $sql_auto_increments,
+ __('AUTO_INCREMENT for dumped tables'),
+ __('AUTO_INCREMENT for table'),
+ $table_alias,
+ $compat
+ ) . $sql_auto_increments_query;
+ }
+
+ // Removing the `AUTO_INCREMENT` attribute from the `CREATE TABLE`
+ // too.
+ if (! empty($statement->entityOptions)
+ && (empty($GLOBALS['sql_if_not_exists'])
+ || empty($GLOBALS['sql_auto_increment']))
+ ) {
+ $statement->entityOptions->remove('AUTO_INCREMENT');
+ }
+
+ // Rebuilding the query.
+ $create_query = $statement->build();
+ }
+
+ $schema_create .= $create_query;
+ }
+
+ $GLOBALS['dbi']->freeResult($result);
+
+ // Restoring old mode.
+ Context::$MODE = $old_mode;
+
+ return $warning . $schema_create . ($add_semicolon ? ';' . $crlf : '');
+ } // end of the 'getTableDef()' function
+
+ /**
+ * Returns $table's comments, relations etc.
+ *
+ * @param string $db database name
+ * @param string $table table name
+ * @param string $crlf end of line sequence
+ * @param bool $do_relation whether to include relation comments
+ * @param bool $do_mime whether to include mime comments
+ * @param array $aliases Aliases of db/table/columns
+ *
+ * @return string resulting comments
+ */
+ private function _getTableComments(
+ $db,
+ $table,
+ $crlf,
+ $do_relation = false,
+ $do_mime = false,
+ array $aliases = []
+ ) {
+ global $cfgRelation, $sql_backquotes;
+
+ $db_alias = $db;
+ $table_alias = $table;
+ $this->initAlias($aliases, $db_alias, $table_alias);
+
+ $schema_create = '';
+
+ // Check if we can use Relations
+ list($res_rel, $have_rel) = $this->relation->getRelationsAndStatus(
+ $do_relation && ! empty($cfgRelation['relation']),
+ $db,
+ $table
+ );
+
+ if ($do_mime && $cfgRelation['mimework']) {
+ if (! ($mime_map = $this->transformations->getMime($db, $table, true))) {
+ unset($mime_map);
+ }
+ }
+
+ if (isset($mime_map) && count($mime_map) > 0) {
+ $schema_create .= $this->_possibleCRLF()
+ . $this->_exportComment()
+ . $this->_exportComment(
+ __('MEDIA (MIME) TYPES FOR TABLE') . ' '
+ . Util::backquote($table, $sql_backquotes) . ':'
+ );
+ foreach ($mime_map as $mime_field => $mime) {
+ $schema_create .= $this->_exportComment(
+ ' '
+ . Util::backquote($mime_field, $sql_backquotes)
+ )
+ . $this->_exportComment(
+ ' '
+ . Util::backquote(
+ $mime['mimetype'],
+ $sql_backquotes
+ )
+ );
+ }
+ $schema_create .= $this->_exportComment();
+ }
+
+ if ($have_rel) {
+ $schema_create .= $this->_possibleCRLF()
+ . $this->_exportComment()
+ . $this->_exportComment(
+ __('RELATIONSHIPS FOR TABLE') . ' '
+ . Util::backquote($table_alias, $sql_backquotes)
+ . ':'
+ );
+
+ foreach ($res_rel as $rel_field => $rel) {
+ if ($rel_field != 'foreign_keys_data') {
+ $rel_field_alias = ! empty(
+ $aliases[$db]['tables'][$table]['columns'][$rel_field]
+ ) ? $aliases[$db]['tables'][$table]['columns'][$rel_field]
+ : $rel_field;
+ $schema_create .= $this->_exportComment(
+ ' '
+ . Util::backquote(
+ $rel_field_alias,
+ $sql_backquotes
+ )
+ )
+ . $this->_exportComment(
+ ' '
+ . Util::backquote(
+ $rel['foreign_table'],
+ $sql_backquotes
+ )
+ . ' -> '
+ . Util::backquote(
+ $rel['foreign_field'],
+ $sql_backquotes
+ )
+ );
+ } else {
+ foreach ($rel as $one_key) {
+ foreach ($one_key['index_list'] as $index => $field) {
+ $rel_field_alias = ! empty(
+ $aliases[$db]['tables'][$table]['columns'][$field]
+ ) ? $aliases[$db]['tables'][$table]['columns'][$field]
+ : $field;
+ $schema_create .= $this->_exportComment(
+ ' '
+ . Util::backquote(
+ $rel_field_alias,
+ $sql_backquotes
+ )
+ )
+ . $this->_exportComment(
+ ' '
+ . Util::backquote(
+ $one_key['ref_table_name'],
+ $sql_backquotes
+ )
+ . ' -> '
+ . Util::backquote(
+ $one_key['ref_index_list'][$index],
+ $sql_backquotes
+ )
+ );
+ }
+ }
+ }
+ }
+ $schema_create .= $this->_exportComment();
+ }
+
+ return $schema_create;
+ } // end of the '_getTableComments()' function
+
+ /**
+ * Outputs table's structure
+ *
+ * @param string $db database name
+ * @param string $table table name
+ * @param string $crlf the end of line sequence
+ * @param string $error_url the url to go back in case of error
+ * @param string $export_mode 'create_table','triggers','create_view',
+ * 'stand_in'
+ * @param string $export_type 'server', 'database', 'table'
+ * @param bool $relation whether to include relation comments
+ * @param bool $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.php calls exportStructure()
+ * also for other export types which use this
+ * parameter
+ * @param bool $mime whether to include mime comments
+ * @param bool $dates whether to include creation/update/check dates
+ * @param array $aliases Aliases of db/table/columns
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportStructure(
+ $db,
+ $table,
+ $crlf,
+ $error_url,
+ $export_mode,
+ $export_type,
+ $relation = false,
+ $comments = false,
+ $mime = false,
+ $dates = false,
+ array $aliases = []
+ ) {
+ $db_alias = $db;
+ $table_alias = $table;
+ $this->initAlias($aliases, $db_alias, $table_alias);
+ if (isset($GLOBALS['sql_compatibility'])) {
+ $compat = $GLOBALS['sql_compatibility'];
+ } else {
+ $compat = 'NONE';
+ }
+
+ $formatted_table_name = Util::backquoteCompat(
+ $table_alias,
+ $compat,
+ isset($GLOBALS['sql_backquotes'])
+ );
+ $dump = $this->_possibleCRLF()
+ . $this->_exportComment(str_repeat('-', 56))
+ . $this->_possibleCRLF()
+ . $this->_exportComment();
+
+ switch ($export_mode) {
+ case 'create_table':
+ $dump .= $this->_exportComment(
+ __('Table structure for table') . ' ' . $formatted_table_name
+ );
+ $dump .= $this->_exportComment();
+ $dump .= $this->getTableDef(
+ $db,
+ $table,
+ $crlf,
+ $error_url,
+ $dates,
+ true,
+ false,
+ true,
+ $aliases
+ );
+ $dump .= $this->_getTableComments(
+ $db,
+ $table,
+ $crlf,
+ $relation,
+ $mime,
+ $aliases
+ );
+ break;
+ case 'triggers':
+ $dump = '';
+ $delimiter = '$$';
+ $triggers = $GLOBALS['dbi']->getTriggers($db, $table, $delimiter);
+ if ($triggers) {
+ $dump .= $this->_possibleCRLF()
+ . $this->_exportComment()
+ . $this->_exportComment(
+ __('Triggers') . ' ' . $formatted_table_name
+ )
+ . $this->_exportComment();
+ $used_alias = false;
+ $trigger_query = '';
+ foreach ($triggers as $trigger) {
+ if (! empty($GLOBALS['sql_drop_table'])) {
+ $trigger_query .= $trigger['drop'] . ';' . $crlf;
+ }
+
+ $trigger_query .= 'DELIMITER ' . $delimiter . $crlf;
+ $trigger_query .= $this->replaceWithAliases(
+ $trigger['create'],
+ $aliases,
+ $db,
+ $table,
+ $flag
+ );
+ if ($flag) {
+ $used_alias = true;
+ }
+ $trigger_query .= 'DELIMITER ;' . $crlf;
+ }
+ // One warning per table.
+ if ($used_alias) {
+ $dump .= $this->_exportComment(
+ __('It appears your table uses triggers;')
+ )
+ . $this->_exportComment(
+ __('alias export may not work reliably in all cases.')
+ )
+ . $this->_exportComment();
+ }
+ $dump .= $trigger_query;
+ }
+ break;
+ case 'create_view':
+ if (empty($GLOBALS['sql_views_as_tables'])) {
+ $dump .= $this->_exportComment(
+ __('Structure for view')
+ . ' '
+ . $formatted_table_name
+ )
+ . $this->_exportComment();
+ // delete the stand-in table previously created (if any)
+ if ($export_type != 'table') {
+ $dump .= 'DROP TABLE IF EXISTS '
+ . Util::backquote($table_alias) . ';' . $crlf;
+ }
+ $dump .= $this->getTableDef(
+ $db,
+ $table,
+ $crlf,
+ $error_url,
+ $dates,
+ true,
+ true,
+ true,
+ $aliases
+ );
+ } else {
+ $dump .= $this->_exportComment(
+ sprintf(
+ __('Structure for view %s exported as a table'),
+ $formatted_table_name
+ )
+ )
+ . $this->_exportComment();
+ // delete the stand-in table previously created (if any)
+ if ($export_type != 'table') {
+ $dump .= 'DROP TABLE IF EXISTS '
+ . Util::backquote($table_alias) . ';' . $crlf;
+ }
+ $dump .= $this->_getTableDefForView(
+ $db,
+ $table,
+ $crlf,
+ true,
+ $aliases
+ );
+ }
+ break;
+ case 'stand_in':
+ $dump .= $this->_exportComment(
+ __('Stand-in structure for view') . ' ' . $formatted_table_name
+ )
+ . $this->_exportComment(
+ __('(See below for the actual view)')
+ )
+ . $this->_exportComment();
+ // export a stand-in definition to resolve view dependencies
+ $dump .= $this->getTableDefStandIn($db, $table, $crlf, $aliases);
+ } // end switch
+
+ // this one is built by getTableDef() to use in table copy/move
+ // but not in the case of export
+ unset($GLOBALS['sql_constraints_query']);
+
+ return $this->export->outputHandler($dump);
+ }
+
+ /**
+ * Outputs the content of a table in SQL format
+ *
+ * @param string $db database name
+ * @param string $table table name
+ * @param string $crlf the end of line sequence
+ * @param string $error_url the url to go back in case of error
+ * @param string $sql_query SQL query for obtaining data
+ * @param array $aliases Aliases of db/table/columns
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportData(
+ $db,
+ $table,
+ $crlf,
+ $error_url,
+ $sql_query,
+ array $aliases = []
+ ) {
+ global $current_row, $sql_backquotes;
+
+ // Do not export data for merge tables
+ if ($GLOBALS['dbi']->getTable($db, $table)->isMerge()) {
+ return true;
+ }
+
+ $db_alias = $db;
+ $table_alias = $table;
+ $this->initAlias($aliases, $db_alias, $table_alias);
+
+ if (isset($GLOBALS['sql_compatibility'])) {
+ $compat = $GLOBALS['sql_compatibility'];
+ } else {
+ $compat = 'NONE';
+ }
+
+ $formatted_table_name = Util::backquoteCompat(
+ $table_alias,
+ $compat,
+ $sql_backquotes
+ );
+
+ // Do not export data for a VIEW, unless asked to export the view as a table
+ // (For a VIEW, this is called only when exporting a single VIEW)
+ if ($GLOBALS['dbi']->getTable($db, $table)->isView()
+ && empty($GLOBALS['sql_views_as_tables'])
+ ) {
+ $head = $this->_possibleCRLF()
+ . $this->_exportComment()
+ . $this->_exportComment('VIEW ' . $formatted_table_name)
+ . $this->_exportComment(__('Data:') . ' ' . __('None'))
+ . $this->_exportComment()
+ . $this->_possibleCRLF();
+
+ return $this->export->outputHandler($head);
+ }
+
+ $result = $GLOBALS['dbi']->tryQuery(
+ $sql_query,
+ DatabaseInterface::CONNECT_USER,
+ DatabaseInterface::QUERY_UNBUFFERED
+ );
+ // a possible error: the table has crashed
+ $tmp_error = $GLOBALS['dbi']->getError();
+ if ($tmp_error) {
+ $message = sprintf(__('Error reading data for table %s:'), "$db.$table");
+ $message .= ' ' . $tmp_error;
+ if (! defined('TESTSUITE')) {
+ trigger_error($message, E_USER_ERROR);
+ }
+ return $this->export->outputHandler(
+ $this->_exportComment($message)
+ );
+ }
+
+ if ($result == false) {
+ $GLOBALS['dbi']->freeResult($result);
+
+ return true;
+ }
+
+ $fields_cnt = $GLOBALS['dbi']->numFields($result);
+
+ // Get field information
+ $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result);
+ $field_flags = [];
+ for ($j = 0; $j < $fields_cnt; $j++) {
+ $field_flags[$j] = $GLOBALS['dbi']->fieldFlags($result, $j);
+ }
+
+ $field_set = [];
+ for ($j = 0; $j < $fields_cnt; $j++) {
+ $col_as = $fields_meta[$j]->name;
+ if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) {
+ $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as];
+ }
+ $field_set[$j] = Util::backquoteCompat(
+ $col_as,
+ $compat,
+ $sql_backquotes
+ );
+ }
+
+ if (isset($GLOBALS['sql_type'])
+ && $GLOBALS['sql_type'] == 'UPDATE'
+ ) {
+ // update
+ $schema_insert = 'UPDATE ';
+ if (isset($GLOBALS['sql_ignore'])) {
+ $schema_insert .= 'IGNORE ';
+ }
+ // avoid EOL blank
+ $schema_insert .= Util::backquoteCompat(
+ $table_alias,
+ $compat,
+ $sql_backquotes
+ ) . ' SET';
+ } else {
+ // insert or replace
+ if (isset($GLOBALS['sql_type'])
+ && $GLOBALS['sql_type'] == 'REPLACE'
+ ) {
+ $sql_command = 'REPLACE';
+ } else {
+ $sql_command = 'INSERT';
+ }
+
+ // delayed inserts?
+ if (isset($GLOBALS['sql_delayed'])) {
+ $insert_delayed = ' DELAYED';
+ } else {
+ $insert_delayed = '';
+ }
+
+ // insert ignore?
+ if (isset($GLOBALS['sql_type'])
+ && $GLOBALS['sql_type'] == 'INSERT'
+ && isset($GLOBALS['sql_ignore'])
+ ) {
+ $insert_delayed .= ' IGNORE';
+ }
+ //truncate table before insert
+ if (isset($GLOBALS['sql_truncate'])
+ && $GLOBALS['sql_truncate']
+ && $sql_command == 'INSERT'
+ ) {
+ $truncate = 'TRUNCATE TABLE '
+ . Util::backquoteCompat(
+ $table_alias,
+ $compat,
+ $sql_backquotes
+ ) . ";";
+ $truncatehead = $this->_possibleCRLF()
+ . $this->_exportComment()
+ . $this->_exportComment(
+ __('Truncate table before insert') . ' '
+ . $formatted_table_name
+ )
+ . $this->_exportComment()
+ . $crlf;
+ $this->export->outputHandler($truncatehead);
+ $this->export->outputHandler($truncate);
+ }
+
+ // scheme for inserting fields
+ if ($GLOBALS['sql_insert_syntax'] == 'complete'
+ || $GLOBALS['sql_insert_syntax'] == 'both'
+ ) {
+ $fields = implode(', ', $field_set);
+ $schema_insert = $sql_command . $insert_delayed . ' INTO '
+ . Util::backquoteCompat(
+ $table_alias,
+ $compat,
+ $sql_backquotes
+ )
+ // avoid EOL blank
+ . ' (' . $fields . ') VALUES';
+ } else {
+ $schema_insert = $sql_command . $insert_delayed . ' INTO '
+ . Util::backquoteCompat(
+ $table_alias,
+ $compat,
+ $sql_backquotes
+ )
+ . ' VALUES';
+ }
+ }
+
+ //\x08\\x09, not required
+ $current_row = 0;
+ $query_size = 0;
+ if (($GLOBALS['sql_insert_syntax'] == 'extended'
+ || $GLOBALS['sql_insert_syntax'] == 'both')
+ && (! isset($GLOBALS['sql_type'])
+ || $GLOBALS['sql_type'] != 'UPDATE')
+ ) {
+ $separator = ',';
+ $schema_insert .= $crlf;
+ } else {
+ $separator = ';';
+ }
+
+ while ($row = $GLOBALS['dbi']->fetchRow($result)) {
+ if ($current_row == 0) {
+ $head = $this->_possibleCRLF()
+ . $this->_exportComment()
+ . $this->_exportComment(
+ __('Dumping data for table') . ' '
+ . $formatted_table_name
+ )
+ . $this->_exportComment()
+ . $crlf;
+ if (! $this->export->outputHandler($head)) {
+ return false;
+ }
+ }
+ // We need to SET IDENTITY_INSERT ON for MSSQL
+ if (isset($GLOBALS['sql_compatibility'])
+ && $GLOBALS['sql_compatibility'] == 'MSSQL'
+ && $current_row == 0
+ ) {
+ if (! $this->export->outputHandler(
+ 'SET IDENTITY_INSERT '
+ . Util::backquoteCompat(
+ $table_alias,
+ $compat,
+ $sql_backquotes
+ )
+ . ' ON ;' . $crlf
+ )
+ ) {
+ return false;
+ }
+ }
+ $current_row++;
+ $values = [];
+ for ($j = 0; $j < $fields_cnt; $j++) {
+ // NULL
+ if (! isset($row[$j]) || $row[$j] === null) {
+ $values[] = 'NULL';
+ } elseif ($fields_meta[$j]->numeric
+ && $fields_meta[$j]->type != 'timestamp'
+ && ! $fields_meta[$j]->blob
+ ) {
+ // a number
+ // timestamp is numeric on some MySQL 4.1, BLOBs are
+ // sometimes numeric
+ $values[] = $row[$j];
+ } elseif (false !== stripos($field_flags[$j], 'BINARY')
+ && isset($GLOBALS['sql_hex_for_binary'])
+ ) {
+ // a true BLOB
+ // - mysqldump only generates hex data when the --hex-blob
+ // option is used, for fields having the binary attribute
+ // no hex is generated
+ // - a TEXT field returns type blob but a real blob
+ // returns also the 'binary' flag
+
+ // empty blobs need to be different, but '0' is also empty
+ // :-(
+ if (empty($row[$j]) && $row[$j] != '0') {
+ $values[] = '\'\'';
+ } else {
+ $values[] = '0x' . bin2hex($row[$j]);
+ }
+ } elseif ($fields_meta[$j]->type == 'bit') {
+ // detection of 'bit' works only on mysqli extension
+ $values[] = "b'" . $GLOBALS['dbi']->escapeString(
+ Util::printableBitValue(
+ (int) $row[$j],
+ (int) $fields_meta[$j]->length
+ )
+ )
+ . "'";
+ } elseif ($fields_meta[$j]->type === 'geometry') {
+ // export GIS types as hex
+ $values[] = '0x' . bin2hex($row[$j]);
+ } elseif (! empty($GLOBALS['exporting_metadata'])
+ && $row[$j] == '@LAST_PAGE'
+ ) {
+ $values[] = '@LAST_PAGE';
+ } else {
+ // something else -> treat as a string
+ $values[] = '\''
+ . $GLOBALS['dbi']->escapeString($row[$j])
+ . '\'';
+ } // end if
+ } // end for
+
+ // should we make update?
+ if (isset($GLOBALS['sql_type'])
+ && $GLOBALS['sql_type'] == 'UPDATE'
+ ) {
+ $insert_line = $schema_insert;
+ for ($i = 0; $i < $fields_cnt; $i++) {
+ if (0 == $i) {
+ $insert_line .= ' ';
+ }
+ if ($i > 0) {
+ // avoid EOL blank
+ $insert_line .= ',';
+ }
+ $insert_line .= $field_set[$i] . ' = ' . $values[$i];
+ }
+
+ list($tmp_unique_condition, $tmp_clause_is_unique)
+ = Util::getUniqueCondition(
+ $result, // handle
+ $fields_cnt, // fields_cnt
+ $fields_meta, // fields_meta
+ $row, // row
+ false, // force_unique
+ false, // restrict_to_table
+ null // analyzed_sql_results
+ );
+ $insert_line .= ' WHERE ' . $tmp_unique_condition;
+ unset($tmp_unique_condition, $tmp_clause_is_unique);
+ } else {
+ // Extended inserts case
+ if ($GLOBALS['sql_insert_syntax'] == 'extended'
+ || $GLOBALS['sql_insert_syntax'] == 'both'
+ ) {
+ if ($current_row == 1) {
+ $insert_line = $schema_insert . '('
+ . implode(', ', $values) . ')';
+ } else {
+ $insert_line = '(' . implode(', ', $values) . ')';
+ $insertLineSize = mb_strlen($insert_line);
+ $sql_max_size = $GLOBALS['sql_max_query_size'];
+ if (isset($sql_max_size)
+ && $sql_max_size > 0
+ && $query_size + $insertLineSize > $sql_max_size
+ ) {
+ if (! $this->export->outputHandler(';' . $crlf)) {
+ return false;
+ }
+ $query_size = 0;
+ $current_row = 1;
+ $insert_line = $schema_insert . $insert_line;
+ }
+ }
+ $query_size += mb_strlen($insert_line);
+ // Other inserts case
+ } else {
+ $insert_line = $schema_insert
+ . '(' . implode(', ', $values) . ')';
+ }
+ }
+ unset($values);
+
+ if (! $this->export->outputHandler(
+ ($current_row == 1 ? '' : $separator . $crlf)
+ . $insert_line
+ )
+ ) {
+ return false;
+ }
+ } // end while
+
+ if ($current_row > 0) {
+ if (! $this->export->outputHandler(';' . $crlf)) {
+ return false;
+ }
+ }
+
+ // We need to SET IDENTITY_INSERT OFF for MSSQL
+ if (isset($GLOBALS['sql_compatibility'])
+ && $GLOBALS['sql_compatibility'] == 'MSSQL'
+ && $current_row > 0
+ ) {
+ $outputSucceeded = $this->export->outputHandler(
+ $crlf . 'SET IDENTITY_INSERT '
+ . Util::backquoteCompat(
+ $table_alias,
+ $compat,
+ $sql_backquotes
+ )
+ . ' OFF;' . $crlf
+ );
+ if (! $outputSucceeded) {
+ return false;
+ }
+ }
+
+ $GLOBALS['dbi']->freeResult($result);
+
+ return true;
+ } // end of the 'exportData()' function
+
+ /**
+ * Make a create table statement compatible with MSSQL
+ *
+ * @param string $create_query MySQL create table statement
+ *
+ * @return string MSSQL compatible create table statement
+ */
+ private function _makeCreateTableMSSQLCompatible($create_query)
+ {
+ // In MSSQL
+ // 1. No 'IF NOT EXISTS' in CREATE TABLE
+ // 2. DATE field doesn't exists, we will use DATETIME instead
+ // 3. UNSIGNED attribute doesn't exist
+ // 4. No length on INT, TINYINT, SMALLINT, BIGINT and no precision on
+ // FLOAT fields
+ // 5. No KEY and INDEX inside CREATE TABLE
+ // 6. DOUBLE field doesn't exists, we will use FLOAT instead
+
+ $create_query = preg_replace(
+ "/^CREATE TABLE IF NOT EXISTS/",
+ 'CREATE TABLE',
+ $create_query
+ );
+ // first we need to replace all lines ended with '" DATE ...,\n'
+ // last preg_replace preserve us from situation with date text
+ // inside DEFAULT field value
+ $create_query = preg_replace(
+ "/\" date DEFAULT NULL(,)?\n/",
+ '" datetime DEFAULT NULL$1' . "\n",
+ $create_query
+ );
+ $create_query = preg_replace(
+ "/\" date NOT NULL(,)?\n/",
+ '" datetime NOT NULL$1' . "\n",
+ $create_query
+ );
+ $create_query = preg_replace(
+ '/" date NOT NULL DEFAULT \'([^\'])/',
+ '" datetime NOT NULL DEFAULT \'$1',
+ $create_query
+ );
+
+ // next we need to replace all lines ended with ') UNSIGNED ...,'
+ // last preg_replace preserve us from situation with unsigned text
+ // inside DEFAULT field value
+ $create_query = preg_replace(
+ "/\) unsigned NOT NULL(,)?\n/",
+ ') NOT NULL$1' . "\n",
+ $create_query
+ );
+ $create_query = preg_replace(
+ "/\) unsigned DEFAULT NULL(,)?\n/",
+ ') DEFAULT NULL$1' . "\n",
+ $create_query
+ );
+ $create_query = preg_replace(
+ '/\) unsigned NOT NULL DEFAULT \'([^\'])/',
+ ') NOT NULL DEFAULT \'$1',
+ $create_query
+ );
+
+ // we need to replace all lines ended with
+ // '" INT|TINYINT([0-9]{1,}) ...,' last preg_replace preserve us
+ // from situation with int([0-9]{1,}) text inside DEFAULT field
+ // value
+ $create_query = preg_replace(
+ '/" (int|tinyint|smallint|bigint)\([0-9]+\) DEFAULT NULL(,)?\n/',
+ '" $1 DEFAULT NULL$2' . "\n",
+ $create_query
+ );
+ $create_query = preg_replace(
+ '/" (int|tinyint|smallint|bigint)\([0-9]+\) NOT NULL(,)?\n/',
+ '" $1 NOT NULL$2' . "\n",
+ $create_query
+ );
+ $create_query = preg_replace(
+ '/" (int|tinyint|smallint|bigint)\([0-9]+\) NOT NULL DEFAULT \'([^\'])/',
+ '" $1 NOT NULL DEFAULT \'$2',
+ $create_query
+ );
+
+ // we need to replace all lines ended with
+ // '" FLOAT|DOUBLE([0-9,]{1,}) ...,'
+ // last preg_replace preserve us from situation with
+ // float([0-9,]{1,}) text inside DEFAULT field value
+ $create_query = preg_replace(
+ '/" (float|double)(\([0-9]+,[0-9,]+\))? DEFAULT NULL(,)?\n/',
+ '" float DEFAULT NULL$3' . "\n",
+ $create_query
+ );
+ $create_query = preg_replace(
+ '/" (float|double)(\([0-9,]+,[0-9,]+\))? NOT NULL(,)?\n/',
+ '" float NOT NULL$3' . "\n",
+ $create_query
+ );
+ return preg_replace(
+ '/" (float|double)(\([0-9,]+,[0-9,]+\))? NOT NULL DEFAULT \'([^\'])/',
+ '" float NOT NULL DEFAULT \'$3',
+ $create_query
+ );
+
+ // @todo remove indexes from CREATE TABLE
+ }
+
+ /**
+ * replaces db/table/column names with their aliases
+ *
+ * @param string $sql_query SQL query in which aliases are to be substituted
+ * @param array $aliases Alias information for db/table/column
+ * @param string $db the database name
+ * @param string $table the tablename
+ * @param string $flag the flag denoting whether any replacement was done
+ *
+ * @return string query replaced with aliases
+ */
+ public function replaceWithAliases(
+ $sql_query,
+ array $aliases,
+ $db,
+ $table = '',
+ &$flag = null
+ ) {
+ $flag = false;
+
+ /**
+ * The parser of this query.
+ *
+ * @var Parser $parser
+ */
+ $parser = new Parser($sql_query);
+
+ if (empty($parser->statements[0])) {
+ return $sql_query;
+ }
+
+ /**
+ * The statement that represents the query.
+ *
+ * @var CreateStatement $statement
+ */
+ $statement = $parser->statements[0];
+
+ /**
+ * Old database name.
+ *
+ * @var string $old_database
+ */
+ $old_database = $db;
+
+ // Replacing aliases in `CREATE TABLE` statement.
+ if ($statement->options->has('TABLE')) {
+ // Extracting the name of the old database and table from the
+ // statement to make sure the parameters are corect.
+ if (! empty($statement->name->database)) {
+ $old_database = $statement->name->database;
+ }
+
+ /**
+ * Old table name.
+ *
+ * @var string $old_table
+ */
+ $old_table = $statement->name->table;
+
+ // Finding the aliased database name.
+ // The database might be empty so we have to add a few checks.
+ $new_database = null;
+ if (! empty($statement->name->database)) {
+ $new_database = $statement->name->database;
+ if (! empty($aliases[$old_database]['alias'])) {
+ $new_database = $aliases[$old_database]['alias'];
+ }
+ }
+
+ // Finding the aliases table name.
+ $new_table = $old_table;
+ if (! empty($aliases[$old_database]['tables'][$old_table]['alias'])) {
+ $new_table = $aliases[$old_database]['tables'][$old_table]['alias'];
+ }
+
+ // Replacing new values.
+ if (($statement->name->database !== $new_database)
+ || ($statement->name->table !== $new_table)
+ ) {
+ $statement->name->database = $new_database;
+ $statement->name->table = $new_table;
+ $statement->name->expr = null; // Force rebuild.
+ $flag = true;
+ }
+
+ /** @var CreateDefinition $field */
+ foreach ($statement->fields as $field) {
+ // Column name.
+ if (! empty($field->type)) {
+ if (! empty($aliases[$old_database]['tables'][$old_table]['columns'][$field->name])) {
+ $field->name = $aliases[$old_database]['tables'][$old_table]['columns'][$field->name];
+ $flag = true;
+ }
+ }
+
+ // Key's columns.
+ if (! empty($field->key)) {
+ foreach ($field->key->columns as $key => $column) {
+ if (! empty($aliases[$old_database]['tables'][$old_table]['columns'][$column['name']])) {
+ $field->key->columns[$key]['name'] = $aliases[$old_database]['tables'][$old_table]['columns'][$column['name']];
+ $flag = true;
+ }
+ }
+ }
+
+ // References.
+ if (! empty($field->references)) {
+ $ref_table = $field->references->table->table;
+ // Replacing table.
+ if (! empty($aliases[$old_database]['tables'][$ref_table]['alias'])) {
+ $field->references->table->table
+ = $aliases[$old_database]['tables'][$ref_table]['alias'];
+ $field->references->table->expr = null;
+ $flag = true;
+ }
+ // Replacing column names.
+ foreach ($field->references->columns as $key => $column) {
+ if (! empty($aliases[$old_database]['tables'][$ref_table]['columns'][$column])) {
+ $field->references->columns[$key]
+ = $aliases[$old_database]['tables'][$ref_table]['columns'][$column];
+ $flag = true;
+ }
+ }
+ }
+ }
+ } elseif ($statement->options->has('TRIGGER')) {
+ // Extracting the name of the old database and table from the
+ // statement to make sure the parameters are corect.
+ if (! empty($statement->table->database)) {
+ $old_database = $statement->table->database;
+ }
+
+ /**
+ * Old table name.
+ *
+ * @var string $old_table
+ */
+ $old_table = $statement->table->table;
+
+ if (! empty($aliases[$old_database]['tables'][$old_table]['alias'])) {
+ $statement->table->table
+ = $aliases[$old_database]['tables'][$old_table]['alias'];
+ $statement->table->expr = null; // Force rebuild.
+ $flag = true;
+ }
+ }
+
+ if ($statement->options->has('TRIGGER')
+ || $statement->options->has('PROCEDURE')
+ || $statement->options->has('FUNCTION')
+ || $statement->options->has('VIEW')
+ ) {
+ // Repalcing the body.
+ for ($i = 0, $count = count($statement->body); $i < $count; ++$i) {
+
+ /**
+ * Token parsed at this moment.
+ *
+ * @var Token $token
+ */
+ $token = $statement->body[$i];
+
+ // Replacing only symbols (that are not variables) and unknown
+ // identifiers.
+ if (($token->type === Token::TYPE_SYMBOL)
+ && (! ($token->flags & Token::FLAG_SYMBOL_VARIABLE))
+ || (($token->type === Token::TYPE_KEYWORD)
+ && (! ($token->flags & Token::FLAG_KEYWORD_RESERVED))
+ || ($token->type === Token::TYPE_NONE))
+ ) {
+ $alias = $this->getAlias($aliases, $token->value);
+ if (! empty($alias)) {
+ // Replacing the token.
+ $token->token = Context::escape($alias);
+ $flag = true;
+ }
+ }
+ }
+ }
+
+ return $statement->build();
+ }
+
+ /**
+ * Generate comment
+ *
+ * @param string $crlf Carriage return character
+ * @param string|null $sql_statement SQL statement
+ * @param string $comment1 Comment for dumped table
+ * @param string $comment2 Comment for current table
+ * @param string $table_alias Table alias
+ * @param string $compat Compatibility mode
+ *
+ * @return string
+ */
+ protected function generateComment(
+ $crlf,
+ ?string $sql_statement,
+ $comment1,
+ $comment2,
+ $table_alias,
+ $compat
+ ) {
+ if (! isset($sql_statement)) {
+ if (isset($GLOBALS['no_constraints_comments'])) {
+ $sql_statement = '';
+ } else {
+ $sql_statement = $crlf
+ . $this->_exportComment()
+ . $this->_exportComment($comment1)
+ . $this->_exportComment();
+ }
+ }
+
+ // comments for current table
+ if (! isset($GLOBALS['no_constraints_comments'])) {
+ $sql_statement .= $crlf
+ . $this->_exportComment()
+ . $this->_exportComment(
+ $comment2 . ' ' . Util::backquoteCompat(
+ $table_alias,
+ $compat,
+ isset($GLOBALS['sql_backquotes'])
+ )
+ )
+ . $this->_exportComment();
+ }
+
+ return $sql_statement;
+ }
+}
diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportTexytext.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportTexytext.php
new file mode 100644
index 0000000..a2fdec8
--- /dev/null
+++ b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportTexytext.php
@@ -0,0 +1,624 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * Export to Texy! text.
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage Texy!text
+ */
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Plugins\Export;
+
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\Export;
+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\Relation;
+use PhpMyAdmin\Transformations;
+use PhpMyAdmin\Util;
+
+/**
+ * Handles the export for the Texy! text class
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage Texy!text
+ */
+class ExportTexytext extends ExportPlugin
+{
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setProperties();
+ }
+
+ /**
+ * Sets the export Texy! text properties
+ *
+ * @return void
+ */
+ protected function setProperties()
+ {
+ $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);
+ $this->properties = $exportPluginProperties;
+ }
+
+ /**
+ * Outputs export header
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportHeader()
+ {
+ return true;
+ }
+
+ /**
+ * Outputs export footer
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportFooter()
+ {
+ return true;
+ }
+
+ /**
+ * Outputs database header
+ *
+ * @param string $db Database name
+ * @param string $db_alias Alias of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBHeader($db, $db_alias = '')
+ {
+ if (empty($db_alias)) {
+ $db_alias = $db;
+ }
+
+ return $this->export->outputHandler(
+ '===' . __('Database') . ' ' . $db_alias . "\n\n"
+ );
+ }
+
+ /**
+ * Outputs database footer
+ *
+ * @param string $db Database name
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBFooter($db)
+ {
+ return true;
+ }
+
+ /**
+ * Outputs CREATE DATABASE statement
+ *
+ * @param string $db Database name
+ * @param string $export_type 'server', 'database', 'table'
+ * @param string $db_alias Aliases of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBCreate($db, $export_type, $db_alias = '')
+ {
+ 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 $error_url the url to go back in case of error
+ * @param string $sql_query SQL query for obtaining data
+ * @param array $aliases Aliases of db/table/columns
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportData(
+ $db,
+ $table,
+ $crlf,
+ $error_url,
+ $sql_query,
+ array $aliases = []
+ ) {
+ global $what;
+
+ $db_alias = $db;
+ $table_alias = $table;
+ $this->initAlias($aliases, $db_alias, $table_alias);
+
+ if (! $this->export->outputHandler(
+ '== ' . __('Dumping data for table') . ' ' . $table_alias . "\n\n"
+ )
+ ) {
+ return false;
+ }
+
+ // Gets the data from the database
+ $result = $GLOBALS['dbi']->query(
+ $sql_query,
+ DatabaseInterface::CONNECT_USER,
+ DatabaseInterface::QUERY_UNBUFFERED
+ );
+ $fields_cnt = $GLOBALS['dbi']->numFields($result);
+
+ // If required, get fields name at the first line
+ if (isset($GLOBALS[$what . '_columns'])) {
+ $text_output = "|------\n";
+ for ($i = 0; $i < $fields_cnt; $i++) {
+ $col_as = $GLOBALS['dbi']->fieldName($result, $i);
+ if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) {
+ $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as];
+ }
+ $text_output .= '|'
+ . htmlspecialchars(stripslashes($col_as));
+ } // end for
+ $text_output .= "\n|------\n";
+ if (! $this->export->outputHandler($text_output)) {
+ return false;
+ }
+ } // end if
+
+ // Format the data
+ while ($row = $GLOBALS['dbi']->fetchRow($result)) {
+ $text_output = '';
+ for ($j = 0; $j < $fields_cnt; $j++) {
+ if (! isset($row[$j]) || $row[$j] === null) {
+ $value = $GLOBALS[$what . '_null'];
+ } elseif ($row[$j] == '0' || $row[$j] != '') {
+ $value = $row[$j];
+ } else {
+ $value = ' ';
+ }
+ $text_output .= '|'
+ . str_replace(
+ '|',
+ '&#124;',
+ htmlspecialchars($value)
+ );
+ } // end for
+ $text_output .= "\n";
+ if (! $this->export->outputHandler($text_output)) {
+ return false;
+ }
+ } // end while
+ $GLOBALS['dbi']->freeResult($result);
+
+ return true;
+ }
+
+ /**
+ * 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 = [])
+ {
+ $text_output = '';
+
+ /**
+ * Get the unique keys in the table
+ */
+ $unique_keys = [];
+ $keys = $GLOBALS['dbi']->getTableIndexes($db, $view);
+ foreach ($keys as $key) {
+ if ($key['Non_unique'] == 0) {
+ $unique_keys[] = $key['Column_name'];
+ }
+ }
+
+ /**
+ * Gets fields properties
+ */
+ $GLOBALS['dbi']->selectDb($db);
+
+ /**
+ * Displays the table structure
+ */
+
+ $text_output .= "|------\n"
+ . '|' . __('Column')
+ . '|' . __('Type')
+ . '|' . __('Null')
+ . '|' . __('Default')
+ . "\n|------\n";
+
+ $columns = $GLOBALS['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";
+ } // end foreach
+
+ 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.php 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 $cfgRelation;
+
+ $text_output = '';
+
+ /**
+ * Get the unique keys in the table
+ */
+ $unique_keys = [];
+ $keys = $GLOBALS['dbi']->getTableIndexes($db, $table);
+ foreach ($keys as $key) {
+ if ($key['Non_unique'] == 0) {
+ $unique_keys[] = $key['Column_name'];
+ }
+ }
+
+ /**
+ * Gets fields properties
+ */
+ $GLOBALS['dbi']->selectDb($db);
+
+ // Check if we can use Relations
+ list($res_rel, $have_rel) = $this->relation->getRelationsAndStatus(
+ $do_relation && ! empty($cfgRelation['relation']),
+ $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 && $cfgRelation['mimework']) {
+ $text_output .= '|' . __('Media (MIME) type');
+ $mime_map = $this->transformations->getMime($db, $table, true);
+ }
+ $text_output .= "\n|------\n";
+
+ $columns = $GLOBALS['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 && $cfgRelation['commwork']) {
+ $text_output .= '|'
+ . (isset($comments[$field_name])
+ ? htmlspecialchars($comments[$field_name])
+ : '');
+ }
+ if ($do_mime && $cfgRelation['mimework']) {
+ $text_output .= '|'
+ . (isset($mime_map[$field_name])
+ ? htmlspecialchars(
+ str_replace('_', '/', $mime_map[$field_name]['mimetype'])
+ )
+ : '');
+ }
+
+ $text_output .= "\n";
+ } // end foreach
+
+ return $text_output;
+ } // end of the '$this->getTableDef()' function
+
+ /**
+ * Outputs triggers
+ *
+ * @param string $db database name
+ * @param string $table table name
+ *
+ * @return string Formatted triggers list
+ */
+ public function getTriggers($db, $table)
+ {
+ $dump = "|------\n";
+ $dump .= '|' . __('Name');
+ $dump .= '|' . __('Time');
+ $dump .= '|' . __('Event');
+ $dump .= '|' . __('Definition');
+ $dump .= "\n|------\n";
+
+ $triggers = $GLOBALS['dbi']->getTriggers($db, $table);
+
+ foreach ($triggers as $trigger) {
+ $dump .= '|' . $trigger['name'];
+ $dump .= '|' . $trigger['action_timing'];
+ $dump .= '|' . $trigger['event_manipulation'];
+ $dump .= '|' .
+ str_replace(
+ '|',
+ '&#124;',
+ 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 $error_url the url to go back in case of error
+ * @param string $export_mode 'create_table', 'triggers', 'create_view',
+ * 'stand_in'
+ * @param string $export_type '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.php 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
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportStructure(
+ $db,
+ $table,
+ $crlf,
+ $error_url,
+ $export_mode,
+ $export_type,
+ $do_relation = false,
+ $do_comments = false,
+ $do_mime = false,
+ $dates = false,
+ array $aliases = []
+ ) {
+ $db_alias = $db;
+ $table_alias = $table;
+ $this->initAlias($aliases, $db_alias, $table_alias);
+ $dump = '';
+
+ switch ($export_mode) {
+ case 'create_table':
+ $dump .= '== ' . __('Table structure for table') . ' '
+ . $table_alias . "\n\n";
+ $dump .= $this->getTableDef(
+ $db,
+ $table,
+ $crlf,
+ $error_url,
+ $do_relation,
+ $do_comments,
+ $do_mime,
+ $dates,
+ true,
+ false,
+ $aliases
+ );
+ break;
+ case 'triggers':
+ $dump = '';
+ $triggers = $GLOBALS['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,
+ $error_url,
+ $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);
+ } // end switch
+
+ 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 = '&nbsp;';
+ }
+
+ 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(
+ isset($column['Default']) ? $column['Default'] : ''
+ );
+
+ return $definition;
+ }
+}
diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportXml.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportXml.php
new file mode 100644
index 0000000..db85add
--- /dev/null
+++ b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportXml.php
@@ -0,0 +1,593 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * Set of functions used to build XML dumps of tables
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage XML
+ */
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Plugins\Export;
+
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\Export;
+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;
+
+/* Can't do server export */
+if (! isset($GLOBALS['db']) || strlen($GLOBALS['db']) === 0) {
+ $GLOBALS['skip_import'] = true;
+ return;
+}
+
+/**
+ * Handles the export for the XML class
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage XML
+ */
+class ExportXml extends ExportPlugin
+{
+ /**
+ * Table name
+ *
+ * @var string
+ */
+ private $_table;
+ /**
+ * Table names
+ *
+ * @var array
+ */
+ private $_tables;
+
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setProperties();
+ }
+
+ /**
+ * Initialize the local variables that are used for export XML
+ *
+ * @return void
+ */
+ protected function initSpecificVariables()
+ {
+ global $table, $tables;
+ $this->_setTable($table);
+ if (is_array($tables)) {
+ $this->_setTables($tables);
+ }
+ }
+
+ /**
+ * Sets the export XML properties
+ *
+ * @return void
+ */
+ protected function setProperties()
+ {
+ // 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);
+ $this->properties = $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 qieries
+ *
+ * @return string XML with definitions
+ */
+ private function _exportRoutines($db, $type, $dbitype)
+ {
+ // Export routines
+ $routines = $GLOBALS['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 qieries
+ * @param array $names Names of items to export
+ *
+ * @return string XML with definitions
+ */
+ private function _exportDefinitions($db, $type, $dbitype, array $names)
+ {
+ global $crlf;
+
+ $head = '';
+
+ if ($names) {
+ foreach ($names as $name) {
+ $head .= ' <pma:' . $type . ' name="'
+ . htmlspecialchars($name) . '">' . $crlf;
+
+ // Do some formatting
+ $sql = $GLOBALS['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.
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportHeader()
+ {
+ $this->initSpecificVariables();
+ global $crlf, $cfg, $db;
+ $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']) ? true : false;
+
+ 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 ' . PMA_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:') . ' ' . $GLOBALS['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 = $GLOBALS['dbi']->fetchResult(
+ 'SELECT `DEFAULT_CHARACTER_SET_NAME`, `DEFAULT_COLLATION_NAME`'
+ . ' FROM `information_schema`.`SCHEMATA` WHERE `SCHEMA_NAME`'
+ . ' = \'' . $GLOBALS['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 ($tables === null) {
+ $tables = [];
+ }
+
+ if (count($tables) === 0) {
+ $tables[] = $table;
+ }
+
+ foreach ($tables as $table) {
+ // Export tables and views
+ $result = $GLOBALS['dbi']->fetchResult(
+ 'SHOW CREATE TABLE ' . Util::backquote($db) . '.'
+ . Util::backquote($table),
+ 0
+ );
+ $tbl = $result[$table][1];
+
+ $is_view = $GLOBALS['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']
+ ) {
+ // Export triggers
+ $triggers = $GLOBALS['dbi']->getTriggers($db, $table);
+ if ($triggers) {
+ 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);
+ unset($triggers);
+ }
+ }
+ }
+
+ if (isset($GLOBALS['xml_export_functions'])
+ && $GLOBALS['xml_export_functions']
+ ) {
+ $head .= $this->_exportRoutines($db, 'function', 'FUNCTION');
+ }
+
+ if (isset($GLOBALS['xml_export_procedures'])
+ && $GLOBALS['xml_export_procedures']
+ ) {
+ $head .= $this->_exportRoutines($db, 'procedure', 'PROCEDURE');
+ }
+
+ if (isset($GLOBALS['xml_export_events'])
+ && $GLOBALS['xml_export_events']
+ ) {
+ // Export events
+ $events = $GLOBALS['dbi']->fetchResult(
+ "SELECT EVENT_NAME FROM information_schema.EVENTS "
+ . "WHERE EVENT_SCHEMA='" . $GLOBALS['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
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportFooter()
+ {
+ $foot = '</pma_xml_export>';
+
+ return $this->export->outputHandler($foot);
+ }
+
+ /**
+ * Outputs database header
+ *
+ * @param string $db Database name
+ * @param string $db_alias Aliases of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBHeader($db, $db_alias = '')
+ {
+ global $crlf;
+
+ if (empty($db_alias)) {
+ $db_alias = $db;
+ }
+ if (isset($GLOBALS['xml_export_contents'])
+ && $GLOBALS['xml_export_contents']
+ ) {
+ $head = ' <!--' . $crlf
+ . ' - ' . __('Database:') . ' \''
+ . htmlspecialchars($db_alias) . '\'' . $crlf
+ . ' -->' . $crlf . ' <database name="'
+ . htmlspecialchars($db_alias) . '">' . $crlf;
+
+ return $this->export->outputHandler($head);
+ }
+
+ return true;
+ }
+
+ /**
+ * Outputs database footer
+ *
+ * @param string $db Database name
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBFooter($db)
+ {
+ 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 $export_type 'server', 'database', 'table'
+ * @param string $db_alias Aliases of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBCreate($db, $export_type, $db_alias = '')
+ {
+ 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 $error_url the url to go back in case of error
+ * @param string $sql_query SQL query for obtaining data
+ * @param array $aliases Aliases of db/table/columns
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportData(
+ $db,
+ $table,
+ $crlf,
+ $error_url,
+ $sql_query,
+ array $aliases = []
+ ) {
+ // Do not export data for merge tables
+ if ($GLOBALS['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 = $GLOBALS['dbi']->query(
+ $sql_query,
+ DatabaseInterface::CONNECT_USER,
+ DatabaseInterface::QUERY_UNBUFFERED
+ );
+
+ $columns_cnt = $GLOBALS['dbi']->numFields($result);
+ $columns = [];
+ for ($i = 0; $i < $columns_cnt; $i++) {
+ $columns[$i] = stripslashes($GLOBALS['dbi']->fieldName($result, $i));
+ }
+ unset($i);
+
+ $buffer = ' <!-- ' . __('Table') . ' '
+ . htmlspecialchars($table_alias) . ' -->' . $crlf;
+ if (! $this->export->outputHandler($buffer)) {
+ return false;
+ }
+
+ while ($record = $GLOBALS['dbi']->fetchRow($result)) {
+ $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) {
+ $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;
+ }
+ }
+ $GLOBALS['dbi']->freeResult($result);
+ }
+
+ 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
+ *
+ * @return void
+ */
+ private function _setTable($table)
+ {
+ $this->_table = $table;
+ }
+
+ /**
+ * Gets the table names
+ *
+ * @return array
+ */
+ private function _getTables()
+ {
+ return $this->_tables;
+ }
+
+ /**
+ * Sets the table names
+ *
+ * @param array $tables table names
+ *
+ * @return void
+ */
+ private function _setTables(array $tables)
+ {
+ $this->_tables = $tables;
+ }
+}
diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportYaml.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportYaml.php
new file mode 100644
index 0000000..971f9c6
--- /dev/null
+++ b/srcs/phpmyadmin/libraries/classes/Plugins/Export/ExportYaml.php
@@ -0,0 +1,230 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * Set of functions used to build YAML dumps of tables
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage YAML
+ */
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Plugins\Export;
+
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\Export;
+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;
+
+/**
+ * Handles the export for the YAML format
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage YAML
+ */
+class ExportYaml extends ExportPlugin
+{
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setProperties();
+ }
+
+ /**
+ * Sets the export YAML properties
+ *
+ * @return void
+ */
+ protected function setProperties()
+ {
+ $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);
+ $this->properties = $exportPluginProperties;
+ }
+
+ /**
+ * Outputs export header
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportHeader()
+ {
+ $this->export->outputHandler(
+ '%YAML 1.1' . $GLOBALS['crlf'] . '---' . $GLOBALS['crlf']
+ );
+
+ return true;
+ }
+
+ /**
+ * Outputs export footer
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportFooter()
+ {
+ $this->export->outputHandler('...' . $GLOBALS['crlf']);
+
+ return true;
+ }
+
+ /**
+ * Outputs database header
+ *
+ * @param string $db Database name
+ * @param string $db_alias Aliases of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBHeader($db, $db_alias = '')
+ {
+ return true;
+ }
+
+ /**
+ * Outputs database footer
+ *
+ * @param string $db Database name
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBFooter($db)
+ {
+ return true;
+ }
+
+ /**
+ * Outputs CREATE DATABASE statement
+ *
+ * @param string $db Database name
+ * @param string $export_type 'server', 'database', 'table'
+ * @param string $db_alias Aliases of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBCreate($db, $export_type, $db_alias = '')
+ {
+ 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 $error_url the url to go back in case of error
+ * @param string $sql_query SQL query for obtaining data
+ * @param array $aliases Aliases of db/table/columns
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportData(
+ $db,
+ $table,
+ $crlf,
+ $error_url,
+ $sql_query,
+ array $aliases = []
+ ) {
+ $db_alias = $db;
+ $table_alias = $table;
+ $this->initAlias($aliases, $db_alias, $table_alias);
+ $result = $GLOBALS['dbi']->query(
+ $sql_query,
+ DatabaseInterface::CONNECT_USER,
+ DatabaseInterface::QUERY_UNBUFFERED
+ );
+
+ $columns_cnt = $GLOBALS['dbi']->numFields($result);
+ $columns = [];
+ for ($i = 0; $i < $columns_cnt; $i++) {
+ $col_as = $GLOBALS['dbi']->fieldName($result, $i);
+ if (! empty($aliases[$db]['tables'][$table]['columns'][$col_as])) {
+ $col_as = $aliases[$db]['tables'][$table]['columns'][$col_as];
+ }
+ $columns[$i] = stripslashes($col_as);
+ }
+
+ $buffer = '';
+ $record_cnt = 0;
+ while ($record = $GLOBALS['dbi']->fetchRow($result)) {
+ $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 (! isset($record[$i])) {
+ continue;
+ }
+
+ if ($record[$i] === null) {
+ $buffer .= ' ' . $columns[$i] . ': null' . $crlf;
+ continue;
+ }
+
+ if (is_numeric($record[$i])) {
+ $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;
+ }
+ }
+ $GLOBALS['dbi']->freeResult($result);
+
+ return true;
+ } // end getTableYAML
+}
diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/Helpers/Pdf.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/Helpers/Pdf.php
new file mode 100644
index 0000000..58f1b5a
--- /dev/null
+++ b/srcs/phpmyadmin/libraries/classes/Plugins/Export/Helpers/Pdf.php
@@ -0,0 +1,855 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * PhpMyAdmin\Plugins\Export\Helpers\Pdf class
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage PDF
+ */
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Plugins\Export\Helpers;
+
+use PhpMyAdmin\DatabaseInterface;
+use PhpMyAdmin\Pdf as PdfLib;
+use PhpMyAdmin\Relation;
+use PhpMyAdmin\Transformations;
+use PhpMyAdmin\Util;
+use TCPDF_STATIC;
+
+/**
+ * Adapted from a LGPL script by Philip Clarke
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage PDF
+ */
+class Pdf extends PdfLib
+{
+ public $tablewidths;
+ public $headerset;
+
+ private $dataY;
+ private $cellFontSize;
+ private $titleFontSize;
+ private $titleText;
+ private $dbAlias;
+ private $tableAlias;
+ private $purpose;
+ private $colTitles;
+ private $results;
+ private $colAlign;
+ private $titleWidth;
+ private $colFits;
+ private $display_column;
+ private $numFields;
+ private $fields;
+ private $sColWidth;
+ private $currentDb;
+ private $currentTable;
+ 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 boolean $unicode true means that the input text is unicode
+ * @param string $encoding charset encoding; default is UTF-8.
+ * @param boolean $diskcache if true reduce the RAM memory usage by caching
+ * temporary data on filesystem (slower).
+ * @param boolean $pdfa If TRUE set the document to PDF/A mode.
+ *
+ * @access public
+ */
+ public function __construct(
+ $orientation = 'P',
+ $unit = 'mm',
+ $format = 'A4',
+ $unicode = true,
+ $encoding = 'UTF-8',
+ $diskcache = false,
+ $pdfa = false
+ ) {
+ parent::__construct(
+ $orientation,
+ $unit,
+ $format,
+ $unicode,
+ $encoding,
+ $diskcache,
+ $pdfa
+ );
+ $this->relation = new Relation($GLOBALS['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 boolean $addpage if true add a page, otherwise only return
+ * the true/false state
+ *
+ * @return boolean true in case of page break, false otherwise.
+ */
+ public function checkPageBreak($h = 0, $y = '', $addpage = true)
+ {
+ if (TCPDF_STATIC::empty_string($y)) {
+ $y = $this->y;
+ }
+ $current_page = $this->page;
+ if ((($y + $h) > $this->PageBreakTrigger)
+ && (! $this->InFooter)
+ && $this->AcceptPageBreak()
+ ) {
+ if ($addpage) {
+ //Automatic page break
+ $x = $this->x;
+ $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.
+ *
+ * @return void
+ */
+ // @codingStandardsIgnoreLine
+ public function Header()
+ {
+ 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
+ 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',
+ 1
+ );
+ $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;
+ }
+
+ $this->dataY = $maxY;
+ $this->SetAutoPageBreak(true);
+ }
+
+ /**
+ * Generate table
+ *
+ * @param int $lineheight Height of line
+ *
+ * @return void
+ */
+ public function morepagestable($lineheight = 8)
+ {
+ // 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 = $GLOBALS['dbi']->fetchRow($this->results)) {
+ $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;
+ }
+
+ /**
+ * Sets a set of attributes.
+ *
+ * @param array $attr array containing the attributes
+ *
+ * @return void
+ */
+ public function setAttributes(array $attr = [])
+ {
+ foreach ($attr as $key => $val) {
+ $this->$key = $val;
+ }
+ }
+
+ /**
+ * Defines the top margin.
+ * The method can be called before creating the first page.
+ *
+ * @param float $topMargin the margin
+ *
+ * @return void
+ */
+ public function setTopMargin($topMargin)
+ {
+ $this->tMargin = $topMargin;
+ }
+
+ /**
+ * Prints triggers
+ *
+ * @param string $db database name
+ * @param string $table table name
+ *
+ * @return void
+ */
+ public function getTriggers($db, $table)
+ {
+ $triggers = $GLOBALS['dbi']->getTriggers($db, $table);
+ if ([] === $triggers) {
+ return; //prevents printing blank trigger list for any table
+ }
+
+ unset($this->tablewidths);
+ unset($this->colTitles);
+ unset($this->titleWidth);
+ unset($this->colFits);
+ unset($this->display_column);
+ unset($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->display_column[$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],
+ $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) {
+ $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.php 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
+ *
+ * @return void
+ */
+ public function getTableDef(
+ $db,
+ $table,
+ $do_relation,
+ $do_comments,
+ $do_mime,
+ $view = false,
+ array $aliases = []
+ ) {
+ // set $cfgRelation here, because there is a chance that it's modified
+ // since the class initialization
+ global $cfgRelation;
+
+ unset($this->tablewidths);
+ unset($this->colTitles);
+ unset($this->titleWidth);
+ unset($this->colFits);
+ unset($this->display_column);
+ unset($this->colAlign);
+
+ /**
+ * Gets fields properties
+ */
+ $GLOBALS['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;
+ } // end if
+
+ //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->display_column[$columns_cnt] = true;
+ }
+
+ if ($do_relation && $have_rel) {
+ $this->colTitles[$columns_cnt] = __('Links to');
+ $this->display_column[$columns_cnt] = true;
+ $this->colAlign[$columns_cnt] = 'L';
+ $this->tablewidths[$columns_cnt] = 120;
+ $columns_cnt++;
+ }
+ if ($do_comments /*&& $cfgRelation['commwork']*/) {
+ $this->colTitles[$columns_cnt] = __('Comments');
+ $this->display_column[$columns_cnt] = true;
+ $this->colAlign[$columns_cnt] = 'L';
+ $this->tablewidths[$columns_cnt] = 120;
+ $columns_cnt++;
+ }
+ if ($do_mime && $cfgRelation['mimework']) {
+ $this->colTitles[$columns_cnt] = __('Media (MIME) type');
+ $this->display_column[$columns_cnt] = true;
+ $this->colAlign[$columns_cnt] = 'L';
+ $this->tablewidths[$columns_cnt] = 120;
+ $columns_cnt++;
+ }
+
+ // 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 && $cfgRelation['mimework']) {
+ $mime_map = $this->transformations->getMime($db, $table, true);
+ }
+
+ $columns = $GLOBALS['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[] = isset($column['Default']) ? $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[] = isset($comments[$field_name])
+ ? $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],
+ $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) {
+ $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
+ *
+ * @return void
+ */
+ public function mysqlReport($query)
+ {
+ unset($this->tablewidths);
+ unset($this->colTitles);
+ unset($this->titleWidth);
+ unset($this->colFits);
+ unset($this->display_column);
+ unset($this->colAlign);
+
+ /**
+ * Pass 1 for column widths
+ */
+ $this->results = $GLOBALS['dbi']->query(
+ $query,
+ DatabaseInterface::CONNECT_USER,
+ DatabaseInterface::QUERY_UNBUFFERED
+ );
+ $this->numFields = $GLOBALS['dbi']->numFields($this->results);
+ $this->fields = $GLOBALS['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];
+ }
+ $stringWidth = $this->GetStringWidth($col_as) + 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->display_column[$i] = true;
+
+ switch ($this->fields[$i]->type) {
+ case 'int':
+ $this->colAlign[$i] = 'R';
+ break;
+ case 'blob':
+ case 'tinyblob':
+ case 'mediumblob':
+ case 'longblob':
+ /**
+ * @todo do not deactivate completely the display
+ * but show the field's name and [BLOB]
+ */
+ if (false !== stripos($this->fields[$i]->flags, 'BINARY')) {
+ $this->display_column[$i] = false;
+ unset($this->colTitles[$i]);
+ }
+ $this->colAlign[$i] = 'L';
+ break;
+ default:
+ $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 = $GLOBALS['dbi']->fetchRow($this->results)) {
+ foreach ($colFits as $key => $val) {
+ $stringWidth = $this->GetStringWidth($row[$key]) + 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->display_column[$i] == false) {
+ $this->tablewidths[$i] = 0;
+ }
+ }
+
+ ksort($this->tablewidths);
+
+ $GLOBALS['dbi']->freeResult($this->results);
+
+ // Pass 2
+
+ $this->results = $GLOBALS['dbi']->query(
+ $query,
+ DatabaseInterface::CONNECT_USER,
+ DatabaseInterface::QUERY_UNBUFFERED
+ );
+ $this->SetY($this->tMargin);
+ $this->AddPage();
+ $this->SetFont(PdfLib::PMA_PDF_FONT, '', 9);
+ $this->morepagestable($this->FontSizePt);
+ $GLOBALS['dbi']->freeResult($this->results);
+ } // end of mysqlReport function
+} // end of Pdf class
diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/Helpers/TableProperty.php b/srcs/phpmyadmin/libraries/classes/Plugins/Export/Helpers/TableProperty.php
new file mode 100644
index 0000000..8991251
--- /dev/null
+++ b/srcs/phpmyadmin/libraries/classes/Plugins/Export/Helpers/TableProperty.php
@@ -0,0 +1,277 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * Holds the PhpMyAdmin\Plugins\Export\Helpers\TableProperty class
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage CodeGen
+ */
+declare(strict_types=1);
+
+namespace PhpMyAdmin\Plugins\Export\Helpers;
+
+use PhpMyAdmin\Plugins\Export\ExportCodegen;
+
+/**
+ * PhpMyAdmin\Plugins\Export\Helpers\TableProperty class
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage CodeGen
+ */
+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;
+
+ /**
+ * Constructor
+ *
+ * @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 = 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
+ *
+ * @return bool true if the key is primary, false otherwise
+ */
+ 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;
+ }
+}
diff --git a/srcs/phpmyadmin/libraries/classes/Plugins/Export/README b/srcs/phpmyadmin/libraries/classes/Plugins/Export/README
new file mode 100644
index 0000000..5ada85b
--- /dev/null
+++ b/srcs/phpmyadmin/libraries/classes/Plugins/Export/README
@@ -0,0 +1,255 @@
+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
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * [Name] export plugin for phpMyAdmin
+ *
+ * @package PhpMyAdmin-Export
+ * @subpackage [Name]
+ */
+declare(strict_types=1);
+
+/**
+ * Handles the export for the [Name] format
+ *
+ * @package PhpMyAdmin-Export
+ */
+class Export[Name] extends PhpMyAdmin\Plugins\ExportPlugin
+{
+ /**
+ * optional - declare variables and descriptions
+ *
+ * @var type
+ */
+ private $_myOptionalVariable;
+
+ /**
+ * optional - declare global variables and descriptions
+ *
+ * @var type
+ */
+ 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
+ *
+ * @global type $global_variable_name
+ * [..]
+ *
+ * @return void
+ */
+ 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(
+ array(
+ '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 $db_alias Aliases of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBHeader ($db, $db_alias = '')
+ {
+ // 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 $db_alias Aliases of db
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportDBCreate($db, $db_alias = '')
+ {
+ // 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 $error_url the url to go back in case of error
+ * @param string $sql_query SQL query for obtaining data
+ * @param array $aliases Aliases of db/table/columns
+ *
+ * @return bool Whether it succeeded
+ */
+ public function exportData(
+ $db, $table, $crlf, $error_url, $sql_query, $aliases = array()
+ ) {
+ // implementation;
+ return true;
+ }
+
+ // optional - implement other methods defined in PhpMyAdmin\Plugins\ExportPlugin.class.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
+ *
+ * @return type
+ */
+ private function _getMyOptionalVariable()
+ {
+ return $this->_myOptionalVariable;
+ }
+
+ /**
+ * Setter description
+ *
+ * @param type $my_optional_variable description
+ *
+ * @return void
+ */
+ private function _setMyOptionalVariable($my_optional_variable)
+ {
+ $this->_myOptionalVariable = $my_optional_variable;
+ }
+
+ /**
+ * Getter description
+ *
+ * @return type
+ */
+ private function _getGlobalVariableName()
+ {
+ return $this->_globalVariableName;
+ }
+
+ /**
+ * Setter description
+ *
+ * @param type $global_variable_name description
+ *
+ * @return void
+ */
+ private function _setGlobalVariableName($global_variable_name)
+ {
+ $this->_globalVariableName = $global_variable_name;
+ }
+}
+?>