Initial commit

This commit is contained in:
2022-11-21 09:47:28 +01:00
commit 76cec83d26
11652 changed files with 1980467 additions and 0 deletions

View File

@ -0,0 +1,159 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Abstract class for the authentication plugins
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins;
/**
* Provides a common interface that will have to be implemented by all of the
* authentication plugins.
*
* @package PhpMyAdmin
*/
abstract class AuthenticationPlugin
{
/**
* Displays authentication form
*
* @return boolean
*/
abstract public function auth();
/**
* Gets advanced authentication settings
*
* @return boolean
*/
abstract public function authCheck();
/**
* Set the user and password after last checkings if required
*
* @return boolean
*/
abstract public function authSetUser();
/**
* Stores user credentials after successful login.
*
* @return void
*/
public function storeUserCredentials()
{
}
/**
* User is not allowed to login to MySQL -> authentication failed
*
* @return boolean
*/
abstract public function authFails();
/**
* Perform logout
*
* @return void
*/
public function logOut()
{
global $PHP_AUTH_USER, $PHP_AUTH_PW;
/* Obtain redirect URL (before doing logout) */
if (! empty($GLOBALS['cfg']['Server']['LogoutURL'])) {
$redirect_url = $GLOBALS['cfg']['Server']['LogoutURL'];
} else {
$redirect_url = $this->getLoginFormURL();
}
/* Clear credentials */
$PHP_AUTH_USER = '';
$PHP_AUTH_PW = '';
/* delete user's choices that were stored in session */
$_SESSION = array();
if (!defined('TESTSUITE')) {
session_destroy();
}
/* Redirect to login form (or configured URL) */
PMA_sendHeaderLocation($redirect_url);
}
/**
* Returns URL for login form.
*
* @return string
*/
public function getLoginFormURL()
{
return './index.php';
}
/**
* Returns error message for failed authentication.
*
* @return string
*/
public function getErrorMessage()
{
if (!empty($GLOBALS['login_without_password_is_forbidden'])) {
return __(
'Login without a password is forbidden by configuration'
. ' (see AllowNoPassword)'
);
} elseif (!empty($GLOBALS['allowDeny_forbidden'])) {
return __('Access denied!');
} elseif (!empty($GLOBALS['no_activity'])) {
return sprintf(
__('No activity within %s seconds; please log in again.'),
intval($GLOBALS['cfg']['LoginCookieValidity'])
);
} else {
$dbi_error = $GLOBALS['dbi']->getError();
if (!empty($dbi_error)) {
return htmlspecialchars($dbi_error);
} elseif (isset($GLOBALS['errno'])) {
return '#' . $GLOBALS['errno'] . ' '
. __('Cannot log in to the MySQL server');
} else {
return __('Cannot log in to the MySQL server');
}
}
}
/**
* Callback when user changes password.
*
* @param string $password New password to set
*
* @return void
*/
public function handlePasswordChange($password)
{
}
/**
* Store session access time in session.
*
* Tries to workaround PHP 5 session garbage collection which
* looks at the session file's last modified time
*
* @return void
*/
public function setSessionAccessTime()
{
if (isset($_REQUEST['access_time'])) {
// Ensure access_time is in range <0, LoginCookieValidity + 1>
// to avoid excessive extension of validity.
//
// Negative values can cause session expiry extension
// Too big values can cause overflow and lead to same
$_SESSION['last_access_time'] = time() - min(max(0, intval($_REQUEST['access_time'])), $GLOBALS['cfg']['LoginCookieValidity'] + 1);
} else {
$_SESSION['last_access_time'] = time();
}
}
}

View File

@ -0,0 +1,367 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Abstract class for the export plugins
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins;
use PMA\libraries\properties\plugins\ExportPluginProperties;
/**
* Provides a common interface that will have to be implemented by all of the
* export plugins. Some of the plugins will also implement other public
* methods, but those are not declared here, because they are not implemented
* by all export plugins.
*
* @package PhpMyAdmin
*/
abstract class ExportPlugin
{
/**
* PMA\libraries\properties\plugins\ExportPluginProperties object containing
* the specific export plugin type properties
*
* @var \PMA\libraries\properties\plugins\ExportPluginProperties
*/
protected $properties;
/**
* Common methods, must be overwritten by all export plugins
*/
/**
* Outputs export header
*
* @return bool Whether it succeeded
*/
abstract public function exportHeader();
/**
* Outputs export footer
*
* @return bool Whether it succeeded
*/
abstract public function exportFooter();
/**
* Outputs database header
*
* @param string $db Database name
* @param string $db_alias Aliases of db
*
* @return bool Whether it succeeded
*/
abstract public function exportDBHeader($db, $db_alias = '');
/**
* Outputs database footer
*
* @param string $db Database name
*
* @return bool Whether it succeeded
*/
abstract public function exportDBFooter($db);
/**
* 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
*/
abstract public function exportDBCreate($db, $export_type, $db_alias = '');
/**
* Outputs the content of a table
*
* @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
*/
abstract public function exportData(
$db,
$table,
$crlf,
$error_url,
$sql_query,
$aliases = array()
);
/**
* The following methods are used in export.php or in db_operations.php,
* but they are not implemented by all export plugins
*/
/**
* 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, $aliases = array())
{
;
}
/**
* Exports events
*
* @param string $db Database
*
* @return bool Whether it succeeded
*/
public function exportEvents($db)
{
;
}
/**
* 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,
$aliases = array()
) {
;
}
/**
* 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,
$metadataTypes
) {
;
}
/**
* 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 = array())
{
;
}
/**
* Outputs triggers
*
* @param string $db database name
* @param string $table table name
*
* @return string Formatted triggers list
*/
protected function getTriggers($db, $table)
{
;
}
/**
* Initialize the specific variables for each export plugin
*
* @return void
*/
protected function initSpecificVariables()
{
;
}
/* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */
/**
* Gets the export specific format plugin properties
*
* @return ExportPluginProperties
*/
public function getProperties()
{
return $this->properties;
}
/**
* Sets the export plugins properties and is implemented by each export
* plugin
*
* @return void
*/
abstract protected function setProperties();
/**
* The following methods are implemented here so that they
* can be used by all export plugin without overriding it.
* Note: If you are creating a export plugin then don't include
* below methods unless you want to override them.
*/
/**
* Initialize aliases
*
* @param array $aliases Alias information for db/table/column
* @param string &$db the database
* @param string &$table the table
*
* @return void
*/
public function initAlias($aliases, &$db, &$table = null)
{
if (!empty($aliases[$db]['tables'][$table]['alias'])) {
$table = $aliases[$db]['tables'][$table]['alias'];
}
if (!empty($aliases[$db]['alias'])) {
$db = $aliases[$db]['alias'];
}
}
/**
* Search for alias of a identifier.
*
* @param array $aliases Alias information for db/table/column
* @param string $id the identifier to be searched
* @param string $type db/tbl/col or any combination of them
* representing what to be searched
* @param string $db the database in which search is to be done
* @param string $tbl the table in which search is to be done
*
* @return string alias of the identifier if found or ''
*/
public function getAlias($aliases, $id, $type = 'dbtblcol', $db = '', $tbl = '')
{
if (!empty($db) && isset($aliases[$db])) {
$aliases = array(
$db => $aliases[$db],
);
}
// search each database
foreach ($aliases as $db_key => $db) {
// check if id is database and has alias
if (stristr($type, 'db') !== false
&& $db_key === $id
&& !empty($db['alias'])
) {
return $db['alias'];
}
if (empty($db['tables'])) {
continue;
}
if (!empty($tbl) && isset($db['tables'][$tbl])) {
$db['tables'] = array(
$tbl => $db['tables'][$tbl],
);
}
// search each of its tables
foreach ($db['tables'] as $table_key => $table) {
// check if id is table and has alias
if (stristr($type, 'tbl') !== false
&& $table_key === $id
&& !empty($table['alias'])
) {
return $table['alias'];
}
if (empty($table['columns'])) {
continue;
}
// search each of its columns
foreach ($table['columns'] as $col_key => $col) {
// check if id is column
if (stristr($type, 'col') !== false
&& $col_key === $id
&& !empty($col)
) {
return $col;
}
}
}
}
return '';
}
/**
* Gives the relation string and
* also substitutes with alias if required
* in this format:
* [Foreign Table] ([Foreign Field])
*
* @param array $res_rel the foreigners array
* @param string $field_name the field name
* @param string $db the field name
* @param array $aliases Alias information for db/table/column
*
* @return string the Relation string
*/
public function getRelationString(
$res_rel,
$field_name,
$db,
$aliases = array()
) {
$relation = '';
$foreigner = PMA_searchColumnInForeigners($res_rel, $field_name);
if ($foreigner) {
$ftable = $foreigner['foreign_table'];
$ffield = $foreigner['foreign_field'];
if (!empty($aliases[$db]['tables'][$ftable]['columns'][$ffield])) {
$ffield = $aliases[$db]['tables'][$ftable]['columns'][$ffield];
}
if (!empty($aliases[$db]['tables'][$ftable]['alias'])) {
$ftable = $aliases[$db]['tables'][$ftable]['alias'];
}
$relation = $ftable . ' (' . $ffield . ')';
}
return $relation;
}
}

View File

@ -0,0 +1,96 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Abstract class for the I/O transformations plugins
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins;
use PMA\libraries\plugins\TransformationsPlugin;
/**
* Provides a common interface that will have to be implemented
* by all of the Input/Output transformations plugins.
*
* @package PhpMyAdmin
*/
abstract class IOTransformationsPlugin extends TransformationsPlugin
{
// specifies whether transformation was successful or not
protected $success = true;
// to store the error message in case of failed transformations
protected $error = '';
/**
* Returns the html for input field to override default textarea.
* Note: Return empty string if default textarea is required.
*
* @param array $column column details
* @param int $row_id row number
* @param string $column_name_appendix the name attribute
* @param array $options transformation options
* @param string $value Current field value
* @param string $text_dir text direction
* @param int $tabindex tab index
* @param int $tabindex_for_value offset for the values tabindex
* @param int $idindex id index
*
* @return string the html for input field
*/
public function getInputHtml(
$column,
$row_id,
$column_name_appendix,
$options,
$value,
$text_dir,
$tabindex,
$tabindex_for_value,
$idindex
) {
return '';
}
/**
* Returns the array of scripts (filename) required for plugin
* initialization and handling
*
* @return array javascripts to be included
*/
public function getScripts()
{
return array();
}
/**
* Returns the error message
*
* @return string error
*/
public function getError()
{
return $this->error;
}
/**
* Returns the success status
*
* @return bool
*/
public function isSuccess()
{
return $this->success;
}
/**
* Resets the object properties
*
* @return void
*/
public function reset()
{
$this->success = true;
$this->error = '';
}
}

View File

@ -0,0 +1,76 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Abstract class for the import plugins
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins;
use PMA\libraries\properties\plugins\ImportPluginProperties;
/**
* Provides a common interface that will have to be implemented by all of the
* import plugins.
*
* @package PhpMyAdmin
*/
abstract class ImportPlugin
{
/**
* ImportPluginProperties object containing the import plugin properties
*
* @var ImportPluginProperties
*/
protected $properties;
/**
* Handles the whole import logic
*
* @return void
*/
abstract public function doImport();
/* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */
/**
* Gets the import specific format plugin properties
*
* @return \PMA\libraries\properties\plugins\ImportPluginProperties
*/
public function getProperties()
{
return $this->properties;
}
/**
* Sets the export plugins properties and is implemented by each import
* plugin
*
* @return void
*/
abstract protected function setProperties();
/**
* Define DB name and options
*
* @param string $currentDb DB
* @param string $defaultDb Default DB name
*
* @return array DB name and options (an associative array of options)
*/
protected function getDbnameAndOptions($currentDb, $defaultDb)
{
if (mb_strlen($currentDb)) {
$db_name = $currentDb;
$options = array('create_db' => false);
} else {
$db_name = $defaultDb;
$options = null;
}
return array($db_name, $options);
}
}

View File

@ -0,0 +1,89 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Abstract class for the schema export plugins
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins;
use PMA\libraries\properties\options\items\BoolPropertyItem;
use PMA\libraries\properties\options\groups\OptionsPropertyMainGroup;
use PMA\libraries\properties\plugins\SchemaPluginProperties;
/**
* Provides a common interface that will have to be implemented by all of the
* schema export plugins. Some of the plugins will also implement other public
* methods, but those are not declared here, because they are not implemented
* by all export plugins.
*
* @package PhpMyAdmin
*/
abstract class SchemaPlugin
{
/**
* PMA\libraries\properties\plugins\SchemaPluginProperties object containing
* the specific schema export plugin type properties
*
* @var SchemaPluginProperties
*/
protected $properties;
/**
* Gets the export specific format plugin properties
*
* @return SchemaPluginProperties
*/
public function getProperties()
{
return $this->properties;
}
/**
* Sets the export plugins properties and is implemented by
* each schema export plugin
*
* @return void
*/
protected abstract function setProperties();
/**
* Exports the schema into the specified format.
*
* @param string $db database name
*
* @return bool Whether it succeeded
*/
public abstract function exportSchema($db);
/**
* Adds export options common to all plugins.
*
* @param \PMA\libraries\properties\options\groups\OptionsPropertyMainGroup $propertyGroup property group
*
* @return void
*/
protected function addCommonOptions(OptionsPropertyMainGroup $propertyGroup)
{
$leaf = new BoolPropertyItem('show_color', __('Show color'));
$propertyGroup->addProperty($leaf);
$leaf = new BoolPropertyItem('show_keys', __('Only show keys'));
$propertyGroup->addProperty($leaf);
}
/**
* Returns the array of paper sizes
*
* @return array array of paper sizes
*/
protected function getPaperSizeArray()
{
$ret = array();
foreach ($GLOBALS['cfg']['PDFPageSizes'] as $val) {
$ret[$val] = $val;
}
return $ret;
}
}

View File

@ -0,0 +1,46 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Interface for the transformations plugins
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins;
/**
* Provides a common interface that will have to be implemented by all of the
* transformations plugins.
*
* @package PhpMyAdmin
*/
interface TransformationsInterface
{
/**
* Gets the transformation description
*
* @return string
*/
public static function getInfo();
/**
* Gets the specific MIME type
*
* @return string
*/
public static function getMIMEType();
/**
* Gets the specific MIME subtype
*
* @return string
*/
public static function getMIMESubtype();
/**
* Gets the transformation name of the specific plugin
*
* @return string
*/
public static function getName();
}

View File

@ -0,0 +1,66 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Abstract class for the transformations plugins
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins;
/**
* Provides a common interface that will have to
* be implemented by all of the transformations plugins.
*
* @package PhpMyAdmin
*/
abstract class TransformationsPlugin implements TransformationsInterface
{
/**
* Does the actual work of each specific transformations plugin.
*
* @param array $options transformation options
*
* @return void
*/
public function applyTransformationNoWrap($options = array())
{
;
}
/**
* Does the actual work of each specific transformations plugin.
*
* @param string $buffer text to be transformed
* @param array $options transformation options
* @param string $meta meta information
*
* @return string the transformed text
*/
abstract public function applyTransformation(
$buffer,
$options = array(),
$meta = ''
);
/**
* Returns passed options or default values if they were not set
*
* @param string[] $options List of passed options
* @param string[] $defaults List of default values
*
* @return string[] List of options possibly filled in by defaults.
*/
public function getOptions($options, $defaults)
{
$result = array();
foreach ($defaults as $key => $value) {
if (isset($options[$key]) && $options[$key] !== '') {
$result[$key] = $options[$key];
} else {
$result[$key] = $value;
}
}
return $result;
}
}

View File

@ -0,0 +1,33 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Interface for the import->upload plugins
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins;
/**
* Provides a common interface that will have to implemented by all of the
* import->upload plugins.
*
* @package PhpMyAdmin
*/
interface UploadInterface
{
/**
* Gets the specific upload ID Key
*
* @return string ID Key
*/
public static function getIdKey();
/**
* Returns upload status.
*
* @param string $id upload id
*
* @return array|null
*/
public static function getUploadStatus($id);
}

View File

@ -0,0 +1,176 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Config Authentication plugin for phpMyAdmin
*
* @package PhpMyAdmin-Authentication
* @subpackage Config
*/
namespace PMA\libraries\plugins\auth;
use PMA\libraries\plugins\AuthenticationPlugin;
use PMA;
/**
* Handles the config authentication method
*
* @package PhpMyAdmin-Authentication
*/
class AuthenticationConfig extends AuthenticationPlugin
{
/**
* Displays authentication form
*
* @return boolean always true
*/
public function auth()
{
$response = PMA\libraries\Response::getInstance();
if ($response->isAjax()) {
$response->setRequestStatus(false);
// reload_flag removes the token parameter from the URL and reloads
$response->addJSON('reload_flag', '1');
if (defined('TESTSUITE')) {
return true;
} else {
exit;
}
}
return true;
}
/**
* Gets advanced authentication settings
*
* @return boolean always true
*/
public function authCheck()
{
if ($GLOBALS['token_provided'] && $GLOBALS['token_mismatch']) {
return false;
}
return true;
}
/**
* Set the user and password after last checkings if required
*
* @return boolean always true
*/
public function authSetUser()
{
$this->setSessionAccessTime();
return true;
}
/**
* User is not allowed to login to MySQL -> authentication failed
*
* @return boolean always true (no return indeed)
*/
public function authFails()
{
$conn_error = $GLOBALS['dbi']->getError();
if (!$conn_error) {
$conn_error = __('Cannot connect: invalid settings.');
}
/* HTML header */
$response = PMA\libraries\Response::getInstance();
$response->getFooter()
->setMinimal();
$header = $response->getHeader();
$header->setBodyId('loginform');
$header->setTitle(__('Access denied!'));
$header->disableMenuAndConsole();
echo '<br /><br />
<center>
<h1>';
echo sprintf(__('Welcome to %s'), ' phpMyAdmin ');
echo '</h1>
</center>
<br />
<table cellpadding="0" cellspacing="3" style="margin: 0 auto" width="80%">
<tr>
<td>';
if (isset($GLOBALS['allowDeny_forbidden'])
&& $GLOBALS['allowDeny_forbidden']
) {
trigger_error(__('Access denied!'), E_USER_NOTICE);
} else {
// Check whether user has configured something
if ($GLOBALS['PMA_Config']->source_mtime == 0) {
echo '<p>' , sprintf(
__(
'You probably did not create a configuration file.'
. ' You might want to use the %1$ssetup script%2$s to'
. ' create one.'
),
'<a href="setup/">',
'</a>'
) , '</p>' , "\n";
} elseif (!isset($GLOBALS['errno'])
|| (isset($GLOBALS['errno']) && $GLOBALS['errno'] != 2002)
&& $GLOBALS['errno'] != 2003
) {
// if we display the "Server not responding" error, do not confuse
// users by telling them they have a settings problem
// (note: it's true that they could have a badly typed host name,
// but anyway the current message tells that the server
// rejected the connection, which is not really what happened)
// 2002 is the error given by mysqli
// 2003 is the error given by mysql
trigger_error(
__(
'phpMyAdmin tried to connect to the MySQL server, and the'
. ' server rejected the connection. You should check the'
. ' host, username and password in your configuration and'
. ' make sure that they correspond to the information given'
. ' by the administrator of the MySQL server.'
),
E_USER_WARNING
);
}
echo PMA\libraries\Util::mysqlDie(
$conn_error,
'',
true,
'',
false
);
}
$GLOBALS['error_handler']->dispUserErrors();
echo '</td>
</tr>
<tr>
<td>' , "\n";
echo '<a href="'
, PMA\libraries\Util::getScriptNameForOption(
$GLOBALS['cfg']['DefaultTabServer'],
'server'
)
, PMA_URL_getCommon(array()) , '" class="button disableAjax">'
, __('Retry to connect')
, '</a>' , "\n";
echo '</td>
</tr>' , "\n";
if (count($GLOBALS['cfg']['Servers']) > 1) {
// offer a chance to login to other servers if the current one failed
include_once './libraries/select_server.lib.php';
echo '<tr>' , "\n";
echo ' <td>' , "\n";
echo PMA_selectServer(true, true);
echo ' </td>' , "\n";
echo '</tr>' , "\n";
}
echo '</table>' , "\n";
if (!defined('TESTSUITE')) {
exit;
}
return true;
}
}

View File

@ -0,0 +1,867 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Cookie Authentication plugin for phpMyAdmin
*
* @package PhpMyAdmin-Authentication
* @subpackage Cookie
*/
namespace PMA\libraries\plugins\auth;
use phpseclib\Crypt;
use PMA\libraries\Message;
use PMA\libraries\plugins\AuthenticationPlugin;
use PMA\libraries\Response;
use PMA\libraries\Util;
use ReCaptcha\ReCaptcha;
require_once './libraries/session.lib.php';
/**
* Remember where to redirect the user
* in case of an expired session.
*/
if (! empty($_REQUEST['target'])) {
$GLOBALS['target'] = $_REQUEST['target'];
} else if (PMA_getenv('SCRIPT_NAME')) {
$GLOBALS['target'] = basename(PMA_getenv('SCRIPT_NAME'));
}
/**
* Handles the cookie authentication method
*
* @package PhpMyAdmin-Authentication
*/
class AuthenticationCookie extends AuthenticationPlugin
{
/**
* IV for encryption
*/
private $_cookie_iv = null;
/**
* Displays authentication form
*
* this function MUST exit/quit the application
*
* @global string $conn_error the last connection error
*
* @return boolean|void
*/
public function auth()
{
global $conn_error;
$response = Response::getInstance();
if ($response->isAjax()) {
$response->setRequestStatus(false);
// redirect_flag redirects to the login page
$response->addJSON('redirect_flag', '1');
if (defined('TESTSUITE')) {
return true;
} else {
exit;
}
}
// No recall if blowfish secret is not configured as it would produce
// garbage
if ($GLOBALS['cfg']['LoginCookieRecall']
&& ! empty($GLOBALS['cfg']['blowfish_secret'])
) {
$default_user = $GLOBALS['PHP_AUTH_USER'];
$default_server = $GLOBALS['pma_auth_server'];
$autocomplete = '';
} else {
$default_user = '';
$default_server = '';
// skip the IE autocomplete feature.
$autocomplete = ' autocomplete="off"';
}
$response->getFooter()->setMinimal();
$header = $response->getHeader();
$header->setBodyId('loginform');
$header->setTitle('phpMyAdmin');
$header->disableMenuAndConsole();
$header->disableWarnings();
if (@file_exists(CUSTOM_HEADER_FILE)) {
include CUSTOM_HEADER_FILE;
}
echo '
<div class="container">
<a href="';
echo PMA_linkURL('https://www.phpmyadmin.net/');
echo '" target="_blank" rel="noopener noreferrer" class="logo">';
$logo_image = $GLOBALS['pmaThemeImage'] . 'logo_right.png';
if (@file_exists($logo_image)) {
echo '<img src="' , $logo_image
, '" id="imLogo" name="imLogo" alt="phpMyAdmin" border="0" />';
} else {
echo '<img name="imLogo" id="imLogo" src="'
, $GLOBALS['pmaThemeImage'] , 'pma_logo.png' , '" '
, 'border="0" width="88" height="31" alt="phpMyAdmin" />';
}
echo '</a>
<h1>';
echo sprintf(
__('Welcome to %s'),
'<bdo dir="ltr" lang="en">phpMyAdmin</bdo>'
);
echo "</h1>";
// Show error message
if (! empty($conn_error)) {
Message::rawError($conn_error)->display();
} elseif (isset($_GET['session_expired'])
&& intval($_GET['session_expired']) == 1
) {
Message::rawError(
__('Your session has expired. Please log in again.')
)->display();
}
echo "<noscript>\n";
Message::error(
__("Javascript must be enabled past this point!")
)->display();
echo "</noscript>\n";
echo "<div class='hide js-show'>";
// Displays the languages form
if (empty($GLOBALS['cfg']['Lang'])) {
include_once './libraries/display_select_lang.lib.php';
// use fieldset, don't show doc link
echo PMA_getLanguageSelectorHtml(true, false);
}
echo '</div>
<br />
<!-- Login form -->
<form method="post" action="index.php" name="login_form"' , $autocomplete ,
' class="disableAjax login hide js-show">
<fieldset>
<legend>';
echo __('Log in');
echo Util::showDocu('index');
echo '</legend>';
if ($GLOBALS['cfg']['AllowArbitraryServer']) {
echo '
<div class="item">
<label for="input_servername" title="';
echo __(
'You can enter hostname/IP address and port separated by space.'
);
echo '">';
echo __('Server:');
echo '</label>
<input type="text" name="pma_servername" id="input_servername"';
echo ' value="';
echo htmlspecialchars($default_server);
echo '" size="24" class="textfield" title="';
echo __(
'You can enter hostname/IP address and port separated by space.'
); echo '" />
</div>';
}
echo '<div class="item">
<label for="input_username">' , __('Username:') , '</label>
<input type="text" name="pma_username" id="input_username" '
, 'value="' , htmlspecialchars($default_user) , '" size="24"'
, ' class="textfield"/>
</div>
<div class="item">
<label for="input_password">' , __('Password:') , '</label>
<input type="password" name="pma_password" id="input_password"'
, ' value="" size="24" class="textfield" />
</div>';
if (count($GLOBALS['cfg']['Servers']) > 1) {
echo '<div class="item">
<label for="select_server">' . __('Server Choice:') . '</label>
<select name="server" id="select_server"';
if ($GLOBALS['cfg']['AllowArbitraryServer']) {
echo ' onchange="document.forms[\'login_form\'].'
, 'elements[\'pma_servername\'].value = \'\'" ';
}
echo '>';
include_once './libraries/select_server.lib.php';
echo PMA_selectServer(false, false);
echo '</select></div>';
} else {
echo ' <input type="hidden" name="server" value="'
, $GLOBALS['server'] , '" />';
} // end if (server choice)
// Add captcha input field if reCaptcha is enabled
if (!empty($GLOBALS['cfg']['CaptchaLoginPrivateKey'])
&& !empty($GLOBALS['cfg']['CaptchaLoginPublicKey'])
) {
// If enabled show captcha to the user on the login screen.
echo '<script src="https://www.google.com/recaptcha/api.js?hl='
, $GLOBALS['lang'] , '" async defer></script>';
echo '<div class="g-recaptcha" data-sitekey="'
, htmlspecialchars($GLOBALS['cfg']['CaptchaLoginPublicKey']) , '"></div>';
}
echo '</fieldset>
<fieldset class="tblFooters">
<input value="' , __('Go') , '" type="submit" id="input_go" />';
$_form_params = array();
if (! empty($GLOBALS['target'])) {
$_form_params['target'] = $GLOBALS['target'];
}
if (! empty($GLOBALS['db'])) {
$_form_params['db'] = $GLOBALS['db'];
}
if (! empty($GLOBALS['table'])) {
$_form_params['table'] = $GLOBALS['table'];
}
// do not generate a "server" hidden field as we want the "server"
// drop-down to have priority
echo PMA_URL_getHiddenInputs($_form_params, '', 0, 'server');
echo '</fieldset>
</form>';
if ($GLOBALS['error_handler']->hasDisplayErrors()) {
echo '<div id="pma_errors">';
$GLOBALS['error_handler']->dispErrors();
echo '</div>';
}
echo '</div>';
if (@file_exists(CUSTOM_FOOTER_FILE)) {
include CUSTOM_FOOTER_FILE;
}
if (! defined('TESTSUITE')) {
exit;
} else {
return true;
}
}
/**
* Gets advanced authentication settings
*
* this function DOES NOT check authentication - it just checks/provides
* authentication credentials required to connect to the MySQL server
* usually with $GLOBALS['dbi']->connect()
*
* it returns false if something is missing - which usually leads to
* auth() which displays login form
*
* it returns true if all seems ok which usually leads to auth_set_user()
*
* it directly switches to authFails() if user inactivity timeout is reached
*
* @return boolean whether we get authentication settings or not
*/
public function authCheck()
{
global $conn_error;
// Initialization
/**
* @global $GLOBALS['pma_auth_server'] the user provided server to
* connect to
*/
$GLOBALS['pma_auth_server'] = '';
$GLOBALS['PHP_AUTH_USER'] = $GLOBALS['PHP_AUTH_PW'] = '';
$GLOBALS['from_cookie'] = false;
if (! empty($_REQUEST['pma_username'])) {
// Verify Captcha if it is required.
if (! empty($GLOBALS['cfg']['CaptchaLoginPrivateKey'])
&& ! empty($GLOBALS['cfg']['CaptchaLoginPublicKey'])
) {
if (! empty($_POST["g-recaptcha-response"])) {
include_once 'libraries/plugins/auth/recaptcha/autoload.php';
$reCaptcha = new ReCaptcha(
$GLOBALS['cfg']['CaptchaLoginPrivateKey']
);
// verify captcha status.
$resp = $reCaptcha->verify(
$_POST["g-recaptcha-response"],
$_SERVER["REMOTE_ADDR"]
);
// Check if the captcha entered is valid, if not stop the login.
if ($resp == null || ! $resp->isSuccess()) {
$conn_error = __('Entered captcha is wrong, try again!');
return false;
}
} else {
$conn_error = __('Please enter correct captcha!');
return false;
}
}
// The user just logged in
$GLOBALS['PHP_AUTH_USER'] = PMA_sanitizeMySQLUser($_REQUEST['pma_username']);
$GLOBALS['PHP_AUTH_PW'] = empty($_REQUEST['pma_password'])
? ''
: $_REQUEST['pma_password'];
if ($GLOBALS['cfg']['AllowArbitraryServer']
&& isset($_REQUEST['pma_servername'])
) {
if ($GLOBALS['cfg']['ArbitraryServerRegexp']) {
$parts = explode(' ', $_REQUEST['pma_servername']);
if (count($parts) == 2) {
$tmp_host = $parts[0];
} else {
$tmp_host = $_REQUEST['pma_servername'];
}
$match = preg_match(
$GLOBALS['cfg']['ArbitraryServerRegexp'], $tmp_host
);
if (! $match) {
$conn_error = __(
'You are not allowed to log in to this MySQL server!'
);
return false;
}
}
$GLOBALS['pma_auth_server'] = PMA_sanitizeMySQLHost($_REQUEST['pma_servername']);
}
PMA_secureSession();
return true;
}
// At the end, try to set the $GLOBALS['PHP_AUTH_USER']
// and $GLOBALS['PHP_AUTH_PW'] variables from cookies
// check cookies
if (empty($_COOKIE['pmaUser-' . $GLOBALS['server']])) {
return false;
}
$GLOBALS['PHP_AUTH_USER'] = $this->cookieDecrypt(
$_COOKIE['pmaUser-' . $GLOBALS['server']],
$this->_getEncryptionSecret()
);
// user was never logged in since session start
if (empty($_SESSION['last_access_time'])) {
return false;
}
// User inactive too long
$last_access_time = time() - $GLOBALS['cfg']['LoginCookieValidity'];
if ($_SESSION['last_access_time'] < $last_access_time) {
Util::cacheUnset('is_create_db_priv');
Util::cacheUnset('is_reload_priv');
Util::cacheUnset('db_to_create');
Util::cacheUnset('dbs_where_create_table_allowed');
Util::cacheUnset('dbs_to_test');
Util::cacheUnset('db_priv');
Util::cacheUnset('col_priv');
Util::cacheUnset('table_priv');
Util::cacheUnset('proc_priv');
$GLOBALS['no_activity'] = true;
$this->authFails();
if (! defined('TESTSUITE')) {
exit;
} else {
return false;
}
}
// check password cookie
if (empty($_COOKIE['pmaAuth-' . $GLOBALS['server']])) {
return false;
}
$auth_data = json_decode(
$this->cookieDecrypt(
$_COOKIE['pmaAuth-' . $GLOBALS['server']],
$this->_getSessionEncryptionSecret()
),
true
);
if (! is_array($auth_data) || ! isset($auth_data['password'])) {
return false;
}
$GLOBALS['PHP_AUTH_PW'] = $auth_data['password'];
if ($GLOBALS['cfg']['AllowArbitraryServer'] && ! empty($auth_data['server'])) {
$GLOBALS['pma_auth_server'] = $auth_data['server'];
}
$GLOBALS['from_cookie'] = true;
return true;
}
/**
* Set the user and password after last checkings if required
*
* @return boolean always true
*/
public function authSetUser()
{
global $cfg;
// Ensures valid authentication mode, 'only_db', bookmark database and
// table names and relation table name are used
if (! hash_equals($cfg['Server']['user'], $GLOBALS['PHP_AUTH_USER'])) {
foreach ($cfg['Servers'] as $idx => $current) {
if ($current['host'] == $cfg['Server']['host']
&& $current['port'] == $cfg['Server']['port']
&& $current['socket'] == $cfg['Server']['socket']
&& $current['ssl'] == $cfg['Server']['ssl']
&& $current['connect_type'] == $cfg['Server']['connect_type']
&& hash_equals($current['user'], $GLOBALS['PHP_AUTH_USER'])
) {
$GLOBALS['server'] = $idx;
$cfg['Server'] = $current;
break;
}
} // end foreach
} // end if
if ($GLOBALS['cfg']['AllowArbitraryServer']
&& ! empty($GLOBALS['pma_auth_server'])
) {
/* Allow to specify 'host port' */
$parts = explode(' ', $GLOBALS['pma_auth_server']);
if (count($parts) == 2) {
$tmp_host = $parts[0];
$tmp_port = $parts[1];
} else {
$tmp_host = $GLOBALS['pma_auth_server'];
$tmp_port = '';
}
if ($cfg['Server']['host'] != $GLOBALS['pma_auth_server']) {
$cfg['Server']['host'] = $tmp_host;
if (! empty($tmp_port)) {
$cfg['Server']['port'] = $tmp_port;
}
}
unset($tmp_host, $tmp_port, $parts);
}
$cfg['Server']['user'] = $GLOBALS['PHP_AUTH_USER'];
$cfg['Server']['password'] = $GLOBALS['PHP_AUTH_PW'];
// Avoid showing the password in phpinfo()'s output
unset($GLOBALS['PHP_AUTH_PW']);
unset($_SERVER['PHP_AUTH_PW']);
$this->setSessionAccessTime();
}
/**
* Stores user credentials after successful login.
*
* @return void|bool
*/
public function storeUserCredentials()
{
global $cfg;
// Name and password cookies need to be refreshed each time
// Duration = one month for username
$this->storeUsernameCookie($cfg['Server']['user']);
// Duration = as configured
// Do not store password cookie on password change as we will
// set the cookie again after password has been changed
if (! isset($_POST['change_pw'])) {
$this->storePasswordCookie($cfg['Server']['password']);
}
// Set server cookies if required (once per session) and, in this case,
// force reload to ensure the client accepts cookies
if (! $GLOBALS['from_cookie']) {
// URL where to go:
$redirect_url = './index.php';
// any parameters to pass?
$url_params = array();
if (mb_strlen($GLOBALS['db'])) {
$url_params['db'] = $GLOBALS['db'];
}
if (mb_strlen($GLOBALS['table'])) {
$url_params['table'] = $GLOBALS['table'];
}
// any target to pass?
if (! empty($GLOBALS['target'])
&& $GLOBALS['target'] != 'index.php'
) {
$url_params['target'] = $GLOBALS['target'];
}
/**
* Clear user cache.
*/
Util::clearUserCache();
Response::getInstance()
->disable();
PMA_sendHeaderLocation(
$redirect_url . PMA_URL_getCommon($url_params, 'text'),
true
);
if (! defined('TESTSUITE')) {
exit;
} else {
return false;
}
} // end if
return true;
}
/**
* Stores username in a cookie.
*
* @param string $username User name
*
* @return void
*/
public function storeUsernameCookie($username)
{
// Name and password cookies need to be refreshed each time
// Duration = one month for username
$GLOBALS['PMA_Config']->setCookie(
'pmaUser-' . $GLOBALS['server'],
$this->cookieEncrypt(
$username,
$this->_getEncryptionSecret()
)
);
}
/**
* Stores password in a cookie.
*
* @param string $password Password
*
* @return void
*/
public function storePasswordCookie($password)
{
$payload = array('password' => $password);
if ($GLOBALS['cfg']['AllowArbitraryServer'] && ! empty($GLOBALS['pma_auth_server'])) {
$payload['server'] = $GLOBALS['pma_auth_server'];
}
// Duration = as configured
$GLOBALS['PMA_Config']->setCookie(
'pmaAuth-' . $GLOBALS['server'],
$this->cookieEncrypt(
json_encode($payload),
$this->_getSessionEncryptionSecret()
),
null,
$GLOBALS['cfg']['LoginCookieStore']
);
}
/**
* User is not allowed to login to MySQL -> authentication failed
*
* prepares error message and switches to auth() which display the error
* and the login form
*
* this function MUST exit/quit the application,
* currently done by call to auth()
*
* @return void
*/
public function authFails()
{
global $conn_error;
// Deletes password cookie and displays the login form
$GLOBALS['PMA_Config']->removeCookie('pmaAuth-' . $GLOBALS['server']);
$conn_error = $this->getErrorMessage();
$response = Response::getInstance();
// needed for PHP-CGI (not need for FastCGI or mod-php)
$response->header('Cache-Control: no-store, no-cache, must-revalidate');
$response->header('Pragma: no-cache');
$this->auth();
}
/**
* Returns blowfish secret or generates one if needed.
*
* @return string
*/
private function _getEncryptionSecret()
{
if (empty($GLOBALS['cfg']['blowfish_secret'])) {
return $this->_getSessionEncryptionSecret();
} else {
return $GLOBALS['cfg']['blowfish_secret'];
}
}
/**
* Returns blowfish secret or generates one if needed.
*
* @return string
*/
private function _getSessionEncryptionSecret()
{
if (empty($_SESSION['encryption_key'])) {
if (self::useOpenSSL()) {
$_SESSION['encryption_key'] = openssl_random_pseudo_bytes(32);
} else {
$_SESSION['encryption_key'] = Crypt\Random::string(32);
}
}
return $_SESSION['encryption_key'];
}
/**
* Checks whether we should use openssl for encryption.
*
* @return boolean
*/
public static function useOpenSSL()
{
return (
function_exists('openssl_encrypt')
&& function_exists('openssl_decrypt')
&& function_exists('openssl_random_pseudo_bytes')
);
}
/**
* Concatenates secret in order to make it 16 bytes log
*
* This doesn't add any security, just ensures the secret
* is long enough by copying it.
*
* @param string $secret Original secret
*
* @return string
*/
public function enlargeSecret($secret)
{
while (strlen($secret) < 16) {
$secret .= $secret;
}
return substr($secret, 0, 16);
}
/**
* Derives MAC secret from encryption secret.
*
* @param string $secret the secret
*
* @return string the MAC secret
*/
public function getMACSecret($secret)
{
// Grab first part, up to 16 chars
// The MAC and AES secrets can overlap if original secret is short
$length = strlen($secret);
if ($length > 16) {
return substr($secret, 0, 16);
}
return $this->enlargeSecret(
$length == 1 ? $secret : substr($secret, 0, -1)
);
}
/**
* Derives AES secret from encryption secret.
*
* @param string $secret the secret
*
* @return string the AES secret
*/
public function getAESSecret($secret)
{
// Grab second part, up to 16 chars
// The MAC and AES secrets can overlap if original secret is short
$length = strlen($secret);
if ($length > 16) {
return substr($secret, -16);
}
return $this->enlargeSecret(
$length == 1 ? $secret : substr($secret, 1)
);
}
/**
* Encryption using openssl's AES or phpseclib's AES
* (phpseclib uses mcrypt when it is available)
*
* @param string $data original data
* @param string $secret the secret
*
* @return string the encrypted result
*/
public function cookieEncrypt($data, $secret)
{
$mac_secret = $this->getMACSecret($secret);
$aes_secret = $this->getAESSecret($secret);
$iv = $this->createIV();
if (self::useOpenSSL()) {
$result = openssl_encrypt(
$data,
'AES-128-CBC',
$secret,
0,
$iv
);
} else {
$cipher = new Crypt\AES(Crypt\Base::MODE_CBC);
$cipher->setIV($iv);
$cipher->setKey($aes_secret);
$result = base64_encode($cipher->encrypt($data));
}
$iv = base64_encode($iv);
return json_encode(
array(
'iv' => $iv,
'mac' => hash_hmac('sha1', $iv . $result, $mac_secret),
'payload' => $result,
)
);
}
/**
* Decryption using openssl's AES or phpseclib's AES
* (phpseclib uses mcrypt when it is available)
*
* @param string $encdata encrypted data
* @param string $secret the secret
*
* @return string|bool original data, false on error
*/
public function cookieDecrypt($encdata, $secret)
{
$data = json_decode($encdata, true);
if (! is_array($data) || ! isset($data['mac']) || ! isset($data['iv']) || ! isset($data['payload'])
|| ! is_string($data['mac']) || ! is_string($data['iv']) || ! is_string($data['payload'])
) {
return false;
}
$mac_secret = $this->getMACSecret($secret);
$aes_secret = $this->getAESSecret($secret);
$newmac = hash_hmac('sha1', $data['iv'] . $data['payload'], $mac_secret);
if (! hash_equals($data['mac'], $newmac)) {
return false;
}
if (self::useOpenSSL()) {
return openssl_decrypt(
$data['payload'],
'AES-128-CBC',
$secret,
0,
base64_decode($data['iv'])
);
} else {
$cipher = new Crypt\AES(Crypt\Base::MODE_CBC);
$cipher->setIV(base64_decode($data['iv']));
$cipher->setKey($aes_secret);
return $cipher->decrypt(base64_decode($data['payload']));
}
}
/**
* Returns size of IV for encryption.
*
* @return int
*/
public function getIVSize()
{
if (self::useOpenSSL()) {
return openssl_cipher_iv_length('AES-128-CBC');
}
$cipher = new Crypt\AES(Crypt\Base::MODE_CBC);
return $cipher->block_size;
}
/**
* Initialization
* Store the initialization vector because it will be needed for
* further decryption. I don't think necessary to have one iv
* per server so I don't put the server number in the cookie name.
*
* @return void
*/
public function createIV()
{
/* Testsuite shortcut only to allow predictable IV */
if (! is_null($this->_cookie_iv)) {
return $this->_cookie_iv;
}
if (self::useOpenSSL()) {
return openssl_random_pseudo_bytes(
$this->getIVSize()
);
} else {
return Crypt\Random::string(
$this->getIVSize()
);
}
}
/**
* Sets encryption IV to use
*
* This is for testing only!
*
* @param string $vector The IV
*
* @return void
*/
public function setIV($vector)
{
$this->_cookie_iv = $vector;
}
/**
* Callback when user changes password.
*
* @param string $password New password to set
*
* @return void
*/
public function handlePasswordChange($password)
{
$this->storePasswordCookie($password);
}
/**
* Perform logout
*
* @return void
*/
public function logOut()
{
// -> delete password cookie(s)
if ($GLOBALS['cfg']['LoginCookieDeleteAll']) {
foreach ($GLOBALS['cfg']['Servers'] as $key => $val) {
$GLOBALS['PMA_Config']->removeCookie('pmaAuth-' . $key);
if (isset($_COOKIE['pmaAuth-' . $key])) {
unset($_COOKIE['pmaAuth-' . $key]);
}
}
} else {
$GLOBALS['PMA_Config']->removeCookie(
'pmaAuth-' . $GLOBALS['server']
);
if (isset($_COOKIE['pmaAuth-' . $GLOBALS['server']])) {
unset($_COOKIE['pmaAuth-' . $GLOBALS['server']]);
}
}
parent::logOut();
}
}

View File

@ -0,0 +1,262 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* HTTP Authentication plugin for phpMyAdmin.
* NOTE: Requires PHP loaded as a Apache module.
*
* @package PhpMyAdmin-Authentication
* @subpackage HTTP
*/
namespace PMA\libraries\plugins\auth;
use PMA\libraries\plugins\AuthenticationPlugin;
use PMA\libraries\Message;
use PMA\libraries\Response;
/**
* Handles the HTTP authentication methods
*
* @package PhpMyAdmin-Authentication
*/
class AuthenticationHttp extends AuthenticationPlugin
{
/**
* Displays authentication form and redirect as necessary
*
* @return boolean always true (no return indeed)
*/
public function auth()
{
$response = Response::getInstance();
if ($response->isAjax()) {
$response->setRequestStatus(false);
// reload_flag removes the token parameter from the URL and reloads
$response->addJSON('reload_flag', '1');
if (defined('TESTSUITE')) {
return true;
} else {
exit;
}
}
return $this->authForm();
}
/**
* Displays authentication form
*
* @return boolean
*/
public function authForm()
{
if (empty($GLOBALS['cfg']['Server']['auth_http_realm'])) {
if (empty($GLOBALS['cfg']['Server']['verbose'])) {
$server_message = $GLOBALS['cfg']['Server']['host'];
} else {
$server_message = $GLOBALS['cfg']['Server']['verbose'];
}
$realm_message = 'phpMyAdmin ' . $server_message;
} else {
$realm_message = $GLOBALS['cfg']['Server']['auth_http_realm'];
}
$response = Response::getInstance();
// remove non US-ASCII to respect RFC2616
$realm_message = preg_replace('/[^\x20-\x7e]/i', '', $realm_message);
$response->header('WWW-Authenticate: Basic realm="' . $realm_message . '"');
$response->header('HTTP/1.0 401 Unauthorized');
if (php_sapi_name() !== 'cgi-fcgi') {
$response->header('status: 401 Unauthorized');
}
/* HTML header */
$footer = $response->getFooter();
$footer->setMinimal();
$header = $response->getHeader();
$header->setTitle(__('Access denied!'));
$header->disableMenuAndConsole();
$header->setBodyId('loginform');
$response->addHTML('<h1>');
$response->addHTML(sprintf(__('Welcome to %s'), ' phpMyAdmin'));
$response->addHTML('</h1>');
$response->addHTML('<h3>');
$response->addHTML(
Message::error(
__('Wrong username/password. Access denied.')
)
);
$response->addHTML('</h3>');
if (@file_exists(CUSTOM_FOOTER_FILE)) {
include CUSTOM_FOOTER_FILE;
}
if (!defined('TESTSUITE')) {
exit;
} else {
return false;
}
}
/**
* Gets advanced authentication settings
*
* @global string $PHP_AUTH_USER the username if register_globals is
* on
* @global string $PHP_AUTH_PW the password if register_globals is
* on
*
* @return boolean whether we get authentication settings or not
*/
public function authCheck()
{
global $PHP_AUTH_USER, $PHP_AUTH_PW;
// Grabs the $PHP_AUTH_USER variable whatever are the values of the
// 'register_globals' and the 'variables_order' directives
if (empty($PHP_AUTH_USER)) {
if (PMA_getenv('PHP_AUTH_USER')) {
$PHP_AUTH_USER = PMA_getenv('PHP_AUTH_USER');
} elseif (PMA_getenv('REMOTE_USER')) {
// CGI, might be encoded, see below
$PHP_AUTH_USER = PMA_getenv('REMOTE_USER');
} elseif (PMA_getenv('REDIRECT_REMOTE_USER')) {
// CGI, might be encoded, see below
$PHP_AUTH_USER = PMA_getenv('REDIRECT_REMOTE_USER');
} elseif (PMA_getenv('AUTH_USER')) {
// WebSite Professional
$PHP_AUTH_USER = PMA_getenv('AUTH_USER');
} elseif (PMA_getenv('HTTP_AUTHORIZATION')) {
// IIS, might be encoded, see below
$PHP_AUTH_USER = PMA_getenv('HTTP_AUTHORIZATION');
} elseif (PMA_getenv('Authorization')) {
// FastCGI, might be encoded, see below
$PHP_AUTH_USER = PMA_getenv('Authorization');
}
}
// Grabs the $PHP_AUTH_PW variable whatever are the values of the
// 'register_globals' and the 'variables_order' directives
if (empty($PHP_AUTH_PW)) {
if (PMA_getenv('PHP_AUTH_PW')) {
$PHP_AUTH_PW = PMA_getenv('PHP_AUTH_PW');
} elseif (PMA_getenv('REMOTE_PASSWORD')) {
// Apache/CGI
$PHP_AUTH_PW = PMA_getenv('REMOTE_PASSWORD');
} elseif (PMA_getenv('AUTH_PASSWORD')) {
// WebSite Professional
$PHP_AUTH_PW = PMA_getenv('AUTH_PASSWORD');
}
}
// Decode possibly encoded information (used by IIS/CGI/FastCGI)
// (do not use explode() because a user might have a colon in his password
if (strcmp(substr($PHP_AUTH_USER, 0, 6), 'Basic ') == 0) {
$usr_pass = base64_decode(substr($PHP_AUTH_USER, 6));
if (!empty($usr_pass)) {
$colon = strpos($usr_pass, ':');
if ($colon) {
$PHP_AUTH_USER = substr($usr_pass, 0, $colon);
$PHP_AUTH_PW = substr($usr_pass, $colon + 1);
}
unset($colon);
}
unset($usr_pass);
}
// sanitize username
$PHP_AUTH_USER = PMA_sanitizeMySQLUser($PHP_AUTH_USER);
// User logged out -> ensure the new username is not the same
$old_usr = isset($_REQUEST['old_usr']) ? $_REQUEST['old_usr'] : '';
if (! empty($old_usr)
&& (isset($PHP_AUTH_USER) && hash_equals($old_usr, $PHP_AUTH_USER))
) {
$PHP_AUTH_USER = '';
// -> delete user's choices that were stored in session
if (!defined('TESTSUITE')) {
session_destroy();
}
}
// Returns whether we get authentication settings or not
if (empty($PHP_AUTH_USER)) {
return false;
} else {
return true;
}
}
/**
* Set the user and password after last checkings if required
*
* @global array $cfg the valid servers settings
* @global integer $server the id of the current server
* @global string $PHP_AUTH_USER the current username
* @global string $PHP_AUTH_PW the current password
*
* @return boolean always true
*/
public function authSetUser()
{
global $cfg, $server;
global $PHP_AUTH_USER, $PHP_AUTH_PW;
// Ensures valid authentication mode, 'only_db', bookmark database and
// table names and relation table name are used
if (! hash_equals($cfg['Server']['user'], $PHP_AUTH_USER)) {
$servers_cnt = count($cfg['Servers']);
for ($i = 1; $i <= $servers_cnt; $i++) {
if (isset($cfg['Servers'][$i])
&& ($cfg['Servers'][$i]['host'] == $cfg['Server']['host']
&& hash_equals($cfg['Servers'][$i]['user'], $PHP_AUTH_USER))
) {
$server = $i;
$cfg['Server'] = $cfg['Servers'][$i];
break;
}
} // end for
} // end if
$cfg['Server']['user'] = $PHP_AUTH_USER;
$cfg['Server']['password'] = $PHP_AUTH_PW;
// Avoid showing the password in phpinfo()'s output
unset($GLOBALS['PHP_AUTH_PW']);
unset($_SERVER['PHP_AUTH_PW']);
$this->setSessionAccessTime();
return true;
}
/**
* User is not allowed to login to MySQL -> authentication failed
*
* @return bool true
*/
public function authFails()
{
$error = $GLOBALS['dbi']->getError();
if ($error && $GLOBALS['errno'] != 1045) {
PMA_fatalError($error);
return true;
}
$this->authForm();
return true;
}
/**
* Returns URL for login form.
*
* @return string
*/
public function getLoginFormURL()
{
return './index.php?old_usr=' . $GLOBALS['PHP_AUTH_USER'];
}
}

View File

@ -0,0 +1,243 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* SignOn Authentication plugin for phpMyAdmin
*
* @package PhpMyAdmin-Authentication
* @subpackage SignOn
*/
namespace PMA\libraries\plugins\auth;
use PMA\libraries\plugins\AuthenticationPlugin;
use PMA;
/**
* Handles the SignOn authentication method
*
* @package PhpMyAdmin-Authentication
*/
class AuthenticationSignon extends AuthenticationPlugin
{
/**
* Displays authentication form
*
* @return boolean always true (no return indeed)
*/
public function auth()
{
unset($_SESSION['LAST_SIGNON_URL']);
if (empty($GLOBALS['cfg']['Server']['SignonURL'])) {
PMA_fatalError('You must set SignonURL!');
} else {
PMA_sendHeaderLocation($GLOBALS['cfg']['Server']['SignonURL']);
}
if (!defined('TESTSUITE')) {
exit();
} else {
return false;
}
}
/**
* Gets advanced authentication settings
*
* @global string $PHP_AUTH_USER the username if register_globals is on
* @global string $PHP_AUTH_PW the password if register_globals is on
*
* @return boolean whether we get authentication settings or not
*/
public function authCheck()
{
global $PHP_AUTH_USER, $PHP_AUTH_PW;
/* Check if we're using same signon server */
$signon_url = $GLOBALS['cfg']['Server']['SignonURL'];
if (isset($_SESSION['LAST_SIGNON_URL'])
&& $_SESSION['LAST_SIGNON_URL'] != $signon_url
) {
return false;
}
/* Script name */
$script_name = $GLOBALS['cfg']['Server']['SignonScript'];
/* Session name */
$session_name = $GLOBALS['cfg']['Server']['SignonSession'];
/* Login URL */
$signon_url = $GLOBALS['cfg']['Server']['SignonURL'];
/* Current host */
$single_signon_host = $GLOBALS['cfg']['Server']['host'];
/* Current port */
$single_signon_port = $GLOBALS['cfg']['Server']['port'];
/* No configuration updates */
$single_signon_cfgupdate = array();
/* Handle script based auth */
if (!empty($script_name)) {
if (!file_exists($script_name)) {
PMA_fatalError(
__('Can not find signon authentication script:')
. ' ' . $script_name
);
}
include $script_name;
list ($PHP_AUTH_USER, $PHP_AUTH_PW)
= get_login_credentials($GLOBALS['cfg']['Server']['user']);
} elseif (isset($_COOKIE[$session_name])) { /* Does session exist? */
/* End current session */
$old_session = session_name();
$old_id = session_id();
if (!defined('TESTSUITE')) {
session_write_close();
}
/* Load single signon session */
session_name($session_name);
session_id($_COOKIE[$session_name]);
if (!defined('TESTSUITE')) {
session_start();
}
/* Clear error message */
unset($_SESSION['PMA_single_signon_error_message']);
/* Grab credentials if they exist */
if (isset($_SESSION['PMA_single_signon_user'])) {
$PHP_AUTH_USER = $_SESSION['PMA_single_signon_user'];
}
if (isset($_SESSION['PMA_single_signon_password'])) {
$PHP_AUTH_PW = $_SESSION['PMA_single_signon_password'];
}
if (isset($_SESSION['PMA_single_signon_host'])) {
$single_signon_host = $_SESSION['PMA_single_signon_host'];
}
if (isset($_SESSION['PMA_single_signon_port'])) {
$single_signon_port = $_SESSION['PMA_single_signon_port'];
}
if (isset($_SESSION['PMA_single_signon_cfgupdate'])) {
$single_signon_cfgupdate = $_SESSION['PMA_single_signon_cfgupdate'];
}
/* Also get token as it is needed to access subpages */
if (isset($_SESSION['PMA_single_signon_token'])) {
/* No need to care about token on logout */
$pma_token = $_SESSION['PMA_single_signon_token'];
}
/* End single signon session */
if (!defined('TESTSUITE')) {
session_write_close();
}
/* Restart phpMyAdmin session */
session_name($old_session);
if (!empty($old_id)) {
session_id($old_id);
}
if (!defined('TESTSUITE')) {
session_start();
}
/* Set the single signon host */
$GLOBALS['cfg']['Server']['host'] = $single_signon_host;
/* Set the single signon port */
$GLOBALS['cfg']['Server']['port'] = $single_signon_port;
/* Configuration update */
$GLOBALS['cfg']['Server'] = array_merge(
$GLOBALS['cfg']['Server'],
$single_signon_cfgupdate
);
/* Restore our token */
if (!empty($pma_token)) {
$_SESSION[' PMA_token '] = $pma_token;
}
/**
* Clear user cache.
*/
PMA\libraries\Util::clearUserCache();
}
// Returns whether we get authentication settings or not
if (empty($PHP_AUTH_USER)) {
unset($_SESSION['LAST_SIGNON_URL']);
return false;
} else {
$_SESSION['LAST_SIGNON_URL'] = $GLOBALS['cfg']['Server']['SignonURL'];
return true;
}
}
/**
* Set the user and password after last checkings if required
*
* @global array $cfg the valid servers settings
* @global string $PHP_AUTH_USER the current username
* @global string $PHP_AUTH_PW the current password
*
* @return boolean always true
*/
public function authSetUser()
{
global $cfg;
global $PHP_AUTH_USER, $PHP_AUTH_PW;
$cfg['Server']['user'] = $PHP_AUTH_USER;
$cfg['Server']['password'] = $PHP_AUTH_PW;
return true;
}
/**
* User is not allowed to login to MySQL -> authentication failed
*
* @return boolean always true (no return indeed)
*/
public function authFails()
{
/* Session name */
$session_name = $GLOBALS['cfg']['Server']['SignonSession'];
/* Does session exist? */
if (isset($_COOKIE[$session_name])) {
/* End current session */
if (!defined('TESTSUITE')) {
session_write_close();
}
/* Load single signon session */
session_name($session_name);
session_id($_COOKIE[$session_name]);
if (!defined('TESTSUITE')) {
session_start();
}
/* Set error message */
$_SESSION['PMA_single_signon_error_message'] = $this->getErrorMessage();
}
$this->auth();
}
/**
* Returns URL for login form.
*
* @return string
*/
public function getLoginFormURL()
{
return $GLOBALS['cfg']['Server']['SignonURL'];
}
}

View File

@ -0,0 +1,29 @@
Copyright 2014, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,97 @@
<?php
/**
* This is a PHP library that handles calling reCAPTCHA.
*
* @copyright Copyright (c) 2015, Google Inc.
* @link http://www.google.com/recaptcha
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace ReCaptcha;
/**
* reCAPTCHA client.
*/
class ReCaptcha
{
/**
* Version of this client library.
* @const string
*/
const VERSION = 'php_1.1.2';
/**
* Shared secret for the site.
* @var type string
*/
private $secret;
/**
* Method used to communicate with service. Defaults to POST request.
* @var RequestMethod
*/
private $requestMethod;
/**
* Create a configured instance to use the reCAPTCHA service.
*
* @param string $secret shared secret between site and reCAPTCHA server.
* @param RequestMethod $requestMethod method used to send the request. Defaults to POST.
*/
public function __construct($secret, RequestMethod $requestMethod = null)
{
if (empty($secret)) {
throw new \RuntimeException('No secret provided');
}
if (!is_string($secret)) {
throw new \RuntimeException('The provided secret must be a string');
}
$this->secret = $secret;
if (!is_null($requestMethod)) {
$this->requestMethod = $requestMethod;
} else {
$this->requestMethod = new RequestMethod\Post();
}
}
/**
* Calls the reCAPTCHA siteverify API to verify whether the user passes
* CAPTCHA test.
*
* @param string $response The value of 'g-recaptcha-response' in the submitted form.
* @param string $remoteIp The end user's IP address.
* @return Response Response from the service.
*/
public function verify($response, $remoteIp = null)
{
// Discard empty solution submissions
if (empty($response)) {
$recaptchaResponse = new Response(false, array('missing-input-response'));
return $recaptchaResponse;
}
$params = new RequestParameters($this->secret, $response, $remoteIp, self::VERSION);
$rawResponse = $this->requestMethod->submit($params);
return Response::fromJson($rawResponse);
}
}

View File

@ -0,0 +1,42 @@
<?php
/**
* This is a PHP library that handles calling reCAPTCHA.
*
* @copyright Copyright (c) 2015, Google Inc.
* @link http://www.google.com/recaptcha
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace ReCaptcha;
/**
* Method used to send the request to the service.
*/
interface RequestMethod
{
/**
* Submit the request with the specified parameters.
*
* @param RequestParameters $params Request parameters
* @return string Body of the reCAPTCHA response
*/
public function submit(RequestParameters $params);
}

View File

@ -0,0 +1,74 @@
<?php
/**
* This is a PHP library that handles calling reCAPTCHA.
*
* @copyright Copyright (c) 2015, Google Inc.
* @link http://www.google.com/recaptcha
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace ReCaptcha\RequestMethod;
/**
* Convenience wrapper around the cURL functions to allow mocking.
*/
class Curl
{
/**
* @see http://php.net/curl_init
* @param string $url
* @return resource cURL handle
*/
public function init($url = null)
{
return curl_init($url);
}
/**
* @see http://php.net/curl_setopt_array
* @param resource $ch
* @param array $options
* @return bool
*/
public function setoptArray($ch, array $options)
{
return curl_setopt_array($ch, $options);
}
/**
* @see http://php.net/curl_exec
* @param resource $ch
* @return mixed
*/
public function exec($ch)
{
return curl_exec($ch);
}
/**
* @see http://php.net/curl_close
* @param resource $ch
*/
public function close($ch)
{
curl_close($ch);
}
}

View File

@ -0,0 +1,88 @@
<?php
/**
* This is a PHP library that handles calling reCAPTCHA.
*
* @copyright Copyright (c) 2015, Google Inc.
* @link http://www.google.com/recaptcha
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace ReCaptcha\RequestMethod;
use ReCaptcha\RequestMethod;
use ReCaptcha\RequestParameters;
/**
* Sends cURL request to the reCAPTCHA service.
* Note: this requires the cURL extension to be enabled in PHP
* @see http://php.net/manual/en/book.curl.php
*/
class CurlPost implements RequestMethod
{
/**
* URL to which requests are sent via cURL.
* @const string
*/
const SITE_VERIFY_URL = 'https://www.google.com/recaptcha/api/siteverify';
/**
* Curl connection to the reCAPTCHA service
* @var Curl
*/
private $curl;
public function __construct(Curl $curl = null)
{
if (!is_null($curl)) {
$this->curl = $curl;
} else {
$this->curl = new Curl();
}
}
/**
* Submit the cURL request with the specified parameters.
*
* @param RequestParameters $params Request parameters
* @return string Body of the reCAPTCHA response
*/
public function submit(RequestParameters $params)
{
$handle = $this->curl->init(self::SITE_VERIFY_URL);
$options = array(
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $params->toQueryString(),
CURLOPT_HTTPHEADER => array(
'Content-Type: application/x-www-form-urlencoded'
),
CURLINFO_HEADER_OUT => false,
CURLOPT_HEADER => false,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => true
);
$this->curl->setoptArray($handle, $options);
$response = $this->curl->exec($handle);
$this->curl->close($handle);
return $response;
}
}

View File

@ -0,0 +1,70 @@
<?php
/**
* This is a PHP library that handles calling reCAPTCHA.
*
* @copyright Copyright (c) 2015, Google Inc.
* @link http://www.google.com/recaptcha
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace ReCaptcha\RequestMethod;
use ReCaptcha\RequestMethod;
use ReCaptcha\RequestParameters;
/**
* Sends POST requests to the reCAPTCHA service.
*/
class Post implements RequestMethod
{
/**
* URL to which requests are POSTed.
* @const string
*/
const SITE_VERIFY_URL = 'https://www.google.com/recaptcha/api/siteverify';
/**
* Submit the POST request with the specified parameters.
*
* @param RequestParameters $params Request parameters
* @return string Body of the reCAPTCHA response
*/
public function submit(RequestParameters $params)
{
/**
* PHP 5.6.0 changed the way you specify the peer name for SSL context options.
* Using "CN_name" will still work, but it will raise deprecated errors.
*/
$peer_key = version_compare(PHP_VERSION, '5.6.0', '<') ? 'CN_name' : 'peer_name';
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => $params->toQueryString(),
// Force the peer to validate (not needed in 5.6.0+, but still works
'verify_peer' => true,
// Force the peer validation to use www.google.com
$peer_key => 'www.google.com',
),
);
$context = stream_context_create($options);
return file_get_contents(self::SITE_VERIFY_URL, false, $context);
}
}

View File

@ -0,0 +1,105 @@
<?php
/**
* This is a PHP library that handles calling reCAPTCHA.
*
* @copyright Copyright (c) 2015, Google Inc.
* @link http://www.google.com/recaptcha
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace ReCaptcha\RequestMethod;
/**
* Convenience wrapper around native socket and file functions to allow for
* mocking.
*/
class Socket
{
private $handle = null;
/**
* fsockopen
*
* @see http://php.net/fsockopen
* @param string $hostname
* @param int $port
* @param int $errno
* @param string $errstr
* @param float $timeout
* @return resource
*/
public function fsockopen($hostname, $port = -1, &$errno = 0, &$errstr = '', $timeout = null)
{
$this->handle = fsockopen($hostname, $port, $errno, $errstr, (is_null($timeout) ? ini_get("default_socket_timeout") : $timeout));
if ($this->handle != false && $errno === 0 && $errstr === '') {
return $this->handle;
} else {
return false;
}
}
/**
* fwrite
*
* @see http://php.net/fwrite
* @param string $string
* @param int $length
* @return int | bool
*/
public function fwrite($string, $length = null)
{
return fwrite($this->handle, $string, (is_null($length) ? strlen($string) : $length));
}
/**
* fgets
*
* @see http://php.net/fgets
* @param int $length
* @return string
*/
public function fgets($length = null)
{
return fgets($this->handle, $length);
}
/**
* feof
*
* @see http://php.net/feof
* @return bool
*/
public function feof()
{
return feof($this->handle);
}
/**
* fclose
*
* @see http://php.net/fclose
* @return bool
*/
public function fclose()
{
return fclose($this->handle);
}
}

View File

@ -0,0 +1,121 @@
<?php
/**
* This is a PHP library that handles calling reCAPTCHA.
*
* @copyright Copyright (c) 2015, Google Inc.
* @link http://www.google.com/recaptcha
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace ReCaptcha\RequestMethod;
use ReCaptcha\RequestMethod;
use ReCaptcha\RequestParameters;
/**
* Sends a POST request to the reCAPTCHA service, but makes use of fsockopen()
* instead of get_file_contents(). This is to account for people who may be on
* servers where allow_furl_open is disabled.
*/
class SocketPost implements RequestMethod
{
/**
* reCAPTCHA service host.
* @const string
*/
const RECAPTCHA_HOST = 'www.google.com';
/**
* @const string reCAPTCHA service path
*/
const SITE_VERIFY_PATH = '/recaptcha/api/siteverify';
/**
* @const string Bad request error
*/
const BAD_REQUEST = '{"success": false, "error-codes": ["invalid-request"]}';
/**
* @const string Bad response error
*/
const BAD_RESPONSE = '{"success": false, "error-codes": ["invalid-response"]}';
/**
* Socket to the reCAPTCHA service
* @var Socket
*/
private $socket;
/**
* Constructor
*
* @param \ReCaptcha\RequestMethod\Socket $socket optional socket, injectable for testing
*/
public function __construct(Socket $socket = null)
{
if (!is_null($socket)) {
$this->socket = $socket;
} else {
$this->socket = new Socket();
}
}
/**
* Submit the POST request with the specified parameters.
*
* @param RequestParameters $params Request parameters
* @return string Body of the reCAPTCHA response
*/
public function submit(RequestParameters $params)
{
$errno = 0;
$errstr = '';
if (false === $this->socket->fsockopen('ssl://' . self::RECAPTCHA_HOST, 443, $errno, $errstr, 30)) {
return self::BAD_REQUEST;
}
$content = $params->toQueryString();
$request = "POST " . self::SITE_VERIFY_PATH . " HTTP/1.1\r\n";
$request .= "Host: " . self::RECAPTCHA_HOST . "\r\n";
$request .= "Content-Type: application/x-www-form-urlencoded\r\n";
$request .= "Content-length: " . strlen($content) . "\r\n";
$request .= "Connection: close\r\n\r\n";
$request .= $content . "\r\n\r\n";
$this->socket->fwrite($request);
$response = '';
while (!$this->socket->feof()) {
$response .= $this->socket->fgets(4096);
}
$this->socket->fclose();
if (0 !== strpos($response, 'HTTP/1.1 200 OK')) {
return self::BAD_RESPONSE;
}
$parts = preg_split("#\n\s*\n#Uis", $response);
return $parts[1];
}
}

View File

@ -0,0 +1,103 @@
<?php
/**
* This is a PHP library that handles calling reCAPTCHA.
*
* @copyright Copyright (c) 2015, Google Inc.
* @link http://www.google.com/recaptcha
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace ReCaptcha;
/**
* Stores and formats the parameters for the request to the reCAPTCHA service.
*/
class RequestParameters
{
/**
* Site secret.
* @var string
*/
private $secret;
/**
* Form response.
* @var string
*/
private $response;
/**
* Remote user's IP address.
* @var string
*/
private $remoteIp;
/**
* Client version.
* @var string
*/
private $version;
/**
* Initialise parameters.
*
* @param string $secret Site secret.
* @param string $response Value from g-captcha-response form field.
* @param string $remoteIp User's IP address.
* @param string $version Version of this client library.
*/
public function __construct($secret, $response, $remoteIp = null, $version = null)
{
$this->secret = $secret;
$this->response = $response;
$this->remoteIp = $remoteIp;
$this->version = $version;
}
/**
* Array representation.
*
* @return array Array formatted parameters.
*/
public function toArray()
{
$params = array('secret' => $this->secret, 'response' => $this->response);
if (!is_null($this->remoteIp)) {
$params['remoteip'] = $this->remoteIp;
}
if (!is_null($this->version)) {
$params['version'] = $this->version;
}
return $params;
}
/**
* Query string representation for HTTP request.
*
* @return string Query string formatted parameters.
*/
public function toQueryString()
{
return http_build_query($this->toArray(), '', '&');
}
}

View File

@ -0,0 +1,102 @@
<?php
/**
* This is a PHP library that handles calling reCAPTCHA.
*
* @copyright Copyright (c) 2015, Google Inc.
* @link http://www.google.com/recaptcha
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace ReCaptcha;
/**
* The response returned from the service.
*/
class Response
{
/**
* Succes or failure.
* @var boolean
*/
private $success = false;
/**
* Error code strings.
* @var array
*/
private $errorCodes = array();
/**
* Build the response from the expected JSON returned by the service.
*
* @param string $json
* @return \ReCaptcha\Response
*/
public static function fromJson($json)
{
$responseData = json_decode($json, true);
if (!$responseData) {
return new Response(false, array('invalid-json'));
}
if (isset($responseData['success']) && $responseData['success'] == true) {
return new Response(true);
}
if (isset($responseData['error-codes']) && is_array($responseData['error-codes'])) {
return new Response(false, $responseData['error-codes']);
}
return new Response(false);
}
/**
* Constructor.
*
* @param boolean $success
* @param array $errorCodes
*/
public function __construct($success, array $errorCodes = array())
{
$this->success = $success;
$this->errorCodes = $errorCodes;
}
/**
* Is success?
*
* @return boolean
*/
public function isSuccess()
{
return $this->success;
}
/**
* Get error codes.
*
* @return array
*/
public function getErrorCodes()
{
return $this->errorCodes;
}
}

View File

@ -0,0 +1,38 @@
<?php
/* An autoloader for ReCaptcha\Foo classes. This should be require()d
* by the user before attempting to instantiate any of the ReCaptcha
* classes.
*/
spl_autoload_register(function ($class) {
if (substr($class, 0, 10) !== 'ReCaptcha\\') {
/* If the class does not lie under the "ReCaptcha" namespace,
* then we can exit immediately.
*/
return;
}
/* All of the classes have names like "ReCaptcha\Foo", so we need
* to replace the backslashes with frontslashes if we want the
* name to map directly to a location in the filesystem.
*/
$class = str_replace('\\', '/', $class);
/* First, check under the current directory. It is important that
* we look here first, so that we don't waste time searching for
* test classes in the common case.
*/
$path = dirname(__FILE__).'/'.$class.'.php';
if (is_readable($path)) {
require_once $path;
}
/* If we didn't find what we're looking for already, maybe it's
* a test class?
*/
$path = dirname(__FILE__).'/../tests/'.$class.'.php';
if (is_readable($path)) {
require_once $path;
}
});

View File

@ -0,0 +1,443 @@
<?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
*/
namespace PMA\libraries\plugins\export;
use PMA\libraries\plugins\ExportPlugin;
use PMA\libraries\properties\plugins\ExportPluginProperties;
use PMA\libraries\properties\options\items\HiddenPropertyItem;
use PMA\libraries\properties\options\groups\OptionsPropertyMainGroup;
use PMA\libraries\properties\options\groups\OptionsPropertyRootGroup;
use PMA;
use PMA\libraries\properties\options\items\SelectPropertyItem;
use PMA\libraries\plugins\export\TableProperty;
/**
* 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()
{
// 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(
array(
"NHibernate C# DO",
"NHibernate XML",
)
);
$this->_setCgHandlers(
array(
"_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,
$aliases = array()
) {
$CG_FORMATS = $this->_getCgFormats();
$CG_HANDLERS = $this->_getCgHandlers();
$format = $GLOBALS['codegen_format'];
if (isset($CG_FORMATS[$format])) {
$method = $CG_HANDLERS[$format];
return PMA_exportOutputHandler(
$this->$method($db, $table, $crlf, $aliases)
);
}
return PMA_exportOutputHandler(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, $aliases = array())
{
$db_alias = $db;
$table_alias = $table;
$this->initAlias($aliases, $db_alias, $table_alias);
$lines = array();
$result = $GLOBALS['dbi']->query(
sprintf(
'DESC %s.%s',
PMA\libraries\Util::backquote($db),
PMA\libraries\Util::backquote($table)
)
);
if ($result) {
/** @var TableProperty[] $tableProperties */
$tableProperties = array();
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 = array();
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,
$aliases = array()
) {
$db_alias = $db;
$table_alias = $table;
$this->initAlias($aliases, $db_alias, $table_alias);
$lines = array();
$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",
PMA\libraries\Util::backquote($db),
PMA\libraries\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($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($CG_HANDLERS)
{
$this->_cgHandlers = $CG_HANDLERS;
}
}

View File

@ -0,0 +1,331 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* CSV export code
*
* @package PhpMyAdmin-Export
* @subpackage CSV
*/
namespace PMA\libraries\plugins\export;
use PMA\libraries\properties\options\items\BoolPropertyItem;
use PMA\libraries\plugins\ExportPlugin;
use PMA\libraries\properties\plugins\ExportPluginProperties;
use PMA\libraries\properties\options\items\HiddenPropertyItem;
use PMA\libraries\properties\options\groups\OptionsPropertyMainGroup;
use PMA\libraries\properties\options\groups\OptionsPropertyRootGroup;
use PMA;
use PMA\libraries\properties\options\items\TextPropertyItem;
/**
* Handles the export for the CSV format
*
* @package PhpMyAdmin-Export
* @subpackage CSV
*/
class ExportCsv extends ExportPlugin
{
/**
* Constructor
*/
public function __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;
// 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', "\015", $csv_terminated);
$csv_terminated = str_replace('\\n', "\012", $csv_terminated);
$csv_terminated = str_replace('\\t', "\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,
$aliases = array()
) {
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,
null,
PMA\libraries\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 (!PMA_exportOutputHandler($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]) || is_null($row[$j])) {
$schema_insert .= $GLOBALS[$what . '_null'];
} elseif ($row[$j] == '0' || $row[$j] != '') {
// always enclose fields
if ($what == 'excel') {
$row[$j] = preg_replace("/\015(\012)?/", "\012", $row[$j]);
}
// remove CRLF characters within field
if (isset($GLOBALS[$what . '_removeCRLF'])
&& $GLOBALS[$what . '_removeCRLF']
) {
$row[$j] = str_replace(
"\n",
"",
str_replace(
"\r",
"",
$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 (!PMA_exportOutputHandler($schema_insert . $csv_terminated)) {
return false;
}
} // end while
$GLOBALS['dbi']->freeResult($result);
return true;
}
}

View File

@ -0,0 +1,88 @@
<?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
*/
namespace PMA\libraries\plugins\export;
use PMA\libraries\properties\options\items\BoolPropertyItem;
use PMA\libraries\properties\plugins\ExportPluginProperties;
use PMA\libraries\properties\options\items\HiddenPropertyItem;
use PMA\libraries\properties\options\groups\OptionsPropertyMainGroup;
use PMA\libraries\properties\options\groups\OptionsPropertyRootGroup;
use PMA\libraries\properties\options\items\SelectPropertyItem;
use PMA\libraries\properties\options\items\TextPropertyItem;
/**
* 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(
array(
'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;
}
}

View File

@ -0,0 +1,665 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* HTML-Word export code
*
* @package PhpMyAdmin-Export
* @subpackage HTML-Word
*/
namespace PMA\libraries\plugins\export;
use PMA\libraries\properties\options\items\BoolPropertyItem;
use PMA\libraries\properties\options\groups\OptionsPropertyMainGroup;
use PMA\libraries\properties\options\groups\OptionsPropertyRootGroup;
use PMA\libraries\plugins\ExportPlugin;
use PMA\libraries\properties\plugins\ExportPluginProperties;
use PMA\libraries\DatabaseInterface;
use PMA\libraries\Util;
use PMA\libraries\properties\options\items\RadioPropertyItem;
use PMA\libraries\properties\options\items\TextPropertyItem;
/**
* Handles the export for the HTML-Word format
*
* @package PhpMyAdmin-Export
* @subpackage HTML-Word
*/
class ExportHtmlword extends ExportPlugin
{
/**
* Constructor
*/
public function __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(
array(
'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 PMA_exportOutputHandler(
'<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 PMA_exportOutputHandler('</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 PMA_exportOutputHandler(
'<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,
$aliases = array()
) {
global $what;
$db_alias = $db;
$table_alias = $table;
$this->initAlias($aliases, $db_alias, $table_alias);
if (!PMA_exportOutputHandler(
'<h2>'
. __('Dumping data for table') . ' ' . htmlspecialchars($table_alias)
. '</h2>'
)
) {
return false;
}
if (!PMA_exportOutputHandler(
'<table class="width100" cellspacing="1">'
)
) {
return false;
}
// Gets the data from the database
$result = $GLOBALS['dbi']->query(
$sql_query,
null,
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 (!PMA_exportOutputHandler($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]) || is_null($row[$j])) {
$value = $GLOBALS[$what . '_null'];
} elseif ($row[$j] == '0' || $row[$j] != '') {
$value = $row[$j];
} else {
$value = '';
}
$schema_insert .= '<td class="print">'
. htmlspecialchars($value)
. '</td>';
} // end for
$schema_insert .= '</tr>';
if (!PMA_exportOutputHandler($schema_insert)) {
return false;
}
} // end while
$GLOBALS['dbi']->freeResult($result);
if (!PMA_exportOutputHandler('</table>')) {
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 = array())
{
$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 = array();
$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,
$aliases = array()
) {
// 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) = PMA_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 = PMA_getComments($db, $table);
}
if ($do_mime && $cfgRelation['mimework']) {
$schema_insert .= '<td class="print"><strong>'
. htmlspecialchars('MIME')
. '</strong></td>';
$mime_map = PMA_getMIME($db, $table, true);
}
$schema_insert .= '</tr>';
$columns = $GLOBALS['dbi']->getColumns($db, $table);
/**
* Get the unique keys in the table
*/
$unique_keys = array();
$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,
$aliases = array()
) {
$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 PMA_exportOutputHandler($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(
$column,
$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 = $fmt_post . '</strong>';
}
if ($column['Key'] == 'PRI') {
$fmt_pre = '<em>' . $fmt_pre;
$fmt_post = $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;
}
}

View File

@ -0,0 +1,238 @@
<?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
*/
namespace PMA\libraries\plugins\export;
use PMA\libraries\properties\options\items\BoolPropertyItem;
use PMA\libraries\plugins\ExportPlugin;
use PMA\libraries\properties\plugins\ExportPluginProperties;
use PMA\libraries\properties\options\items\HiddenPropertyItem;
use PMA\libraries\properties\options\groups\OptionsPropertyMainGroup;
use PMA\libraries\properties\options\groups\OptionsPropertyRootGroup;
use PMA;
/**
* Handles the export for the JSON format
*
* @package PhpMyAdmin-Export
* @subpackage JSON
*/
class ExportJson extends ExportPlugin
{
/**
* Constructor
*/
public function __construct()
{
$this->setProperties();
}
/**
* 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);
// JSON_PRETTY_PRINT is available since 5.4.0
if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
$leaf = new BoolPropertyItem(
'pretty_print',
__('Output pretty-printed JSON (Use human-readable formatting)')
);
$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()
{
PMA_exportOutputHandler(
'/**' . $GLOBALS['crlf']
. ' Export to JSON 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;
}
PMA_exportOutputHandler(
'// Database \'' . $db_alias . '\'' . $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 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,
$aliases = array()
) {
$db_alias = $db;
$table_alias = $table;
$this->initAlias($aliases, $db_alias, $table_alias);
$result = $GLOBALS['dbi']->query(
$sql_query,
null,
PMA\libraries\DatabaseInterface::QUERY_UNBUFFERED
);
$columns_cnt = $GLOBALS['dbi']->numFields($result);
$columns = array();
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) {
$buffer = $crlf . '// ' . $db_alias . '.' . $table_alias
. $crlf . $crlf;
$buffer .= '[';
} else {
$buffer = ', ';
}
if (!PMA_exportOutputHandler($buffer)) {
return false;
}
$data = array();
for ($i = 0; $i < $columns_cnt; $i++) {
$data[$columns[$i]] = $record[$i];
}
if (isset($GLOBALS['json_pretty_print'])
&& $GLOBALS['json_pretty_print']
) {
$encoded = json_encode($data, JSON_PRETTY_PRINT);
} else {
$encoded = json_encode($data);
}
if (!PMA_exportOutputHandler($encoded)) {
return false;
}
}
if ($record_cnt) {
if (!PMA_exportOutputHandler(']' . $crlf)) {
return false;
}
}
$GLOBALS['dbi']->freeResult($result);
return true;
}
}

View File

@ -0,0 +1,675 @@
<?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
*/
namespace PMA\libraries\plugins\export;
use PMA\libraries\properties\options\items\BoolPropertyItem;
use PMA\libraries\properties\plugins\ExportPluginProperties;
use PMA\libraries\properties\options\groups\OptionsPropertyMainGroup;
use PMA\libraries\properties\options\groups\OptionsPropertyRootGroup;
use PMA\libraries\plugins\ExportPlugin;
use PMA\libraries\DatabaseInterface;
use PMA\libraries\Util;
use PMA\libraries\properties\options\items\RadioPropertyItem;
use PMA\libraries\properties\options\items\TextPropertyItem;
/**
* Handles the export for the Latex format
*
* @package PhpMyAdmin-Export
* @subpackage Latex
*/
class ExportLatex extends ExportPlugin
{
/**
* Constructor
*/
public function __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(
array(
'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 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:') . ' ' . PMA_MYSQL_STR_VERSION . $crlf
. '% ' . __('PHP Version:') . ' ' . phpversion() . $crlf;
return PMA_exportOutputHandler($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 PMA_exportOutputHandler($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,
$aliases = array()
) {
$db_alias = $db;
$table_alias = $table;
$this->initAlias($aliases, $db_alias, $table_alias);
$result = $GLOBALS['dbi']->tryQuery(
$sql_query,
null,
DatabaseInterface::QUERY_UNBUFFERED
);
$columns_cnt = $GLOBALS['dbi']->numFields($result);
$columns = array();
$columns_alias = array();
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'],
array(
'texEscape',
get_class($this),
),
array('table' => $table_alias, 'database' => $db_alias)
)
. '} \\label{'
. Util::expandUserString(
$GLOBALS['latex_data_label'],
null,
array('table' => $table_alias, 'database' => $db_alias)
)
. '} \\\\';
}
if (!PMA_exportOutputHandler($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 (!PMA_exportOutputHandler($buffer . ' \\endfirsthead ' . $crlf)) {
return false;
}
if (isset($GLOBALS['latex_caption'])) {
if (!PMA_exportOutputHandler(
'\\caption{'
. Util::expandUserString(
$GLOBALS['latex_data_continued_caption'],
array(
'texEscape',
get_class($this),
),
array('table' => $table_alias, 'database' => $db_alias)
)
. '} \\\\ '
)
) {
return false;
}
}
if (!PMA_exportOutputHandler($buffer . '\\endhead \\endfoot' . $crlf)) {
return false;
}
} else {
if (!PMA_exportOutputHandler('\\\\ \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 ((!function_exists('is_null')
|| !is_null($record[$columns[$i]]))
&& 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 (!PMA_exportOutputHandler($buffer)) {
return false;
}
}
$buffer = ' \\end{longtable}' . $crlf;
if (!PMA_exportOutputHandler($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,
$aliases = array()
) {
$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 = array();
$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) = PMA_getRelationsAndStatus(
$do_relation && !empty($cfgRelation['relation']),
$db,
$table
);
/**
* Displays the table structure
*/
$buffer = $crlf . '%' . $crlf . '% ' . __('Structure:') . ' '
. $table_alias . $crlf . '%' . $crlf . ' \\begin{longtable}{';
if (!PMA_exportOutputHandler($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 = PMA_getComments($db, $table);
}
if ($do_mime && $cfgRelation['mimework']) {
$header .= ' & \\multicolumn{1}{|c|}{\\textbf{MIME}}';
$mime_map = PMA_getMIME($db, $table, true);
}
// Table caption for first page and label
if (isset($GLOBALS['latex_caption'])) {
$buffer .= ' \\caption{'
. Util::expandUserString(
$GLOBALS['latex_structure_caption'],
array(
'texEscape',
get_class($this),
),
array('table' => $table_alias, 'database' => $db_alias)
)
. '} \\label{'
. Util::expandUserString(
$GLOBALS['latex_structure_label'],
null,
array('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'],
array(
'texEscape',
get_class($this),
),
array('table' => $table_alias, 'database' => $db_alias)
)
. '} \\\\ ' . $crlf;
}
$buffer .= $header . ' \\\\ \\hline \\hline \\endhead \\endfoot ' . $crlf;
if (!PMA_exportOutputHandler($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 (!PMA_exportOutputHandler($buffer)) {
return false;
}
} // end while
$buffer = ' \\end{longtable}' . $crlf;
return PMA_exportOutputHandler($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 = array('$', '%', '{', '}', '&', '#', '_', '^');
$cnt_escape = count($escape);
for ($k = 0; $k < $cnt_escape; $k++) {
$string = str_replace($escape[$k], '\\' . $escape[$k], $string);
}
return $string;
}
}

View File

@ -0,0 +1,379 @@
<?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
*/
namespace PMA\libraries\plugins\export;
use PMA\libraries\properties\options\items\BoolPropertyItem;
use PMA\libraries\plugins\ExportPlugin;
use PMA\libraries\properties\plugins\ExportPluginProperties;
use PMA\libraries\properties\options\groups\OptionsPropertyMainGroup;
use PMA\libraries\properties\options\groups\OptionsPropertyRootGroup;
use PMA\libraries\properties\options\groups\OptionsPropertySubgroup;
use PMA;
use PMA\libraries\properties\options\items\RadioPropertyItem;
/**
* Handles the export for the MediaWiki class
*
* @package PhpMyAdmin-Export
* @subpackage MediaWiki
*/
class ExportMediawiki extends ExportPlugin
{
/**
* Constructor
*/
public function __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(
array(
'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,
$aliases = array()
) {
$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 "
. PMA\libraries\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 PMA_exportOutputHandler($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,
$aliases = array()
) {
$db_alias = $db;
$table_alias = $table;
$this->initAlias($aliases, $db_alias, $table_alias);
// Print data comment
$output = $this->_exportComment(
"Table data for " . PMA\libraries\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 (!is_null($column_names)) {
// Use '|-' for separating rows
$output .= "|-" . $this->_exportCRLF();
// Use '!' for separating table headers
foreach ($column_names as $column) {
if (!empty($aliases[$db]['tables'][$table]['columns'][$column])
) {
$column
= $aliases[$db]['tables'][$table]['columns'][$column];
}
$output .= " ! " . $column . "" . $this->_exportCRLF();
}
}
}
// Get the table data from the database
$result = $GLOBALS['dbi']->query(
$sql_query,
null,
PMA\libraries\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 PMA_exportOutputHandler($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 http://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";
}
}

View File

@ -0,0 +1,342 @@
<?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
*/
namespace PMA\libraries\plugins\export;
use PMA\libraries\properties\options\items\BoolPropertyItem;
use PMA\libraries\plugins\ExportPlugin;
use PMA\libraries\properties\plugins\ExportPluginProperties;
use PMA\libraries\properties\options\items\HiddenPropertyItem;
use PMA\libraries\properties\options\groups\OptionsPropertyMainGroup;
use PMA\libraries\properties\options\groups\OptionsPropertyRootGroup;
use PMA\libraries\DatabaseInterface;
use PMA\libraries\properties\options\items\TextPropertyItem;
$GLOBALS['ods_buffer'] = '';
require_once 'libraries/opendocument.lib.php';
/**
* Handles the export for the ODS class
*
* @package PhpMyAdmin-Export
* @subpackage ODS
*/
class ExportOds extends ExportPlugin
{
/**
* Constructor
*/
public function __construct()
{
$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 '
. $GLOBALS['OpenDocumentNS'] . '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>';
if (!PMA_exportOutputHandler(
PMA_createOpenDocument(
'application/vnd.oasis.opendocument.spreadsheet',
$GLOBALS['ods_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 = '')
{
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,
$aliases = array()
) {
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,
null,
DatabaseInterface::QUERY_UNBUFFERED
);
$fields_cnt = $GLOBALS['dbi']->numFields($result);
$fields_meta = $GLOBALS['dbi']->getFieldsMeta($result);
$field_flags = array();
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 (!isset($row[$j]) || is_null($row[$j])) {
$GLOBALS['ods_buffer']
.= '<table:table-cell office:value-type="string">'
. '<text:p>'
. htmlspecialchars($GLOBALS[$what . '_null'])
. '</text:p>'
. '</table:table-cell>';
} elseif (stristr($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;
}
}

View File

@ -0,0 +1,802 @@
<?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
*/
namespace PMA\libraries\plugins\export;
use PMA\libraries\properties\options\items\BoolPropertyItem;
use PMA\libraries\properties\plugins\ExportPluginProperties;
use PMA\libraries\properties\options\groups\OptionsPropertyMainGroup;
use PMA\libraries\properties\options\groups\OptionsPropertyRootGroup;
use PMA\libraries\DatabaseInterface;
use PMA\libraries\plugins\ExportPlugin;
use PMA\libraries\Util;
use PMA\libraries\properties\options\items\RadioPropertyItem;
use PMA\libraries\properties\options\items\TextPropertyItem;
$GLOBALS['odt_buffer'] = '';
require_once 'libraries/opendocument.lib.php';
/**
* Handles the export for the ODT class
*
* @package PhpMyAdmin-Export
* @subpackage ODT
*/
class ExportOdt extends ExportPlugin
{
/**
* Constructor
*/
public function __construct()
{
$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(
array(
'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 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 '
. $GLOBALS['OpenDocumentNS'] . '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 (!PMA_exportOutputHandler(
PMA_createOpenDocument(
'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,
$aliases = array()
) {
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,
null,
DatabaseInterface::QUERY_UNBUFFERED
);
$fields_cnt = $GLOBALS['dbi']->numFields($result);
$fields_meta = $GLOBALS['dbi']->getFieldsMeta($result);
$field_flags = array();
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 (!isset($row[$j]) || is_null($row[$j])) {
$GLOBALS['odt_buffer']
.= '<table:table-cell office:value-type="string">'
. '<text:p>'
. htmlspecialchars($GLOBALS[$what . '_null'])
. '</text:p>'
. '</table:table-cell>';
} elseif (stristr($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 = array())
{
$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'];
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 true;
}
/**
* 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,
$aliases = array()
) {
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) = PMA_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 = PMA_getComments($db, $table);
}
if ($do_mime && $cfgRelation['mimework']) {
$GLOBALS['odt_buffer'] .= '<table:table-cell office:value-type="string">'
. '<text:p>' . __('MIME type') . '</text:p>'
. '</table:table-cell>';
$mime_map = PMA_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 = PMA_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, $aliases = array())
{
$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,
$aliases = array()
) {
$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;
}
}

View File

@ -0,0 +1,390 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Produce a PDF report (export) from a query
*
* @package PhpMyAdmin-Export
* @subpackage PDF
*/
namespace PMA\libraries\plugins\export;
use PMA\libraries\plugins\ExportPlugin;
use PMA\libraries\properties\plugins\ExportPluginProperties;
use PMA\libraries\properties\options\groups\OptionsPropertyMainGroup;
use PMA\libraries\properties\options\groups\OptionsPropertyRootGroup;
use PMA\libraries\plugins\export\PMA_ExportPdf;
use PMA\libraries\properties\options\items\RadioPropertyItem;
use PMA\libraries\properties\options\items\TextPropertyItem;
/**
* Skip the plugin if TCPDF is not available.
*/
if (!@file_exists(TCPDF_INC)) {
$GLOBALS['skip_import'] = true;
return;
}
require_once 'libraries/transformations.lib.php';
/**
* Handles the export for the PDF class
*
* @package PhpMyAdmin-Export
* @subpackage PDF
*/
class ExportPdf extends ExportPlugin
{
/**
* PMA\libraries\plugins\export\PMA_ExportPdf instance
*
* @var PMA_ExportPdf
*/
private $_pdf;
/**
* PDF Report Title
*
* @var string
*/
private $_pdfReportTitle;
/**
* Constructor
*/
public function __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 PMA_ExportPdf('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(
array(
'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 = array('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():
if (!PMA_exportOutputHandler($pdf->getPDFData())) {
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 = '')
{
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,
$aliases = array()
) {
$db_alias = $db;
$table_alias = $table;
$this->initAlias($aliases, $db_alias, $table_alias);
$pdf = $this->_getPdf();
$attr = array(
'currentDb' => $db,
'currentTable' => $table,
'dbAlias' => $db_alias,
'tableAlias' => $table_alias,
'aliases' => $aliases,
);
$pdf->setAttributes($attr);
$pdf->purpose = __('Dumping data');
$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,
$aliases = array()
) {
$db_alias = $db;
$table_alias = $table;
$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 = array(
'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 PMA\libraries\plugins\export\PMA_ExportPdf instance
*
* @return PMA_ExportPdf
*/
private function _getPdf()
{
return $this->_pdf;
}
/**
* Instantiates the PMA\libraries\plugins\export\PMA_ExportPdf class
*
* @param PMA_ExportPdf $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;
}
}

View File

@ -0,0 +1,255 @@
<?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
*/
namespace PMA\libraries\plugins\export;
use PMA\libraries\plugins\ExportPlugin;
use PMA\libraries\properties\plugins\ExportPluginProperties;
use PMA\libraries\properties\options\items\HiddenPropertyItem;
use PMA\libraries\properties\options\groups\OptionsPropertyMainGroup;
use PMA\libraries\properties\options\groups\OptionsPropertyRootGroup;
use PMA;
/**
* Handles the export for the PHP Array class
*
* @package PhpMyAdmin-Export
* @subpackage PHP
*/
class ExportPhparray extends ExportPlugin
{
/**
* Constructor
*/
public function __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()
{
PMA_exportOutputHandler(
'<?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;
}
PMA_exportOutputHandler(
'/**' . $GLOBALS['crlf']
. ' * Database ' . $this->commentString(PMA\libraries\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,
$aliases = array()
) {
$db_alias = $db;
$table_alias = $table;
$this->initAlias($aliases, $db_alias, $table_alias);
$result = $GLOBALS['dbi']->query(
$sql_query,
null,
PMA\libraries\DatabaseInterface::QUERY_UNBUFFERED
);
$columns_cnt = $GLOBALS['dbi']->numFields($result);
$columns = array();
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/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(PMA\libraries\Util::backquote($db_alias)) . '.'
. $this->commentString(PMA\libraries\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 (!PMA_exportOutputHandler($buffer)) {
return false;
}
$GLOBALS['dbi']->freeResult($result);
return true;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,616 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Export to Texy! text.
*
* @package PhpMyAdmin-Export
* @subpackage Texy!text
*/
namespace PMA\libraries\plugins\export;
use PMA\libraries\properties\options\items\BoolPropertyItem;
use PMA\libraries\properties\plugins\ExportPluginProperties;
use PMA\libraries\properties\options\groups\OptionsPropertyMainGroup;
use PMA\libraries\properties\options\groups\OptionsPropertyRootGroup;
use PMA\libraries\DatabaseInterface;
use PMA\libraries\plugins\ExportPlugin;
use PMA\libraries\Util;
use PMA\libraries\properties\options\items\RadioPropertyItem;
use PMA\libraries\properties\options\items\TextPropertyItem;
/**
* Handles the export for the Texy! text class
*
* @package PhpMyAdmin-Export
* @subpackage Texy!text
*/
class ExportTexytext extends ExportPlugin
{
/**
* Constructor
*/
public function __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(
array(
'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 PMA_exportOutputHandler(
'===' . __('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,
$aliases = array()
) {
global $what;
$db_alias = $db;
$table_alias = $table;
$this->initAlias($aliases, $db_alias, $table_alias);
if (!PMA_exportOutputHandler(
'== ' . __('Dumping data for table') . ' ' . $table_alias . "\n\n"
)
) {
return false;
}
// Gets the data from the database
$result = $GLOBALS['dbi']->query(
$sql_query,
null,
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 (!PMA_exportOutputHandler($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]) || is_null($row[$j])) {
$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 (!PMA_exportOutputHandler($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 = array())
{
$text_output = '';
/**
* Get the unique keys in the table
*/
$unique_keys = array();
$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'];
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,
$aliases = array()
) {
global $cfgRelation;
$text_output = '';
/**
* Get the unique keys in the table
*/
$unique_keys = array();
$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) = PMA_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 = PMA_getComments($db, $table);
}
if ($do_mime && $cfgRelation['mimework']) {
$text_output .= '|' . htmlspecialchars('MIME');
$mime_map = PMA_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,
$aliases = array()
) {
$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 PMA_exportOutputHandler($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 = $fmt_post . '**';
}
if ($column['Key'] == 'PRI') {
$fmt_pre = '//' . $fmt_pre;
$fmt_post = $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;
}
}

View File

@ -0,0 +1,577 @@
<?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
*/
namespace PMA\libraries\plugins\export;
use PMA\libraries\properties\options\items\BoolPropertyItem;
use PMA\libraries\properties\plugins\ExportPluginProperties;
use PMA\libraries\properties\options\items\HiddenPropertyItem;
use PMA\libraries\properties\options\groups\OptionsPropertyMainGroup;
use PMA\libraries\properties\options\groups\OptionsPropertyRootGroup;
use PMA\libraries\DatabaseInterface;
use PMA\libraries\plugins\ExportPlugin;
use PMA\libraries\Util;
if (!mb_strlen($GLOBALS['db'])) { /* Can't do server export */
$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()
{
$this->setProperties();
}
/**
* Initialize the local variables that are used for export PDF
*
* @return void
*/
protected function initSpecificVariables()
{
global $table, $tables;
$this->_setTable($table);
$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, $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:') . ' ' . PMA_MYSQL_STR_VERSION . $crlf
. '- ' . __('PHP Version:') . ' ' . phpversion() . $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 (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 PMA_exportOutputHandler($head);
}
/**
* Outputs export footer
*
* @return bool Whether it succeeded
*/
public function exportFooter()
{
$foot = '</pma_xml_export>';
return PMA_exportOutputHandler($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 PMA_exportOutputHandler($head);
} else {
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 PMA_exportOutputHandler(' </database>' . $crlf);
} else {
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,
$aliases = array()
) {
// 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,
null,
DatabaseInterface::QUERY_UNBUFFERED
);
$columns_cnt = $GLOBALS['dbi']->numFields($result);
$columns = array();
for ($i = 0; $i < $columns_cnt; $i++) {
$columns[$i] = stripslashes($GLOBALS['dbi']->fieldName($result, $i));
}
unset($i);
$buffer = ' <!-- ' . __('Table') . ' '
. htmlspecialchars($table_alias) . ' -->' . $crlf;
if (!PMA_exportOutputHandler($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]) || is_null($record[$i])) {
$record[$i] = 'NULL';
}
$buffer .= ' <column name="'
. htmlspecialchars($col_as) . '">'
. htmlspecialchars((string)$record[$i])
. '</column>' . $crlf;
}
$buffer .= ' </table>' . $crlf;
if (!PMA_exportOutputHandler($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($tables)
{
$this->_tables = $tables;
}
}

View File

@ -0,0 +1,217 @@
<?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
*/
namespace PMA\libraries\plugins\export;
use PMA\libraries\plugins\ExportPlugin;
use PMA\libraries\properties\plugins\ExportPluginProperties;
use PMA\libraries\properties\options\items\HiddenPropertyItem;
use PMA\libraries\properties\options\groups\OptionsPropertyMainGroup;
use PMA\libraries\properties\options\groups\OptionsPropertyRootGroup;
use PMA;
/**
* Handles the export for the YAML format
*
* @package PhpMyAdmin-Export
* @subpackage YAML
*/
class ExportYaml extends ExportPlugin
{
/**
* Constructor
*/
public function __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()
{
PMA_exportOutputHandler(
'%YAML 1.1' . $GLOBALS['crlf'] . '---' . $GLOBALS['crlf']
);
return true;
}
/**
* Outputs export footer
*
* @return bool Whether it succeeded
*/
public function exportFooter()
{
PMA_exportOutputHandler('...' . $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,
$aliases = array()
) {
$db_alias = $db;
$table_alias = $table;
$this->initAlias($aliases, $db_alias, $table_alias);
$result = $GLOBALS['dbi']->query(
$sql_query,
null,
PMA\libraries\DatabaseInterface::QUERY_UNBUFFERED
);
$columns_cnt = $GLOBALS['dbi']->numFields($result);
$columns = array();
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 (is_null($record[$i])) {
$buffer .= ' ' . $columns[$i] . ': null' . $crlf;
continue;
}
if (is_numeric($record[$i])) {
$buffer .= ' ' . $columns[$i] . ': ' . $record[$i] . $crlf;
continue;
}
$record[$i] = str_replace(
array('\\', '"', "\n", "\r"),
array('\\\\', '\"', '\n', '\r'),
$record[$i]
);
$buffer .= ' ' . $columns[$i] . ': "' . $record[$i] . '"' . $crlf;
}
if (!PMA_exportOutputHandler($buffer)) {
return false;
}
}
$GLOBALS['dbi']->freeResult($result);
return true;
} // end getTableYAML
}

View File

@ -0,0 +1,811 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* PMA\libraries\plugins\export\TableProperty class
*
* @package PhpMyAdmin-Export
* @subpackage PDF
*/
namespace PMA\libraries\plugins\export;
use PMA\libraries\DatabaseInterface;
use PMA\libraries\PDF;
use PMA\libraries\Util;
use TCPDF_STATIC;
/**
* Adapted from a LGPL script by Philip Clarke
*
* @package PhpMyAdmin-Export
* @subpackage PDF
*/
class PMA_ExportPdf extends PDF
{
var $tablewidths;
var $headerset;
/**
* 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;
}
if ($current_page != $this->page) {
// account for columns mode
return true;
}
return false;
}
/**
* This method is used to render the page header.
*
* @return void
*/
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])) {
$fullwidth = 0;
foreach ($this->tablewidths as $width) {
$fullwidth += $width;
}
$this->SetY(($this->tMargin) - ($this->FontSizePt / $this->k) * 5);
$this->cellFontSize = $this->FontSizePt;
$this->SetFont(
PDF::PMA_PDF_FONT,
'',
($this->titleFontSize
? $this->titleFontSize
: $this->FontSizePt)
);
$this->Cell(0, $this->FontSizePt, $this->titleText, 0, 1, 'C');
$this->SetFont(PDF::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 = array();
$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($attr = array())
{
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)
{
$i = 0;
$triggers = $GLOBALS['dbi']->getTriggers($db, $table);
foreach ($triggers as $trigger) {
$i++;
break;
}
if ($i == 0) {
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(PDF::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 = array();
$maxpage = $this->page;
$data = array();
$triggers = $GLOBALS['dbi']->getTriggers($db, $table);
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,
$aliases = array()
) {
// 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 = PMA_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] = __('MIME');
$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(PDF::PMA_PDF_FONT, '', 9);
// Now let's start to write the table structure
if ($do_comments) {
$comments = PMA_getComments($db, $table);
}
if ($do_mime && $cfgRelation['mimework']) {
$mime_map = PMA_getMIME($db, $table, true);
}
$columns = $GLOBALS['dbi']->getColumns($db, $table);
/**
* Get the unique keys in the table.
* Presently, this information is not used. We will have to find out
* way of displaying it.
*/
$unique_keys = array();
$keys = $GLOBALS['dbi']->getTableIndexes($db, $table);
foreach ($keys as $key) {
if ($key['Non_unique'] == 0) {
$unique_keys[] = $key['Column_name'];
}
}
// 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 = array();
$maxpage = $this->page;
$data = array();
// 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,
null,
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 = array();
$titleWidth = array();
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 (stristr($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 = (sizeof($colFits) * $this->sColWidth) - $totAlreadyFitted;
$surplusToAdd = $surplus / ($this->numFields - sizeof($colFits));
} else {
$surplusToAdd = 0;
}
for ($i = 0; $i < $this->numFields; $i++) {
if (!in_array($i, array_keys($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,
null,
DatabaseInterface::QUERY_UNBUFFERED
);
$this->setY($this->tMargin);
$this->AddPage();
$this->SetFont(PDF::PMA_PDF_FONT, '', 9);
$this->morepagestable($this->FontSizePt);
$GLOBALS['dbi']->freeResult($this->results);
} // end of mysqlReport function
} // end of PMA_Export_PDF class

View File

@ -0,0 +1,257 @@
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]
*/
if (! defined('PHPMYADMIN')) {
exit;
}
/**
* Handles the export for the [Name] format
*
* @package PhpMyAdmin-Export
*/
class Export[Name] extends PMA\libraries\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 PMA\libraries\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 PMA\libraries\properties\options\groups\OptionsPropertyRootGroup(
"Format Specific Options"
);
// general options main group
$generalOptions = new PMA\libraries\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 PMA\libraries\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 PMA\libraries\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 PMA\libraries\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;
}
}
?>

View File

@ -0,0 +1,283 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Holds the PMA\libraries\plugins\export\TableProperty class
*
* @package PhpMyAdmin-Export
* @subpackage CodeGen
*/
namespace PMA\libraries\plugins\export;
/**
* PMA\libraries\plugins\export\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 bool
*/
public $nullable;
/**
* The key
*
* @var int
*/
public $key;
/**
* Default value
*
* @var mixed
*/
public $defaultValue;
/**
* Extension
*
* @var string
*/
public $ext;
/**
* Constructor
*
* @param array $row table row
*/
public function __construct($row)
{
$this->name = trim($row[0]);
$this->type = trim($row[1]);
$this->nullable = trim($row[2]);
$this->key = trim($row[3]);
$this->defaultValue = trim($row[4]);
$this->ext = trim($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 bool 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 bool true if the key is unique, false otherwise
*/
public function isUnique()
{
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 (mb_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()
{
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#",
htmlspecialchars($this->name, ENT_COMPAT, 'UTF-8'),
$text
);
$text = str_replace(
"#indexName#",
$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#",
ExportCodegen::cgMakeIdentifier($this->name),
$text
);
$text = str_replace(
"#dotNetPrimitiveType#",
$this->getDotNetPrimitiveType(),
$text
);
$text = str_replace(
"#dotNetObjectType#",
$this->getDotNetObjectType(),
$text
);
$text = str_replace(
"#type#",
$this->getPureType(),
$text
);
$text = str_replace(
"#notNull#",
$this->isNotNull(),
$text
);
$text = str_replace(
"#unique#",
$this->isUnique(),
$text
);
return $text;
}
}

View File

@ -0,0 +1,92 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Super class of CSV import plugins for phpMyAdmin
*
* @package PhpMyAdmin-Import
* @subpackage CSV
*/
namespace PMA\libraries\plugins\import;
use PMA\libraries\properties\options\items\BoolPropertyItem;
use PMA\libraries\properties\plugins\ImportPluginProperties;
use PMA\libraries\properties\options\groups\OptionsPropertyMainGroup;
use PMA\libraries\properties\options\groups\OptionsPropertyRootGroup;
use PMA\libraries\plugins\ImportPlugin;
use PMA\libraries\properties\options\items\TextPropertyItem;
/**
* Super class of the import plugins for the CSV format
*
* @package PhpMyAdmin-Import
* @subpackage CSV
*/
abstract class AbstractImportCsv extends ImportPlugin
{
/**
* Sets the import plugin properties.
* Called in the constructor.
*
* @return \PMA\libraries\properties\options\groups\OptionsPropertyMainGroup PMA\libraries\properties\options\groups\OptionsPropertyMainGroup object of the plugin
*/
protected function setProperties()
{
$importPluginProperties = new ImportPluginProperties();
$importPluginProperties->setOptionsText(__('Options'));
// create the root group that will be the options field for
// $importPluginProperties
// this will be shown as "Format specific options"
$importSpecificOptions = new OptionsPropertyRootGroup(
"Format Specific Options"
);
// general options main group
$generalOptions = new OptionsPropertyMainGroup("general_opts");
// create common items and add them to the group
$leaf = new BoolPropertyItem(
"replace",
__(
'Update data when duplicate keys found on import (add ON DUPLICATE '
. 'KEY UPDATE)'
)
);
$generalOptions->addProperty($leaf);
$leaf = new TextPropertyItem(
"terminated",
__('Columns separated with:')
);
$leaf->setSize(2);
$generalOptions->addProperty($leaf);
$leaf = new TextPropertyItem(
"enclosed",
__('Columns enclosed with:')
);
$leaf->setSize(2);
$leaf->setLen(2);
$generalOptions->addProperty($leaf);
$leaf = new TextPropertyItem(
"escaped",
__('Columns escaped with:')
);
$leaf->setSize(2);
$leaf->setLen(2);
$generalOptions->addProperty($leaf);
$leaf = new TextPropertyItem(
"new_line",
__('Lines terminated with:')
);
$leaf->setSize(2);
$generalOptions->addProperty($leaf);
// add the main group to the root group
$importSpecificOptions->addProperty($generalOptions);
// set the options for the import plugin property item
$importPluginProperties->setOptions($importSpecificOptions);
$this->properties = $importPluginProperties;
return $generalOptions;
}
}

View File

@ -0,0 +1,716 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* CSV import plugin for phpMyAdmin
*
* @todo add an option for handling NULL values
* @package PhpMyAdmin-Import
* @subpackage CSV
*/
namespace PMA\libraries\plugins\import;
use PMA\libraries\properties\options\items\BoolPropertyItem;
use PMA;
use PMA\libraries\properties\options\items\TextPropertyItem;
/**
* Handles the import for the CSV format
*
* @package PhpMyAdmin-Import
* @subpackage CSV
*/
class ImportCsv extends AbstractImportCsv
{
/**
* Whether to analyze tables
*
* @var bool
*/
private $_analyze;
/**
* Constructor
*/
public function __construct()
{
$this->setProperties();
}
/**
* Sets the import plugin properties.
* Called in the constructor.
*
* @return void
*/
protected function setProperties()
{
$this->_setAnalyze(false);
if ($GLOBALS['plugin_param'] !== 'table') {
$this->_setAnalyze(true);
}
$generalOptions = parent::setProperties();
$this->properties->setText('CSV');
$this->properties->setExtension('csv');
if ($GLOBALS['plugin_param'] !== 'table') {
$leaf = new BoolPropertyItem(
"col_names",
__(
'The first line of the file contains the table column names'
. ' <i>(if this is unchecked, the first line will become part'
. ' of the data)</i>'
)
);
$generalOptions->addProperty($leaf);
} else {
$hint = new PMA\libraries\Message(
__(
'If the data in each row of the file is not'
. ' in the same order as in the database, list the corresponding'
. ' column names here. Column names must be separated by commas'
. ' and not enclosed in quotations.'
)
);
$leaf = new TextPropertyItem(
"columns",
__('Column names: ') . PMA\libraries\Util::showHint($hint)
);
$generalOptions->addProperty($leaf);
}
$leaf = new BoolPropertyItem(
"ignore",
__('Do not abort on INSERT error')
);
$generalOptions->addProperty($leaf);
}
/**
* Handles the whole import logic
*
* @param array &$sql_data 2-element array with sql data
*
* @return void
*/
public function doImport(&$sql_data = array())
{
global $db, $table, $csv_terminated, $csv_enclosed, $csv_escaped,
$csv_new_line, $csv_columns, $err_url;
// $csv_replace and $csv_ignore should have been here,
// but we use directly from $_POST
global $error, $timeout_passed, $finished, $message;
$replacements = array(
'\\n' => "\n",
'\\t' => "\t",
'\\r' => "\r",
);
$csv_terminated = strtr($csv_terminated, $replacements);
$csv_enclosed = strtr($csv_enclosed, $replacements);
$csv_escaped = strtr($csv_escaped, $replacements);
$csv_new_line = strtr($csv_new_line, $replacements);
$param_error = false;
if (mb_strlen($csv_terminated) < 1) {
$message = PMA\libraries\Message::error(
__('Invalid parameter for CSV import: %s')
);
$message->addParam(__('Columns terminated with'), false);
$error = true;
$param_error = true;
// The default dialog of MS Excel when generating a CSV produces a
// semi-colon-separated file with no chance of specifying the
// enclosing character. Thus, users who want to import this file
// tend to remove the enclosing character on the Import dialog.
// I could not find a test case where having no enclosing characters
// confuses this script.
// But the parser won't work correctly with strings so we allow just
// one character.
} elseif (mb_strlen($csv_enclosed) > 1) {
$message = PMA\libraries\Message::error(
__('Invalid parameter for CSV import: %s')
);
$message->addParam(__('Columns enclosed with'), false);
$error = true;
$param_error = true;
// I could not find a test case where having no escaping characters
// confuses this script.
// But the parser won't work correctly with strings so we allow just
// one character.
} elseif (mb_strlen($csv_escaped) > 1) {
$message = PMA\libraries\Message::error(
__('Invalid parameter for CSV import: %s')
);
$message->addParam(__('Columns escaped with'), false);
$error = true;
$param_error = true;
} elseif (mb_strlen($csv_new_line) != 1
&& $csv_new_line != 'auto'
) {
$message = PMA\libraries\Message::error(
__('Invalid parameter for CSV import: %s')
);
$message->addParam(__('Lines terminated with'), false);
$error = true;
$param_error = true;
}
// If there is an error in the parameters entered,
// indicate that immediately.
if ($param_error) {
PMA\libraries\Util::mysqlDie(
$message->getMessage(),
'',
false,
$err_url
);
}
$buffer = '';
$required_fields = 0;
if (!$this->_getAnalyze()) {
$sql_template = 'INSERT';
if (isset($_POST['csv_ignore'])) {
$sql_template .= ' IGNORE';
}
$sql_template .= ' INTO ' . PMA\libraries\Util::backquote($table);
$tmp_fields = $GLOBALS['dbi']->getColumns($db, $table);
if (empty($csv_columns)) {
$fields = $tmp_fields;
} else {
$sql_template .= ' (';
$fields = array();
$tmp = preg_split('/,( ?)/', $csv_columns);
foreach ($tmp as $key => $val) {
if (count($fields) > 0) {
$sql_template .= ', ';
}
/* Trim also `, if user already included backquoted fields */
$val = trim($val, " \t\r\n\0\x0B`");
$found = false;
foreach ($tmp_fields as $field) {
if ($field['Field'] == $val) {
$found = true;
break;
}
}
if (!$found) {
$message = PMA\libraries\Message::error(
__(
'Invalid column (%s) specified! Ensure that columns'
. ' names are spelled correctly, separated by commas'
. ', and not enclosed in quotes.'
)
);
$message->addParam($val);
$error = true;
break;
}
$fields[] = $field;
$sql_template .= PMA\libraries\Util::backquote($val);
}
$sql_template .= ') ';
}
$required_fields = count($fields);
$sql_template .= ' VALUES (';
}
// Defaults for parser
$i = 0;
$len = 0;
$lastlen = null;
$line = 1;
$lasti = -1;
$values = array();
$csv_finish = false;
$tempRow = array();
$rows = array();
$col_names = array();
$tables = array();
$col_count = 0;
$max_cols = 0;
$csv_terminated_len = mb_strlen($csv_terminated);
while (!($finished && $i >= $len) && !$error && !$timeout_passed) {
$data = PMA_importGetNextChunk();
if ($data === false) {
// subtract data we didn't handle yet and stop processing
$GLOBALS['offset'] -= strlen($buffer);
break;
} elseif ($data === true) {
// Handle rest of buffer
} else {
// Append new data to buffer
$buffer .= $data;
unset($data);
// Force a trailing new line at EOF to prevent parsing problems
if ($finished && $buffer) {
$finalch = mb_substr($buffer, -1);
if ($csv_new_line == 'auto'
&& $finalch != "\r"
&& $finalch != "\n"
) {
$buffer .= "\n";
} elseif ($csv_new_line != 'auto'
&& $finalch != $csv_new_line
) {
$buffer .= $csv_new_line;
}
}
// Do not parse string when we're not at the end
// and don't have new line inside
if (($csv_new_line == 'auto'
&& mb_strpos($buffer, "\r") === false
&& mb_strpos($buffer, "\n") === false)
|| ($csv_new_line != 'auto'
&& mb_strpos($buffer, $csv_new_line) === false)
) {
continue;
}
}
// Current length of our buffer
$len = mb_strlen($buffer);
// Currently parsed char
$ch = mb_substr($buffer, $i, 1);
if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) {
$ch = $this->readCsvTerminatedString(
$buffer,
$ch,
$i,
$csv_terminated_len
);
$i += $csv_terminated_len - 1;
}
while ($i < $len) {
// Deadlock protection
if ($lasti == $i && $lastlen == $len) {
$message = PMA\libraries\Message::error(
__('Invalid format of CSV input on line %d.')
);
$message->addParam($line);
$error = true;
break;
}
$lasti = $i;
$lastlen = $len;
// This can happen with auto EOL and \r at the end of buffer
if (!$csv_finish) {
// Grab empty field
if ($ch == $csv_terminated) {
if ($i == $len - 1) {
break;
}
$values[] = '';
$i++;
$ch = mb_substr($buffer, $i, 1);
if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) {
$ch = $this->readCsvTerminatedString(
$buffer,
$ch,
$i,
$csv_terminated_len
);
$i += $csv_terminated_len - 1;
}
continue;
}
// Grab one field
$fallbacki = $i;
if ($ch == $csv_enclosed) {
if ($i == $len - 1) {
break;
}
$need_end = true;
$i++;
$ch = mb_substr($buffer, $i, 1);
if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) {
$ch = $this->readCsvTerminatedString(
$buffer,
$ch,
$i,
$csv_terminated_len
);
$i += $csv_terminated_len - 1;
}
} else {
$need_end = false;
}
$fail = false;
$value = '';
while (($need_end
&& ($ch != $csv_enclosed
|| $csv_enclosed == $csv_escaped))
|| (!$need_end
&& !($ch == $csv_terminated
|| $ch == $csv_new_line
|| ($csv_new_line == 'auto'
&& ($ch == "\r" || $ch == "\n"))))
) {
if ($ch == $csv_escaped) {
if ($i == $len - 1) {
$fail = true;
break;
}
$i++;
$ch = mb_substr($buffer, $i, 1);
if ($csv_terminated_len > 1
&& $ch == $csv_terminated[0]
) {
$ch = $this->readCsvTerminatedString(
$buffer,
$ch,
$i,
$csv_terminated_len
);
$i += $csv_terminated_len - 1;
}
if ($csv_enclosed == $csv_escaped
&& ($ch == $csv_terminated
|| $ch == $csv_new_line
|| ($csv_new_line == 'auto'
&& ($ch == "\r" || $ch == "\n")))
) {
break;
}
}
$value .= $ch;
if ($i == $len - 1) {
if (!$finished) {
$fail = true;
}
break;
}
$i++;
$ch = mb_substr($buffer, $i, 1);
if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) {
$ch = $this->readCsvTerminatedString(
$buffer,
$ch,
$i,
$csv_terminated_len
);
$i += $csv_terminated_len - 1;
}
}
// unquoted NULL string
if (false === $need_end && $value === 'NULL') {
$value = null;
}
if ($fail) {
$i = $fallbacki;
$ch = mb_substr($buffer, $i, 1);
if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) {
$i += $csv_terminated_len - 1;
}
break;
}
// Need to strip trailing enclosing char?
if ($need_end && $ch == $csv_enclosed) {
if ($finished && $i == $len - 1) {
$ch = null;
} elseif ($i == $len - 1) {
$i = $fallbacki;
$ch = mb_substr($buffer, $i, 1);
if ($csv_terminated_len > 1
&& $ch == $csv_terminated[0]
) {
$i += $csv_terminated_len - 1;
}
break;
} else {
$i++;
$ch = mb_substr($buffer, $i, 1);
if ($csv_terminated_len > 1
&& $ch == $csv_terminated[0]
) {
$ch = $this->readCsvTerminatedString(
$buffer,
$ch,
$i,
$csv_terminated_len
);
$i += $csv_terminated_len - 1;
}
}
}
// Are we at the end?
if ($ch == $csv_new_line
|| ($csv_new_line == 'auto' && ($ch == "\r" || $ch == "\n"))
|| ($finished && $i == $len - 1)
) {
$csv_finish = true;
}
// Go to next char
if ($ch == $csv_terminated) {
if ($i == $len - 1) {
$i = $fallbacki;
$ch = mb_substr($buffer, $i, 1);
if ($csv_terminated_len > 1
&& $ch == $csv_terminated[0]
) {
$i += $csv_terminated_len - 1;
}
break;
}
$i++;
$ch = mb_substr($buffer, $i, 1);
if ($csv_terminated_len > 1
&& $ch == $csv_terminated[0]
) {
$ch = $this->readCsvTerminatedString(
$buffer,
$ch,
$i,
$csv_terminated_len
);
$i += $csv_terminated_len - 1;
}
}
// If everything went okay, store value
$values[] = $value;
}
// End of line
if ($csv_finish
|| $ch == $csv_new_line
|| ($csv_new_line == 'auto' && ($ch == "\r" || $ch == "\n"))
) {
if ($csv_new_line == 'auto' && $ch == "\r") { // Handle "\r\n"
if ($i >= ($len - 2) && !$finished) {
break; // We need more data to decide new line
}
if (mb_substr($buffer, $i + 1, 1) == "\n") {
$i++;
}
}
// We didn't parse value till the end of line, so there was
// empty one
if (!$csv_finish) {
$values[] = '';
}
if ($this->_getAnalyze()) {
foreach ($values as $val) {
$tempRow[] = $val;
++$col_count;
}
if ($col_count > $max_cols) {
$max_cols = $col_count;
}
$col_count = 0;
$rows[] = $tempRow;
$tempRow = array();
} else {
// Do we have correct count of values?
if (count($values) != $required_fields) {
// Hack for excel
if ($values[count($values) - 1] == ';') {
unset($values[count($values) - 1]);
} else {
$message = PMA\libraries\Message::error(
__(
'Invalid column count in CSV input'
. ' on line %d.'
)
);
$message->addParam($line);
$error = true;
break;
}
}
$first = true;
$sql = $sql_template;
foreach ($values as $key => $val) {
if (!$first) {
$sql .= ', ';
}
if ($val === null) {
$sql .= 'NULL';
} else {
$sql .= '\''
. $GLOBALS['dbi']->escapeString($val)
. '\'';
}
$first = false;
}
$sql .= ')';
if (isset($_POST['csv_replace'])) {
$sql .= " ON DUPLICATE KEY UPDATE ";
foreach ($fields as $field) {
$fieldName = PMA\libraries\Util::backquote(
$field['Field']
);
$sql .= $fieldName . " = VALUES(" . $fieldName
. "), ";
}
$sql = rtrim($sql, ', ');
}
/**
* @todo maybe we could add original line to verbose
* SQL in comment
*/
PMA_importRunQuery($sql, $sql, $sql_data);
}
$line++;
$csv_finish = false;
$values = array();
$buffer = mb_substr($buffer, $i + 1);
$len = mb_strlen($buffer);
$i = 0;
$lasti = -1;
$ch = mb_substr($buffer, 0, 1);
}
} // End of parser loop
} // End of import loop
if ($this->_getAnalyze()) {
/* Fill out all rows */
$num_rows = count($rows);
for ($i = 0; $i < $num_rows; ++$i) {
for ($j = count($rows[$i]); $j < $max_cols; ++$j) {
$rows[$i][] = 'NULL';
}
}
if (isset($_REQUEST['csv_col_names'])) {
$col_names = array_splice($rows, 0, 1);
$col_names = $col_names[0];
// MySQL column names can't end with a space character.
foreach ($col_names as $key => $col_name) {
$col_names[$key] = rtrim($col_name);
}
}
if ((isset($col_names) && count($col_names) != $max_cols)
|| !isset($col_names)
) {
// Fill out column names
for ($i = 0; $i < $max_cols; ++$i) {
$col_names[] = 'COL ' . ($i + 1);
}
}
if (mb_strlen($db)) {
$result = $GLOBALS['dbi']->fetchResult('SHOW TABLES');
$tbl_name = 'TABLE ' . (count($result) + 1);
} else {
$tbl_name = 'TBL_NAME';
}
$tables[] = array($tbl_name, $col_names, $rows);
/* Obtain the best-fit MySQL types for each column */
$analyses = array();
$analyses[] = PMA_analyzeTable($tables[0]);
/**
* string $db_name (no backquotes)
*
* array $table = array(table_name, array() column_names, array()() rows)
* array $tables = array of "$table"s
*
* array $analysis = array(array() column_types, array() column_sizes)
* array $analyses = array of "$analysis"s
*
* array $create = array of SQL strings
*
* array $options = an associative array of options
*/
/* Set database name to the currently selected one, if applicable */
list($db_name, $options) = $this->getDbnameAndOptions($db, 'CSV_DB');
/* Non-applicable parameters */
$create = null;
/* Created and execute necessary SQL statements from data */
PMA_buildSQL($db_name, $tables, $analyses, $create, $options, $sql_data);
unset($tables);
unset($analyses);
}
// Commit any possible data in buffers
PMA_importRunQuery('', '', $sql_data);
if (count($values) != 0 && !$error) {
$message = PMA\libraries\Message::error(
__('Invalid format of CSV input on line %d.')
);
$message->addParam($line);
$error = true;
}
}
/**
* Read the expected column_separated_with String of length
* $csv_terminated_len from the $buffer
* into variable $ch and return the read string $ch
*
* @param string $buffer The original string buffer read from
* csv file
* @param string $ch Partially read "column Separated with"
* string, also used to return after
* reading length equal $csv_terminated_len
* @param int $i Current read counter of buffer string
* @param int $csv_terminated_len The length of "column separated with"
* String
*
* @return string
*/
public function readCsvTerminatedString($buffer, $ch, $i, $csv_terminated_len)
{
for ($j = 0; $j < $csv_terminated_len - 1; $j++) {
$i++;
$ch .= mb_substr($buffer, $i, 1);
}
return $ch;
}
/* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */
/**
* Returns true if the table should be analyzed, false otherwise
*
* @return bool
*/
private function _getAnalyze()
{
return $this->_analyze;
}
/**
* Sets to true if the table should be analyzed, false otherwise
*
* @param bool $analyze status
*
* @return void
*/
private function _setAnalyze($analyze)
{
$this->_analyze = $analyze;
}
}

View File

@ -0,0 +1,173 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* CSV import plugin for phpMyAdmin using LOAD DATA
*
* @package PhpMyAdmin-Import
* @subpackage LDI
*/
namespace PMA\libraries\plugins\import;
use PMA\libraries\properties\options\items\BoolPropertyItem;
use PMA;
use PMA\libraries\plugins\import\AbstractImportCsv;
use PMA\libraries\properties\options\items\TextPropertyItem;
if (!defined('PHPMYADMIN')) {
exit;
}
// We need relations enabled and we work only on database
if ($GLOBALS['plugin_param'] !== 'table') {
$GLOBALS['skip_import'] = true;
return;
}
/**
* Handles the import for the CSV format using load data
*
* @package PhpMyAdmin-Import
* @subpackage LDI
*/
class ImportLdi extends AbstractImportCsv
{
/**
* Constructor
*/
public function __construct()
{
$this->setProperties();
}
/**
* Sets the import plugin properties.
* Called in the constructor.
*
* @return void
*/
protected function setProperties()
{
if ($GLOBALS['cfg']['Import']['ldi_local_option'] == 'auto') {
$GLOBALS['cfg']['Import']['ldi_local_option'] = false;
$result = $GLOBALS['dbi']->tryQuery(
'SELECT @@local_infile;'
);
if ($result != false && $GLOBALS['dbi']->numRows($result) > 0) {
$tmp = $GLOBALS['dbi']->fetchRow($result);
if ($tmp[0] == 'ON') {
$GLOBALS['cfg']['Import']['ldi_local_option'] = true;
}
}
$GLOBALS['dbi']->freeResult($result);
unset($result);
}
$generalOptions = parent::setProperties();
$this->properties->setText('CSV using LOAD DATA');
$this->properties->setExtension('ldi');
$leaf = new TextPropertyItem(
"columns",
__('Column names: ')
);
$generalOptions->addProperty($leaf);
$leaf = new BoolPropertyItem(
"ignore",
__('Do not abort on INSERT error')
);
$generalOptions->addProperty($leaf);
$leaf = new BoolPropertyItem(
"local_option",
__('Use LOCAL keyword')
);
$generalOptions->addProperty($leaf);
}
/**
* Handles the whole import logic
*
* @param array &$sql_data 2-element array with sql data
*
* @return void
*/
public function doImport(&$sql_data = array())
{
global $finished, $import_file, $compression, $charset_conversion, $table;
global $ldi_local_option, $ldi_replace, $ldi_ignore, $ldi_terminated,
$ldi_enclosed, $ldi_escaped, $ldi_new_line, $skip_queries, $ldi_columns;
if ($import_file == 'none'
|| $compression != 'none'
|| $charset_conversion
) {
// We handle only some kind of data!
$GLOBALS['message'] = PMA\libraries\Message::error(
__('This plugin does not support compressed imports!')
);
$GLOBALS['error'] = true;
return;
}
$sql = 'LOAD DATA';
if (isset($ldi_local_option)) {
$sql .= ' LOCAL';
}
$sql .= ' INFILE \'' . $GLOBALS['dbi']->escapeString($import_file)
. '\'';
if (isset($ldi_replace)) {
$sql .= ' REPLACE';
} elseif (isset($ldi_ignore)) {
$sql .= ' IGNORE';
}
$sql .= ' INTO TABLE ' . PMA\libraries\Util::backquote($table);
if (strlen($ldi_terminated) > 0) {
$sql .= ' FIELDS TERMINATED BY \'' . $ldi_terminated . '\'';
}
if (strlen($ldi_enclosed) > 0) {
$sql .= ' ENCLOSED BY \''
. $GLOBALS['dbi']->escapeString($ldi_enclosed) . '\'';
}
if (strlen($ldi_escaped) > 0) {
$sql .= ' ESCAPED BY \''
. $GLOBALS['dbi']->escapeString($ldi_escaped) . '\'';
}
if (strlen($ldi_new_line) > 0) {
if ($ldi_new_line == 'auto') {
$ldi_new_line
= (PMA\libraries\Util::whichCrlf() == "\n")
? '\n'
: '\r\n';
}
$sql .= ' LINES TERMINATED BY \'' . $ldi_new_line . '\'';
}
if ($skip_queries > 0) {
$sql .= ' IGNORE ' . $skip_queries . ' LINES';
$skip_queries = 0;
}
if (strlen($ldi_columns) > 0) {
$sql .= ' (';
$tmp = preg_split('/,( ?)/', $ldi_columns);
$cnt_tmp = count($tmp);
for ($i = 0; $i < $cnt_tmp; $i++) {
if ($i > 0) {
$sql .= ', ';
}
/* Trim also `, if user already included backquoted fields */
$sql .= PMA\libraries\Util::backquote(
trim($tmp[$i], " \t\r\n\0\x0B`")
);
} // end for
$sql .= ')';
}
PMA_importRunQuery($sql, $sql, $sql_data);
PMA_importRunQuery('', '', $sql_data);
$finished = true;
}
}

View File

@ -0,0 +1,598 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* MediaWiki import plugin for phpMyAdmin
*
* @package PhpMyAdmin-Import
* @subpackage MediaWiki
*/
namespace PMA\libraries\plugins\import;
use PMA\libraries\properties\plugins\ImportPluginProperties;
use PMA;
use PMA\libraries\plugins\ImportPlugin;
/**
* Handles the import for the MediaWiki format
*
* @package PhpMyAdmin-Import
* @subpackage MediaWiki
*/
class ImportMediawiki extends ImportPlugin
{
/**
* Whether to analyze tables
*
* @var bool
*/
private $_analyze;
/**
* Constructor
*/
public function __construct()
{
$this->setProperties();
}
/**
* Sets the import plugin properties.
* Called in the constructor.
*
* @return void
*/
protected function setProperties()
{
$this->_setAnalyze(false);
if ($GLOBALS['plugin_param'] !== 'table') {
$this->_setAnalyze(true);
}
$importPluginProperties = new ImportPluginProperties();
$importPluginProperties->setText(__('MediaWiki Table'));
$importPluginProperties->setExtension('txt');
$importPluginProperties->setMimeType('text/plain');
$importPluginProperties->setOptions(array());
$importPluginProperties->setOptionsText(__('Options'));
$this->properties = $importPluginProperties;
}
/**
* Handles the whole import logic
*
* @param array &$sql_data 2-element array with sql data
*
* @return void
*/
public function doImport(&$sql_data = array())
{
global $error, $timeout_passed, $finished;
// Defaults for parser
// The buffer that will be used to store chunks read from the imported file
$buffer = '';
// Used as storage for the last part of the current chunk data
// Will be appended to the first line of the next chunk, if there is one
$last_chunk_line = '';
// Remembers whether the current buffer line is part of a comment
$inside_comment = false;
// Remembers whether the current buffer line is part of a data comment
$inside_data_comment = false;
// Remembers whether the current buffer line is part of a structure comment
$inside_structure_comment = false;
// MediaWiki only accepts "\n" as row terminator
$mediawiki_new_line = "\n";
// Initialize the name of the current table
$cur_table_name = "";
while (!$finished && !$error && !$timeout_passed) {
$data = PMA_importGetNextChunk();
if ($data === false) {
// Subtract data we didn't handle yet and stop processing
$GLOBALS['offset'] -= mb_strlen($buffer);
break;
} elseif ($data === true) {
// Handle rest of buffer
} else {
// Append new data to buffer
$buffer = $data;
unset($data);
// Don't parse string if we're not at the end
// and don't have a new line inside
if (mb_strpos($buffer, $mediawiki_new_line) === false) {
continue;
}
}
// Because of reading chunk by chunk, the first line from the buffer
// contains only a portion of an actual line from the imported file.
// Therefore, we have to append it to the last line from the previous
// chunk. If we are at the first chunk, $last_chunk_line should be empty.
$buffer = $last_chunk_line . $buffer;
// Process the buffer line by line
$buffer_lines = explode($mediawiki_new_line, $buffer);
$full_buffer_lines_count = count($buffer_lines);
// If the reading is not finalised, the final line of the current chunk
// will not be complete
if (! $finished) {
$last_chunk_line = $buffer_lines[--$full_buffer_lines_count];
}
for ($line_nr = 0; $line_nr < $full_buffer_lines_count; ++$line_nr) {
$cur_buffer_line = trim($buffer_lines[$line_nr]);
// If the line is empty, go to the next one
if ($cur_buffer_line === '') {
continue;
}
$first_character = $cur_buffer_line[0];
$matches = array();
// Check beginning of comment
if (!strcmp(mb_substr($cur_buffer_line, 0, 4), "<!--")) {
$inside_comment = true;
continue;
} elseif ($inside_comment) {
// Check end of comment
if (!strcmp(mb_substr($cur_buffer_line, 0, 4), "-->")
) {
// Only data comments are closed. The structure comments
// will be closed when a data comment begins (in order to
// skip structure tables)
if ($inside_data_comment) {
$inside_data_comment = false;
}
// End comments that are not related to table structure
if (!$inside_structure_comment) {
$inside_comment = false;
}
} else {
// Check table name
$match_table_name = array();
if (preg_match(
"/^Table data for `(.*)`$/",
$cur_buffer_line,
$match_table_name
)
) {
$cur_table_name = $match_table_name[1];
$inside_data_comment = true;
$inside_structure_comment
= $this->_mngInsideStructComm(
$inside_structure_comment
);
} elseif (preg_match(
"/^Table structure for `(.*)`$/",
$cur_buffer_line,
$match_table_name
)
) {
// The structure comments will be ignored
$inside_structure_comment = true;
}
}
continue;
} elseif (preg_match('/^\{\|(.*)$/', $cur_buffer_line, $matches)) {
// Check start of table
// This will store all the column info on all rows from
// the current table read from the buffer
$cur_temp_table = array();
// Will be used as storage for the current row in the buffer
// Once all its columns are read, it will be added to
// $cur_temp_table and then it will be emptied
$cur_temp_line = array();
// Helps us differentiate the header columns
// from the normal columns
$in_table_header = false;
// End processing because the current line does not
// contain any column information
} elseif (mb_substr($cur_buffer_line, 0, 2) === '|-'
|| mb_substr($cur_buffer_line, 0, 2) === '|+'
|| mb_substr($cur_buffer_line, 0, 2) === '|}'
) {
// Check begin row or end table
// Add current line to the values storage
if (!empty($cur_temp_line)) {
// If the current line contains header cells
// ( marked with '!' ),
// it will be marked as table header
if ($in_table_header) {
// Set the header columns
$cur_temp_table_headers = $cur_temp_line;
} else {
// Normal line, add it to the table
$cur_temp_table [] = $cur_temp_line;
}
}
// Empty the temporary buffer
$cur_temp_line = array();
// No more processing required at the end of the table
if (mb_substr($cur_buffer_line, 0, 2) === '|}') {
$current_table = array(
$cur_table_name,
$cur_temp_table_headers,
$cur_temp_table,
);
// Import the current table data into the database
$this->_importDataOneTable($current_table, $sql_data);
// Reset table name
$cur_table_name = "";
}
// What's after the row tag is now only attributes
} elseif (($first_character === '|') || ($first_character === '!')) {
// Check cell elements
// Header cells
if ($first_character === '!') {
// Mark as table header, but treat as normal row
$cur_buffer_line = str_replace('!!', '||', $cur_buffer_line);
// Will be used to set $cur_temp_line as table header
$in_table_header = true;
} else {
$in_table_header = false;
}
// Loop through each table cell
$cells = $this->_explodeMarkup($cur_buffer_line);
foreach ($cells as $cell) {
$cell = $this->_getCellData($cell);
// Delete the beginning of the column, if there is one
$cell = trim($cell);
$col_start_chars = array("|", "!");
foreach ($col_start_chars as $col_start_char) {
$cell = $this->_getCellContent($cell, $col_start_char);
}
// Add the cell to the row
$cur_temp_line [] = $cell;
} // foreach $cells
} else {
// If it's none of the above, then the current line has a bad
// format
$message = PMA\libraries\Message::error(
__('Invalid format of mediawiki input on line: <br />%s.')
);
$message->addParam($cur_buffer_line);
$error = true;
}
} // End treating full buffer lines
} // while - finished parsing buffer
}
/**
* Imports data from a single table
*
* @param array $table containing all table info:
* <code>
* $table[0] - string containing table name
* $table[1] - array[] of table headers
* $table[2] - array[][] of table content rows
* </code>
*
* @param array &$sql_data 2-element array with sql data
*
* @global bool $analyze whether to scan for column types
*
* @return void
*/
private function _importDataOneTable($table, &$sql_data)
{
$analyze = $this->_getAnalyze();
if ($analyze) {
// Set the table name
$this->_setTableName($table[0]);
// Set generic names for table headers if they don't exist
$this->_setTableHeaders($table[1], $table[2][0]);
// Create the tables array to be used in PMA_buildSQL()
$tables = array();
$tables [] = array($table[0], $table[1], $table[2]);
// Obtain the best-fit MySQL types for each column
$analyses = array();
$analyses [] = PMA_analyzeTable($tables[0]);
$this->_executeImportTables($tables, $analyses, $sql_data);
}
// Commit any possible data in buffers
PMA_importRunQuery('', '', $sql_data);
}
/**
* Sets the table name
*
* @param string &$table_name reference to the name of the table
*
* @return void
*/
private function _setTableName(&$table_name)
{
if (empty($table_name)) {
$result = $GLOBALS['dbi']->fetchResult('SHOW TABLES');
// todo check if the name below already exists
$table_name = 'TABLE ' . (count($result) + 1);
}
}
/**
* Set generic names for table headers, if they don't exist
*
* @param array &$table_headers reference to the array containing the headers
* of a table
* @param array $table_row array containing the first content row
*
* @return void
*/
private function _setTableHeaders(&$table_headers, $table_row)
{
if (empty($table_headers)) {
// The first table row should contain the number of columns
// If they are not set, generic names will be given (COL 1, COL 2, etc)
$num_cols = count($table_row);
for ($i = 0; $i < $num_cols; ++$i) {
$table_headers [$i] = 'COL ' . ($i + 1);
}
}
}
/**
* Sets the database name and additional options and calls PMA_buildSQL()
* Used in PMA_importDataAllTables() and $this->_importDataOneTable()
*
* @param array &$tables structure:
* array(
* array(table_name, array() column_names, array()()
* rows)
* )
* @param array &$analyses structure:
* $analyses = array(
* array(array() column_types, array() column_sizes)
* )
* @param array &$sql_data 2-element array with sql data
*
* @global string $db name of the database to import in
*
* @return void
*/
private function _executeImportTables(&$tables, &$analyses, &$sql_data)
{
global $db;
// $db_name : The currently selected database name, if applicable
// No backquotes
// $options : An associative array of options
list($db_name, $options) = $this->getDbnameAndOptions($db, 'mediawiki_DB');
// Array of SQL strings
// Non-applicable parameters
$create = null;
// Create and execute necessary SQL statements from data
PMA_buildSQL($db_name, $tables, $analyses, $create, $options, $sql_data);
unset($tables);
unset($analyses);
}
/**
* Replaces all instances of the '||' separator between delimiters
* in a given string
*
* @param string $replace the string to be replaced with
* @param string $subject the text to be replaced
*
* @return string with replacements
*/
private function _delimiterReplace($replace, $subject)
{
// String that will be returned
$cleaned = "";
// Possible states of current character
$inside_tag = false;
$inside_attribute = false;
// Attributes can be declared with either " or '
$start_attribute_character = false;
// The full separator is "||";
// This remembers if the previous character was '|'
$partial_separator = false;
// Parse text char by char
for ($i = 0; $i < strlen($subject); $i++) {
$cur_char = $subject[$i];
// Check for separators
if ($cur_char == '|') {
// If we're not inside a tag, then this is part of a real separator,
// so we append it to the current segment
if (!$inside_attribute) {
$cleaned .= $cur_char;
if ($partial_separator) {
$inside_tag = false;
$inside_attribute = false;
}
} elseif ($partial_separator) {
// If we are inside a tag, we replace the current char with
// the placeholder and append that to the current segment
$cleaned .= $replace;
}
// If the previous character was also '|', then this ends a
// full separator. If not, this may be the beginning of one
$partial_separator = !$partial_separator;
} else {
// If we're inside a tag attribute and the current character is
// not '|', but the previous one was, it means that the single '|'
// was not appended, so we append it now
if ($partial_separator && $inside_attribute) {
$cleaned .= "|";
}
// If the char is different from "|", no separator can be formed
$partial_separator = false;
// any other character should be appended to the current segment
$cleaned .= $cur_char;
if ($cur_char == '<' && !$inside_attribute) {
// start of a tag
$inside_tag = true;
} elseif ($cur_char == '>' && !$inside_attribute) {
// end of a tag
$inside_tag = false;
} elseif (($cur_char == '"' || $cur_char == "'") && $inside_tag) {
// start or end of an attribute
if (!$inside_attribute) {
$inside_attribute = true;
// remember the attribute`s declaration character (" or ')
$start_attribute_character = $cur_char;
} else {
if ($cur_char == $start_attribute_character) {
$inside_attribute = false;
// unset attribute declaration character
$start_attribute_character = false;
}
}
}
}
} // end for each character in $subject
return $cleaned;
}
/**
* Separates a string into items, similarly to explode
* Uses the '||' separator (which is standard in the mediawiki format)
* and ignores any instances of it inside markup tags
* Used in parsing buffer lines containing data cells
*
* @param string $text text to be split
*
* @return array
*/
private function _explodeMarkup($text)
{
$separator = "||";
$placeholder = "\x00";
// Remove placeholder instances
$text = str_replace($placeholder, '', $text);
// Replace instances of the separator inside HTML-like
// tags with the placeholder
$cleaned = $this->_delimiterReplace($placeholder, $text);
// Explode, then put the replaced separators back in
$items = explode($separator, $cleaned);
foreach ($items as $i => $str) {
$items[$i] = str_replace($placeholder, $separator, $str);
}
return $items;
}
/* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */
/**
* Returns true if the table should be analyzed, false otherwise
*
* @return bool
*/
private function _getAnalyze()
{
return $this->_analyze;
}
/**
* Sets to true if the table should be analyzed, false otherwise
*
* @param bool $analyze status
*
* @return void
*/
private function _setAnalyze($analyze)
{
$this->_analyze = $analyze;
}
/**
* Get cell
*
* @param string $cell Cell
*
* @return mixed
*/
private function _getCellData($cell)
{
// A cell could contain both parameters and data
$cell_data = explode('|', $cell, 2);
// A '|' inside an invalid link should not
// be mistaken as delimiting cell parameters
if (mb_strpos($cell_data[0], '[[') === false) {
return $cell;
}
if (count($cell_data) == 1) {
return $cell_data[0];
}
return $cell_data[1];
}
/**
* Manage $inside_structure_comment
*
* @param boolean $inside_structure_comment Value to test
*
* @return bool
*/
private function _mngInsideStructComm($inside_structure_comment)
{
// End ignoring structure rows
if ($inside_structure_comment) {
$inside_structure_comment = false;
}
return $inside_structure_comment;
}
/**
* Get cell content
*
* @param string $cell Cell
* @param string $col_start_char Start char
*
* @return string
*/
private function _getCellContent($cell, $col_start_char)
{
if (mb_strpos($cell, $col_start_char) === 0) {
$cell = trim(mb_substr($cell, 1));
}
return $cell;
}
}

View File

@ -0,0 +1,430 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* OpenDocument Spreadsheet import plugin for phpMyAdmin
*
* @todo Pretty much everything
* @todo Importing of accented characters seems to fail
* @package PhpMyAdmin-Import
* @subpackage ODS
*/
namespace PMA\libraries\plugins\import;
use PMA\libraries\properties\options\items\BoolPropertyItem;
use PMA\libraries\properties\plugins\ImportPluginProperties;
use PMA\libraries\properties\options\groups\OptionsPropertyMainGroup;
use PMA\libraries\properties\options\groups\OptionsPropertyRootGroup;
use PMA;
use PMA\libraries\plugins\ImportPlugin;
use SimpleXMLElement;
/**
* We need way to disable external XML entities processing.
*/
if (!function_exists('libxml_disable_entity_loader')) {
$GLOBALS['skip_import'] = true;
return;
}
/**
* Handles the import for the ODS format
*
* @package PhpMyAdmin-Import
* @subpackage ODS
*/
class ImportOds extends ImportPlugin
{
/**
* Constructor
*/
public function __construct()
{
$this->setProperties();
}
/**
* Sets the import plugin properties.
* Called in the constructor.
*
* @return void
*/
protected function setProperties()
{
$importPluginProperties = new ImportPluginProperties();
$importPluginProperties->setText('OpenDocument Spreadsheet');
$importPluginProperties->setExtension('ods');
$importPluginProperties->setOptionsText(__('Options'));
// create the root group that will be the options field for
// $importPluginProperties
// this will be shown as "Format specific options"
$importSpecificOptions = 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(
"col_names",
__(
'The first line of the file contains the table column names'
. ' <i>(if this is unchecked, the first line will become part'
. ' of the data)</i>'
)
);
$generalOptions->addProperty($leaf);
$leaf = new BoolPropertyItem(
"empty_rows",
__('Do not import empty rows')
);
$generalOptions->addProperty($leaf);
$leaf = new BoolPropertyItem(
"recognize_percentages",
__(
'Import percentages as proper decimals <i>(ex. 12.00% to .12)</i>'
)
);
$generalOptions->addProperty($leaf);
$leaf = new BoolPropertyItem(
"recognize_currency",
__('Import currencies <i>(ex. $5.00 to 5.00)</i>')
);
$generalOptions->addProperty($leaf);
// add the main group to the root group
$importSpecificOptions->addProperty($generalOptions);
// set the options for the import plugin property item
$importPluginProperties->setOptions($importSpecificOptions);
$this->properties = $importPluginProperties;
}
/**
* Handles the whole import logic
*
* @param array &$sql_data 2-element array with sql data
*
* @return void
*/
public function doImport(&$sql_data = array())
{
global $db, $error, $timeout_passed, $finished;
$i = 0;
$len = 0;
$buffer = "";
/**
* Read in the file via PMA_importGetNextChunk so that
* it can process compressed files
*/
while (!($finished && $i >= $len) && !$error && !$timeout_passed) {
$data = PMA_importGetNextChunk();
if ($data === false) {
/* subtract data we didn't handle yet and stop processing */
$GLOBALS['offset'] -= strlen($buffer);
break;
} elseif ($data === true) {
/* Handle rest of buffer */
} else {
/* Append new data to buffer */
$buffer .= $data;
unset($data);
}
}
unset($data);
/**
* Disable loading of external XML entities.
*/
libxml_disable_entity_loader();
/**
* Load the XML string
*
* The option LIBXML_COMPACT is specified because it can
* result in increased performance without the need to
* alter the code in any way. It's basically a freebee.
*/
$xml = @simplexml_load_string($buffer, "SimpleXMLElement", LIBXML_COMPACT);
unset($buffer);
if ($xml === false) {
$sheets = array();
$GLOBALS['message'] = PMA\libraries\Message::error(
__(
'The XML file specified was either malformed or incomplete.'
. ' Please correct the issue and try again.'
)
);
$GLOBALS['error'] = true;
} else {
/** @var SimpleXMLElement $root */
$root = $xml->children('office', true)->{'body'}->{'spreadsheet'};
if (empty($root)) {
$sheets = array();
$GLOBALS['message'] = PMA\libraries\Message::error(
__('Could not parse OpenDocument Spreadsheet!')
);
$GLOBALS['error'] = true;
} else {
$sheets = $root->children('table', true);
}
}
$tables = array();
$max_cols = 0;
$col_count = 0;
$col_names = array();
$tempRow = array();
$tempRows = array();
$rows = array();
/* Iterate over tables */
/** @var SimpleXMLElement $sheet */
foreach ($sheets as $sheet) {
$col_names_in_first_row = isset($_REQUEST['ods_col_names']);
/* Iterate over rows */
/** @var SimpleXMLElement $row */
foreach ($sheet as $row) {
$type = $row->getName();
if (strcmp('table-row', $type)) {
continue;
}
/* Iterate over columns */
$cellCount = count($row);
$a = 0;
/** @var SimpleXMLElement $cell */
foreach ($row as $cell) {
$a++;
$text = $cell->children('text', true);
$cell_attrs = $cell->attributes('office', true);
if (count($text) != 0) {
$attr = $cell->attributes('table', true);
$num_repeat = (int)$attr['number-columns-repeated'];
$num_iterations = $num_repeat ? $num_repeat : 1;
for ($k = 0; $k < $num_iterations; $k++) {
$value = $this->getValue($cell_attrs, $text);
if (!$col_names_in_first_row) {
$tempRow[] = $value;
} else {
// MySQL column names can't end with a space
// character.
$col_names[] = rtrim($value);
}
++$col_count;
}
continue;
}
// skip empty repeats in the last row
if ($a == $cellCount) {
continue;
}
$attr = $cell->attributes('table', true);
$num_null = (int)$attr['number-columns-repeated'];
if ($num_null) {
if (!$col_names_in_first_row) {
for ($i = 0; $i < $num_null; ++$i) {
$tempRow[] = 'NULL';
++$col_count;
}
} else {
for ($i = 0; $i < $num_null; ++$i) {
$col_names[] = PMA_getColumnAlphaName(
$col_count + 1
);
++$col_count;
}
}
} else {
if (!$col_names_in_first_row) {
$tempRow[] = 'NULL';
} else {
$col_names[] = PMA_getColumnAlphaName(
$col_count + 1
);
}
++$col_count;
}
} //Endforeach
/* Find the widest row */
if ($col_count > $max_cols) {
$max_cols = $col_count;
}
/* Don't include a row that is full of NULL values */
if (!$col_names_in_first_row) {
if ($_REQUEST['ods_empty_rows']) {
foreach ($tempRow as $cell) {
if (strcmp('NULL', $cell)) {
$tempRows[] = $tempRow;
break;
}
}
} else {
$tempRows[] = $tempRow;
}
}
$col_count = 0;
$col_names_in_first_row = false;
$tempRow = array();
}
/* Skip over empty sheets */
if (count($tempRows) == 0 || count($tempRows[0]) == 0) {
$col_names = array();
$tempRow = array();
$tempRows = array();
continue;
}
/**
* Fill out each row as necessary to make
* every one exactly as wide as the widest
* row. This included column names.
*/
/* Fill out column names */
for ($i = count($col_names); $i < $max_cols; ++$i) {
$col_names[] = PMA_getColumnAlphaName($i + 1);
}
/* Fill out all rows */
$num_rows = count($tempRows);
for ($i = 0; $i < $num_rows; ++$i) {
for ($j = count($tempRows[$i]); $j < $max_cols; ++$j) {
$tempRows[$i][] = 'NULL';
}
}
/* Store the table name so we know where to place the row set */
$tbl_attr = $sheet->attributes('table', true);
$tables[] = array((string)$tbl_attr['name']);
/* Store the current sheet in the accumulator */
$rows[] = array((string)$tbl_attr['name'], $col_names, $tempRows);
$tempRows = array();
$col_names = array();
$max_cols = 0;
}
unset($tempRow);
unset($tempRows);
unset($col_names);
unset($sheets);
unset($xml);
/**
* Bring accumulated rows into the corresponding table
*/
$num_tables = count($tables);
for ($i = 0; $i < $num_tables; ++$i) {
$num_rows = count($rows);
for ($j = 0; $j < $num_rows; ++$j) {
if (strcmp($tables[$i][TBL_NAME], $rows[$j][TBL_NAME])) {
continue;
}
if (!isset($tables[$i][COL_NAMES])) {
$tables[$i][] = $rows[$j][COL_NAMES];
}
$tables[$i][ROWS] = $rows[$j][ROWS];
}
}
/* No longer needed */
unset($rows);
/* Obtain the best-fit MySQL types for each column */
$analyses = array();
$len = count($tables);
for ($i = 0; $i < $len; ++$i) {
$analyses[] = PMA_analyzeTable($tables[$i]);
}
/**
* string $db_name (no backquotes)
*
* array $table = array(table_name, array() column_names, array()() rows)
* array $tables = array of "$table"s
*
* array $analysis = array(array() column_types, array() column_sizes)
* array $analyses = array of "$analysis"s
*
* array $create = array of SQL strings
*
* array $options = an associative array of options
*/
/* Set database name to the currently selected one, if applicable */
list($db_name, $options) = $this->getDbnameAndOptions($db, 'ODS_DB');
/* Non-applicable parameters */
$create = null;
/* Created and execute necessary SQL statements from data */
PMA_buildSQL($db_name, $tables, $analyses, $create, $options, $sql_data);
unset($tables);
unset($analyses);
/* Commit any possible data in buffers */
PMA_importRunQuery('', '', $sql_data);
}
/**
* Get value
*
* @param array $cell_attrs Cell attributes
* @param array $text Texts
*
* @return float|string
*/
protected function getValue($cell_attrs, $text)
{
if ($_REQUEST['ods_recognize_percentages']
&& !strcmp(
'percentage',
$cell_attrs['value-type']
)
) {
$value = (double)$cell_attrs['value'];
return $value;
} elseif ($_REQUEST['ods_recognize_currency']
&& !strcmp('currency', $cell_attrs['value-type'])
) {
$value = (double)$cell_attrs['value'];
return $value;
} else {
/* We need to concatenate all paragraphs */
$values = array();
foreach ($text as $paragraph) {
$values[] = (string)$paragraph;
}
$value = implode("\n", $values);
return $value;
}
}
}

View File

@ -0,0 +1,333 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* ESRI Shape file import plugin for phpMyAdmin
*
* @package PhpMyAdmin-Import
* @subpackage ESRI_Shape
*/
namespace PMA\libraries\plugins\import;
use PMA\libraries\properties\plugins\ImportPluginProperties;
use PMA;
use PMA\libraries\plugins\ImportPlugin;
use PMA\libraries\gis\GISFactory;
use PMA\libraries\gis\GISMultilinestring;
use PMA\libraries\gis\GISMultipoint;
use PMA\libraries\gis\GISPoint;
use PMA\libraries\gis\GISPolygon;
use PMA\libraries\plugins\import\ShapeFile;
/* Get the ShapeFile class */
require_once 'libraries/bfShapeFiles/ShapeFile.lib.php';
/**
* Handles the import for ESRI Shape files
*
* @package PhpMyAdmin-Import
* @subpackage ESRI_Shape
*/
class ImportShp extends ImportPlugin
{
/**
* Constructor
*/
public function __construct()
{
$this->setProperties();
}
/**
* Sets the import plugin properties.
* Called in the constructor.
*
* @return void
*/
protected function setProperties()
{
$importPluginProperties = new ImportPluginProperties();
$importPluginProperties->setText(__('ESRI Shape File'));
$importPluginProperties->setExtension('shp');
$importPluginProperties->setOptions(array());
$importPluginProperties->setOptionsText(__('Options'));
$this->properties = $importPluginProperties;
}
/**
* Handles the whole import logic
*
* @param array &$sql_data 2-element array with sql data
*
* @return void
*/
public function doImport(&$sql_data = array())
{
global $db, $error, $finished, $compression,
$import_file, $local_import_file, $message;
$GLOBALS['finished'] = false;
$shp = new ShapeFile(1);
// If the zip archive has more than one file,
// get the correct content to the buffer from .shp file.
if ($compression == 'application/zip'
&& PMA_getNoOfFilesInZip($import_file) > 1
) {
$zip_content = PMA_getZipContents($import_file, '/^.*\.shp$/i');
$GLOBALS['import_text'] = $zip_content['data'];
}
$temp_dbf_file = false;
// We need dbase extension to handle .dbf file
if (extension_loaded('dbase')) {
// If we can extract the zip archive to 'TempDir'
// and use the files in it for import
if ($compression == 'application/zip'
&& !empty($GLOBALS['cfg']['TempDir'])
&& @is_writable($GLOBALS['cfg']['TempDir'])
) {
$dbf_file_name = PMA_findFileFromZipArchive(
'/^.*\.dbf$/i',
$import_file
);
// If the corresponding .dbf file is in the zip archive
if ($dbf_file_name) {
// Extract the .dbf file and point to it.
$extracted = PMA_zipExtract(
$import_file,
$dbf_file_name
);
if ($extracted !== false) {
$dbf_file_path = realpath($GLOBALS['cfg']['TempDir'])
. (PMA_IS_WINDOWS ? '\\' : '/')
. PMA_sanitizeFilename($dbf_file_name, true);
$handle = fopen($dbf_file_path, 'wb');
if ($handle !== false) {
fwrite($handle, $extracted);
fclose($handle);
$temp_dbf_file = true;
// Replace the .dbf with .*, as required
// by the bsShapeFiles library.
$file_name = substr(
$dbf_file_path, 0, strlen($dbf_file_path) - 4
) . '.*';
$shp->FileName = $file_name;
}
}
}
} elseif (!empty($local_import_file)
&& !empty($GLOBALS['cfg']['UploadDir'])
&& $compression == 'none'
) {
// If file is in UploadDir, use .dbf file in the same UploadDir
// to load extra data.
// Replace the .shp with .*,
// so the bsShapeFiles library correctly locates .dbf file.
$file_name = mb_substr(
$import_file,
0,
mb_strlen($import_file) - 4
) . '.*';
$shp->FileName = $file_name;
}
}
// Delete the .dbf file extracted to 'TempDir'
if ($temp_dbf_file
&& isset($dbf_file_path)
&& file_exists($dbf_file_path)
) {
unlink($dbf_file_path);
}
// Load data
$shp->loadFromFile('');
if ($shp->lastError != "") {
$error = true;
$message = PMA\libraries\Message::error(
__('There was an error importing the ESRI shape file: "%s".')
);
$message->addParam($shp->lastError);
return;
}
$esri_types = array(
0 => 'Null Shape',
1 => 'Point',
3 => 'PolyLine',
5 => 'Polygon',
8 => 'MultiPoint',
11 => 'PointZ',
13 => 'PolyLineZ',
15 => 'PolygonZ',
18 => 'MultiPointZ',
21 => 'PointM',
23 => 'PolyLineM',
25 => 'PolygonM',
28 => 'MultiPointM',
31 => 'MultiPatch',
);
switch ($shp->shapeType) {
// ESRI Null Shape
case 0:
break;
// ESRI Point
case 1:
$gis_type = 'point';
break;
// ESRI PolyLine
case 3:
$gis_type = 'multilinestring';
break;
// ESRI Polygon
case 5:
$gis_type = 'multipolygon';
break;
// ESRI MultiPoint
case 8:
$gis_type = 'multipoint';
break;
default:
$error = true;
if (!isset($esri_types[$shp->shapeType])) {
$message = PMA\libraries\Message::error(
__(
'You tried to import an invalid file or the imported file'
. ' contains invalid data!'
)
);
} else {
$message = PMA\libraries\Message::error(
__('MySQL Spatial Extension does not support ESRI type "%s".')
);
$message->addParam($esri_types[$shp->shapeType]);
}
return;
}
if (isset($gis_type)) {
/** @var GISMultilinestring|\PMA\libraries\gis\GISMultipoint|\PMA\libraries\gis\GISPoint|GISPolygon $gis_obj */
$gis_obj = GISFactory::factory($gis_type);
} else {
$gis_obj = null;
}
$num_rows = count($shp->records);
// If .dbf file is loaded, the number of extra data columns
$num_data_cols = isset($shp->DBFHeader) ? count($shp->DBFHeader) : 0;
$rows = array();
$col_names = array();
if ($num_rows != 0) {
foreach ($shp->records as $record) {
$tempRow = array();
if ($gis_obj == null) {
$tempRow[] = null;
} else {
$tempRow[] = "GeomFromText('"
. $gis_obj->getShape($record->SHPData) . "')";
}
if (isset($shp->DBFHeader)) {
foreach ($shp->DBFHeader as $c) {
$cell = trim($record->DBFData[$c[0]]);
if (!strcmp($cell, '')) {
$cell = 'NULL';
}
$tempRow[] = $cell;
}
}
$rows[] = $tempRow;
}
}
if (count($rows) == 0) {
$error = true;
$message = PMA\libraries\Message::error(
__('The imported file does not contain any data!')
);
return;
}
// Column names for spatial column and the rest of the columns,
// if they are available
$col_names[] = 'SPATIAL';
for ($n = 0; $n < $num_data_cols; $n++) {
$col_names[] = $shp->DBFHeader[$n][0];
}
// Set table name based on the number of tables
if (mb_strlen($db)) {
$result = $GLOBALS['dbi']->fetchResult('SHOW TABLES');
$table_name = 'TABLE ' . (count($result) + 1);
} else {
$table_name = 'TBL_NAME';
}
$tables = array(array($table_name, $col_names, $rows));
// Use data from shape file to chose best-fit MySQL types for each column
$analyses = array();
$analyses[] = PMA_analyzeTable($tables[0]);
$table_no = 0;
$spatial_col = 0;
$analyses[$table_no][TYPES][$spatial_col] = GEOMETRY;
$analyses[$table_no][FORMATTEDSQL][$spatial_col] = true;
// Set database name to the currently selected one, if applicable
if (mb_strlen($db)) {
$db_name = $db;
$options = array('create_db' => false);
} else {
$db_name = 'SHP_DB';
$options = null;
}
// Created and execute necessary SQL statements from data
$null_param = null;
PMA_buildSQL($db_name, $tables, $analyses, $null_param, $options, $sql_data);
unset($tables);
unset($analyses);
$finished = true;
$error = false;
// Commit any possible data in buffers
PMA_importRunQuery('', '', $sql_data);
}
/**
* Returns specified number of bytes from the buffer.
* Buffer automatically fetches next chunk of data when the buffer
* falls short.
* Sets $eof when $GLOBALS['finished'] is set and the buffer falls short.
*
* @param int $length number of bytes
*
* @return string
*/
public static function readFromBuffer($length)
{
global $buffer, $eof;
if (strlen($buffer) < $length) {
if ($GLOBALS['finished']) {
$eof = true;
} else {
$buffer .= PMA_importGetNextChunk();
}
}
$result = substr($buffer, 0, $length);
$buffer = substr($buffer, $length);
return $result;
}
}

View File

@ -0,0 +1,198 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* SQL import plugin for phpMyAdmin
*
* @package PhpMyAdmin-Import
* @subpackage SQL
*/
namespace PMA\libraries\plugins\import;
use PMA\libraries\properties\options\items\BoolPropertyItem;
use PMA\libraries\properties\plugins\ImportPluginProperties;
use PMA\libraries\properties\options\groups\OptionsPropertyMainGroup;
use PMA\libraries\properties\options\groups\OptionsPropertyRootGroup;
use PMA;
use PMA\libraries\plugins\ImportPlugin;
use PMA\libraries\properties\options\items\SelectPropertyItem;
use SqlParser;
/**
* Handles the import for the SQL format
*
* @package PhpMyAdmin-Import
* @subpackage SQL
*/
class ImportSql extends ImportPlugin
{
/**
* Constructor
*/
public function __construct()
{
$this->setProperties();
}
/**
* Sets the import plugin properties.
* Called in the constructor.
*
* @return void
*/
protected function setProperties()
{
$importPluginProperties = new ImportPluginProperties();
$importPluginProperties->setText('SQL');
$importPluginProperties->setExtension('sql');
$importPluginProperties->setOptionsText(__('Options'));
$compats = $GLOBALS['dbi']->getCompatibilities();
if (count($compats) > 0) {
$values = array();
foreach ($compats as $val) {
$values[$val] = $val;
}
// create the root group that will be the options field for
// $importPluginProperties
// this will be shown as "Format specific options"
$importSpecificOptions = 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 SelectPropertyItem(
"compatibility",
__('SQL compatibility mode:')
);
$leaf->setValues($values);
$leaf->setDoc(
array(
'manual_MySQL_Database_Administration',
'Server_SQL_mode',
)
);
$generalOptions->addProperty($leaf);
$leaf = new BoolPropertyItem(
"no_auto_value_on_zero",
__('Do not use <code>AUTO_INCREMENT</code> for zero values')
);
$leaf->setDoc(
array(
'manual_MySQL_Database_Administration',
'Server_SQL_mode',
'sqlmode_no_auto_value_on_zero',
)
);
$generalOptions->addProperty($leaf);
// add the main group to the root group
$importSpecificOptions->addProperty($generalOptions);
// set the options for the import plugin property item
$importPluginProperties->setOptions($importSpecificOptions);
}
$this->properties = $importPluginProperties;
}
/**
* Handles the whole import logic
*
* @param array &$sql_data 2-element array with sql data
*
* @return void
*/
public function doImport(&$sql_data = array())
{
global $error, $timeout_passed;
// Handle compatibility options.
$this->_setSQLMode($GLOBALS['dbi'], $_REQUEST);
$bq = new SqlParser\Utils\BufferedQuery();
if (isset($_POST['sql_delimiter'])) {
$bq->setDelimiter($_POST['sql_delimiter']);
}
/**
* Will be set in PMA_importGetNextChunk().
*
* @global bool $GLOBALS ['finished']
*/
$GLOBALS['finished'] = false;
while ((!$error) && (!$timeout_passed)) {
// Getting the first statement, the remaining data and the last
// delimiter.
$statement = $bq->extract();
// If there is no full statement, we are looking for more data.
if (empty($statement)) {
// Importing new data.
$newData = PMA_importGetNextChunk();
// Subtract data we didn't handle yet and stop processing.
if ($newData === false) {
$GLOBALS['offset'] -= mb_strlen($bq->query);
break;
}
// Checking if the input buffer has finished.
if ($newData === true) {
$GLOBALS['finished'] = true;
break;
}
// Convert CR (but not CRLF) to LF otherwise all queries may
// not get executed on some platforms.
$bq->query .= preg_replace("/\r($|[^\n])/", "\n$1", $newData);
continue;
}
// Executing the query.
PMA_importRunQuery($statement, $statement, $sql_data);
}
// Extracting remaining statements.
while ((!$error) && (!$timeout_passed) && (!empty($bq->query))) {
$statement = $bq->extract(true);
if (!empty($statement)) {
PMA_importRunQuery($statement, $statement, $sql_data);
}
}
// Finishing.
PMA_importRunQuery('', '', $sql_data);
}
/**
* Handle compatibility options
*
* @param PMA\libraries\DatabaseInterface $dbi Database interface
* @param array $request Request array
*
* @return void
*/
private function _setSQLMode($dbi, $request)
{
$sql_modes = array();
if (isset($request['sql_compatibility'])
&& 'NONE' != $request['sql_compatibility']
) {
$sql_modes[] = $request['sql_compatibility'];
}
if (isset($request['sql_no_auto_value_on_zero'])) {
$sql_modes[] = 'NO_AUTO_VALUE_ON_ZERO';
}
if (count($sql_modes) > 0) {
$dbi->tryQuery(
'SET SQL_MODE="' . implode(',', $sql_modes) . '"'
);
}
}
}

View File

@ -0,0 +1,378 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* XML import plugin for phpMyAdmin
*
* @todo Improve efficiency
* @package PhpMyAdmin-Import
* @subpackage XML
*/
namespace PMA\libraries\plugins\import;
use PMA\libraries\properties\plugins\ImportPluginProperties;
use PMA;
use PMA\libraries\plugins\ImportPlugin;
use SimpleXMLElement;
/**
* We need way to disable external XML entities processing.
*/
if (!function_exists('libxml_disable_entity_loader')) {
$GLOBALS['skip_import'] = true;
return;
}
/**
* Handles the import for the XML format
*
* @package PhpMyAdmin-Import
* @subpackage XML
*/
class ImportXml extends ImportPlugin
{
/**
* Constructor
*/
public function __construct()
{
$this->setProperties();
}
/**
* Sets the import plugin properties.
* Called in the constructor.
*
* @return void
*/
protected function setProperties()
{
$importPluginProperties = new ImportPluginProperties();
$importPluginProperties->setText(__('XML'));
$importPluginProperties->setExtension('xml');
$importPluginProperties->setMimeType('text/xml');
$importPluginProperties->setOptions(array());
$importPluginProperties->setOptionsText(__('Options'));
$this->properties = $importPluginProperties;
}
/**
* Handles the whole import logic
*
* @param array &$sql_data 2-element array with sql data
*
* @return void
*/
public function doImport(&$sql_data = array())
{
global $error, $timeout_passed, $finished, $db;
$i = 0;
$len = 0;
$buffer = "";
/**
* Read in the file via PMA_importGetNextChunk so that
* it can process compressed files
*/
while (!($finished && $i >= $len) && !$error && !$timeout_passed) {
$data = PMA_importGetNextChunk();
if ($data === false) {
/* subtract data we didn't handle yet and stop processing */
$GLOBALS['offset'] -= strlen($buffer);
break;
} elseif ($data === true) {
/* Handle rest of buffer */
} else {
/* Append new data to buffer */
$buffer .= $data;
unset($data);
}
}
unset($data);
/**
* Disable loading of external XML entities.
*/
libxml_disable_entity_loader();
/**
* Load the XML string
*
* The option LIBXML_COMPACT is specified because it can
* result in increased performance without the need to
* alter the code in any way. It's basically a freebee.
*/
$xml = @simplexml_load_string($buffer, "SimpleXMLElement", LIBXML_COMPACT);
unset($buffer);
/**
* The XML was malformed
*/
if ($xml === false) {
PMA\libraries\Message::error(
__(
'The XML file specified was either malformed or incomplete.'
. ' Please correct the issue and try again.'
)
)
->display();
unset($xml);
$GLOBALS['finished'] = false;
return;
}
/**
* Table accumulator
*/
$tables = array();
/**
* Row accumulator
*/
$rows = array();
/**
* Temp arrays
*/
$tempRow = array();
$tempCells = array();
/**
* CREATE code included (by default: no)
*/
$struct_present = false;
/**
* Analyze the data in each table
*/
$namespaces = $xml->getNameSpaces(true);
/**
* Get the database name, collation and charset
*/
$db_attr = $xml->children($namespaces['pma'])
->{'structure_schemas'}->{'database'};
if ($db_attr instanceof SimpleXMLElement) {
$db_attr = $db_attr->attributes();
$db_name = (string)$db_attr['name'];
$collation = (string)$db_attr['collation'];
$charset = (string)$db_attr['charset'];
} else {
/**
* If the structure section is not present
* get the database name from the data section
*/
$db_attr = $xml->children()
->attributes();
$db_name = (string)$db_attr['name'];
$collation = null;
$charset = null;
}
/**
* The XML was malformed
*/
if ($db_name === null) {
PMA\libraries\Message::error(
__(
'The XML file specified was either malformed or incomplete.'
. ' Please correct the issue and try again.'
)
)
->display();
unset($xml);
$GLOBALS['finished'] = false;
return;
}
/**
* Retrieve the structure information
*/
if (isset($namespaces['pma'])) {
/**
* Get structures for all tables
*
* @var SimpleXMLElement $struct
*/
$struct = $xml->children($namespaces['pma']);
$create = array();
/** @var SimpleXMLElement $val1 */
foreach ($struct as $val1) {
/** @var SimpleXMLElement $val2 */
foreach ($val1 as $val2) {
// Need to select the correct database for the creation of
// tables, views, triggers, etc.
/**
* @todo Generating a USE here blocks importing of a table
* into another database.
*/
$attrs = $val2->attributes();
$create[] = "USE "
. PMA\libraries\Util::backquote(
$attrs["name"]
);
foreach ($val2 as $val3) {
/**
* Remove the extra cosmetic spacing
*/
$val3 = str_replace(" ", "", (string)$val3);
$create[] = $val3;
}
}
}
$struct_present = true;
}
/**
* Move down the XML tree to the actual data
*/
$xml = $xml->children()
->children();
$data_present = false;
/**
* Only attempt to analyze/collect data if there is data present
*/
if ($xml && @count($xml->children())) {
$data_present = true;
/**
* Process all database content
*/
foreach ($xml as $v1) {
$tbl_attr = $v1->attributes();
$isInTables = false;
$num_tables = count($tables);
for ($i = 0; $i < $num_tables; ++$i) {
if (!strcmp($tables[$i][TBL_NAME], (string)$tbl_attr['name'])) {
$isInTables = true;
break;
}
}
if (!$isInTables) {
$tables[] = array((string)$tbl_attr['name']);
}
foreach ($v1 as $v2) {
$row_attr = $v2->attributes();
if (!array_search((string)$row_attr['name'], $tempRow)) {
$tempRow[] = (string)$row_attr['name'];
}
$tempCells[] = (string)$v2;
}
$rows[] = array((string)$tbl_attr['name'], $tempRow, $tempCells);
$tempRow = array();
$tempCells = array();
}
unset($tempRow);
unset($tempCells);
unset($xml);
/**
* Bring accumulated rows into the corresponding table
*/
$num_tables = count($tables);
for ($i = 0; $i < $num_tables; ++$i) {
$num_rows = count($rows);
for ($j = 0; $j < $num_rows; ++$j) {
if (!strcmp($tables[$i][TBL_NAME], $rows[$j][TBL_NAME])) {
if (!isset($tables[$i][COL_NAMES])) {
$tables[$i][] = $rows[$j][COL_NAMES];
}
$tables[$i][ROWS][] = $rows[$j][ROWS];
}
}
}
unset($rows);
if (!$struct_present) {
$analyses = array();
$len = count($tables);
for ($i = 0; $i < $len; ++$i) {
$analyses[] = PMA_analyzeTable($tables[$i]);
}
}
}
unset($xml);
unset($tempCells);
unset($rows);
/**
* Only build SQL from data if there is data present
*/
if ($data_present) {
/**
* Set values to NULL if they were not present
* to maintain PMA_buildSQL() call integrity
*/
if (!isset($analyses)) {
$analyses = null;
if (!$struct_present) {
$create = null;
}
}
}
/**
* string $db_name (no backquotes)
*
* array $table = array(table_name, array() column_names, array()() rows)
* array $tables = array of "$table"s
*
* array $analysis = array(array() column_types, array() column_sizes)
* array $analyses = array of "$analysis"s
*
* array $create = array of SQL strings
*
* array $options = an associative array of options
*/
/* Set database name to the currently selected one, if applicable */
if (strlen($db)) {
/* Override the database name in the XML file, if one is selected */
$db_name = $db;
$options = array('create_db' => false);
} else {
if ($db_name === null) {
$db_name = 'XML_DB';
}
/* Set database collation/charset */
$options = array(
'db_collation' => $collation,
'db_charset' => $charset,
);
}
/* Created and execute necessary SQL statements from data */
PMA_buildSQL($db_name, $tables, $analyses, $create, $options, $sql_data);
unset($analyses);
unset($tables);
unset($create);
/* Commit any possible data in buffers */
PMA_importRunQuery('', '', $sql_data);
}
}

View File

@ -0,0 +1,155 @@
This directory holds import plugins for phpMyAdmin. Any new plugin should
basically follow the structure presented here. The messages must use our
gettext mechanism, see https://wiki.phpmyadmin.net/pma/Gettext_for_developers.
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* [Name] import plugin for phpMyAdmin
*
* @package PhpMyAdmin-Import
* @subpackage [Name]
*/
if (! defined('PHPMYADMIN')) {
exit;
}
/* Get the import interface */
require_once 'libraries/plugins/PMA\libraries\plugins\ImportPlugin.class.php';
/**
* Handles the import for the [Name] format
*
* @package PhpMyAdmin-Import
*/
class Import[Name] extends PMA\libraries\plugins\ImportPlugin
{
/**
* optional - declare variables and descriptions
*
* @var type
*/
private $_myOptionalVariable;
/**
* Constructor
*/
public function __construct()
{
$this->setProperties();
}
/**
* Sets the import plugin properties.
* Called in the constructor.
*
* @return void
*/
protected function setProperties()
{
$importPluginProperties = new PMA\libraries\properties\plugins\ImportPluginProperties();
$importPluginProperties->setText('[name]'); // the name of your plug-in
$importPluginProperties->setExtension('[ext]'); // extension this plug-in can handle
$importPluginProperties->setOptionsText(__('Options'));
// create the root group that will be the options field for
// $importPluginProperties
// this will be shown as "Format specific options"
$importSpecificOptions = new
PMA\libraries\properties\options\groups\OptionsPropertyRootGroup(
"Format Specific Options"
);
// general options main group
$generalOptions = new PMA\libraries\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 PMA\libraries\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
$importSpecificOptions->addProperty($generalOptions);
// set the options for the import plugin property item
$importPluginProperties->setOptions($importSpecificOptions);
$this->properties = $importPluginProperties;
}
/**
* Handles the whole import logic
*
* @param array &$sql_data 2-element array with sql data
*
* @return void
*/
public function doImport(&$sql_data = array())
{
// get globals (others are optional)
global $error, $timeout_passed, $finished;
$buffer = '';
while (! ($finished && $i >= $len) && ! $error && ! $timeout_passed) {
$data = PMA_importGetNextChunk();
if ($data === false) {
// subtract data we didn't handle yet and stop processing
$GLOBALS['offset'] -= strlen($buffer);
break;
} elseif ($data === true) {
// Handle rest of buffer
} else {
// Append new data to buffer
$buffer .= $data;
}
// PARSE $buffer here, post sql queries using:
PMA_importRunQuery($sql, $verbose_sql_with_comments, $sql_data);
} // End of import loop
// Commit any possible data in buffers
PMA_importRunQuery('', '', $sql_data);
}
// 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;
}
}
?>

View File

@ -0,0 +1,100 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* This class extends ShapeFile class to cater the following phpMyAdmin
* specific requirements.
*
* @package PhpMyAdmin-Import
* @subpackage ESRI_Shape
*/
namespace PMA\libraries\plugins\import;
/**
* 1) To load data from .dbf file only when the dBase extension is available.
* 2) To use PMA_importGetNextChunk() functionality to read data, rather than
* reading directly from a file. Using
* PMA\libraries\plugins\import\ImportShp::readFromBuffer() in place of fread().
* This makes it possible to use compressions.
*
* @package PhpMyAdmin-Import
* @subpackage ESRI_Shape
*/
class ShapeFile extends \ShapeFile
{
/**
* Returns whether the 'dbase' extension is loaded
*
* @return boolean whether the 'dbase' extension is loaded
*/
private function _isDbaseLoaded()
{
return extension_loaded('dbase');
}
/**
* Loads ESRI shape data from the imported file
*
* @param string $FileName not used, it's here only to match the method
* signature of the method being overridden
*
* @return void
* @see ShapeFile::loadFromFile()
*/
public function loadFromFile($FileName)
{
$this->_loadHeaders();
$this->_loadRecords();
if ($this->_isDbaseLoaded()) {
$this->_closeDBFFile();
}
}
/**
* Loads metadata from the ESRI shape file header
*
* @return void
* @see ShapeFile::_loadHeaders()
*/
public function _loadHeaders()
{
ImportShp::readFromBuffer(24);
$this->fileLength = loadData("N", ImportShp::readFromBuffer(4));
ImportShp::readFromBuffer(4);
$this->shapeType = loadData("V", ImportShp::readFromBuffer(4));
$this->boundingBox = array();
$this->boundingBox["xmin"] = loadData("d", ImportShp::readFromBuffer(8));
$this->boundingBox["ymin"] = loadData("d", ImportShp::readFromBuffer(8));
$this->boundingBox["xmax"] = loadData("d", ImportShp::readFromBuffer(8));
$this->boundingBox["ymax"] = loadData("d", ImportShp::readFromBuffer(8));
if ($this->_isDbaseLoaded() && $this->_openDBFFile()) {
$this->DBFHeader = $this->_loadDBFHeader();
}
}
/**
* Loads geometry data from the ESRI shape file
*
* @return boolean|void
* @see ShapeFile::_loadRecords()
*/
public function _loadRecords()
{
global $eof;
ImportShp::readFromBuffer(32);
while (true) {
$record = new ShapeRecord(-1);
$record->loadFromFile($this->SHPFile, $this->DBFFile);
if ($record->lastError != "") {
return false;
}
if ($eof) {
break;
}
$this->records[] = $record;
}
}
}

View File

@ -0,0 +1,159 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* This class extends ShapeRecord class to cater the following phpMyAdmin
* specific requirements.
*
* @package PhpMyAdmin-Import
* @subpackage ESRI_Shape
*/
namespace PMA\libraries\plugins\import;
/**
* 1) To load data from .dbf file only when the dBase extension is available.
* 2) To use PMA_importGetNextChunk() functionality to read data, rather than
* reading directly from a file. Using
* PMA\libraries\plugins\import\ImportShp::readFromBuffer() in place of fread().
* This makes it possible to use compressions.
*
* @package PhpMyAdmin-Import
* @subpackage ESRI_Shape
*/
class ShapeRecord extends \ShapeRecord
{
/**
* Loads a geometry data record from the file
*
* @param object &$SHPFile .shp file
* @param object &$DBFFile .dbf file
*
* @return void
* @see ShapeRecord::loadFromFile()
*/
public function loadFromFile(&$SHPFile, &$DBFFile)
{
$this->DBFFile = $DBFFile;
$this->_loadHeaders();
switch ($this->shapeType) {
case 0:
$this->_loadNullRecord();
break;
case 1:
$this->_loadPointRecord();
break;
case 3:
$this->_loadPolyLineRecord();
break;
case 5:
$this->_loadPolygonRecord();
break;
case 8:
$this->_loadMultiPointRecord();
break;
default:
$this->setError(
sprintf(
__("Geometry type '%s' is not supported by MySQL."),
$this->shapeType
)
);
break;
}
if (extension_loaded('dbase') && isset($this->DBFFile)) {
$this->_loadDBFData();
}
}
/**
* Loads metadata from the ESRI shape record header
*
* @return void
* @see ShapeRecord::_loadHeaders()
*/
public function _loadHeaders()
{
$this->recordNumber = loadData("N", ImportShp::readFromBuffer(4));
ImportShp::readFromBuffer(4);
$this->shapeType = loadData("V", ImportShp::readFromBuffer(4));
}
/**
* Loads data from a point record
*
* @return array
* @see ShapeRecord::_loadPoint()
*/
public function _loadPoint()
{
$data = array();
$data["x"] = loadData("d", ImportShp::readFromBuffer(8));
$data["y"] = loadData("d", ImportShp::readFromBuffer(8));
return $data;
}
/**
* Loads data from a multipoint record
*
* @return void
* @see ShapeRecord::_loadMultiPointRecord()
*/
public function _loadMultiPointRecord()
{
$this->SHPData = array();
$this->SHPData["xmin"] = loadData("d", ImportShp::readFromBuffer(8));
$this->SHPData["ymin"] = loadData("d", ImportShp::readFromBuffer(8));
$this->SHPData["xmax"] = loadData("d", ImportShp::readFromBuffer(8));
$this->SHPData["ymax"] = loadData("d", ImportShp::readFromBuffer(8));
$this->SHPData["numpoints"] = loadData("V", ImportShp::readFromBuffer(4));
for ($i = 0; $i <= $this->SHPData["numpoints"]; $i++) {
$this->SHPData["points"][] = $this->_loadPoint();
}
}
/**
* Loads data from a polyline record
*
* @return void
* @see ShapeRecord::_loadPolyLineRecord()
*/
public function _loadPolyLineRecord()
{
$this->SHPData = array();
$this->SHPData["xmin"] = loadData("d", ImportShp::readFromBuffer(8));
$this->SHPData["ymin"] = loadData("d", ImportShp::readFromBuffer(8));
$this->SHPData["xmax"] = loadData("d", ImportShp::readFromBuffer(8));
$this->SHPData["ymax"] = loadData("d", ImportShp::readFromBuffer(8));
$this->SHPData["numparts"] = loadData("V", ImportShp::readFromBuffer(4));
$this->SHPData["numpoints"] = loadData("V", ImportShp::readFromBuffer(4));
for ($i = 0; $i < $this->SHPData["numparts"]; $i++) {
$this->SHPData["parts"][$i] = loadData(
"V",
ImportShp::readFromBuffer(4)
);
}
$readPoints = 0;
foreach ($this->SHPData["parts"] as &$partData) {
if (!isset($partData["points"])
|| !is_array($partData["points"])
) {
$partData = array(
'points' => array()
);
}
while (!in_array($readPoints, $this->SHPData["parts"])
&& ($readPoints < ($this->SHPData["numpoints"]))
) {
$partData["points"][] = $this->_loadPoint();
$readPoints++;
}
}
}
}

View File

@ -0,0 +1,80 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Provides upload functionalities for the import plugins
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins\import\upload;
use PMA\libraries\plugins\UploadInterface;
/**
* Implementation for the APC extension
*
* @package PhpMyAdmin
*/
class UploadApc implements UploadInterface
{
/**
* Gets the specific upload ID Key
*
* @return string ID Key
*/
public static function getIdKey()
{
return 'APC_UPLOAD_PROGRESS';
}
/**
* Returns upload status.
*
* This is implementation for APC extension.
*
* @param string $id upload id
*
* @return array|null
*/
public static function getUploadStatus($id)
{
global $SESSION_KEY;
if (trim($id) == "") {
return null;
}
if (!array_key_exists($id, $_SESSION[$SESSION_KEY])) {
$_SESSION[$SESSION_KEY][$id] = array(
'id' => $id,
'finished' => false,
'percent' => 0,
'total' => 0,
'complete' => 0,
'plugin' => UploadApc::getIdKey(),
);
}
$ret = $_SESSION[$SESSION_KEY][$id];
if (!PMA_Import_apcCheck() || $ret['finished']) {
return $ret;
}
$status = apc_fetch('upload_' . $id);
if ($status) {
$ret['finished'] = (bool)$status['done'];
$ret['total'] = $status['total'];
$ret['complete'] = $status['current'];
if ($ret['total'] > 0) {
$ret['percent'] = $ret['complete'] / $ret['total'] * 100;
}
if ($ret['percent'] == 100) {
$ret['finished'] = (bool)true;
}
$_SESSION[$SESSION_KEY][$id] = $ret;
}
return $ret;
}
}

View File

@ -0,0 +1,60 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Provides upload functionalities for the import plugins
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins\import\upload;
use PMA\libraries\plugins\UploadInterface;
/**
* Implementation for no plugin
*
* @package PhpMyAdmin
*/
class UploadNoplugin implements UploadInterface
{
/**
* Gets the specific upload ID Key
*
* @return string ID Key
*/
public static function getIdKey()
{
return 'noplugin';
}
/**
* Returns upload status.
*
* This is implementation when no webserver support exists,
* so it returns just zeroes.
*
* @param string $id upload id
*
* @return array|null
*/
public static function getUploadStatus($id)
{
global $SESSION_KEY;
if (trim($id) == "") {
return null;
}
if (!array_key_exists($id, $_SESSION[$SESSION_KEY])) {
$_SESSION[$SESSION_KEY][$id] = array(
'id' => $id,
'finished' => false,
'percent' => 0,
'total' => 0,
'complete' => 0,
'plugin' => UploadNoplugin::getIdKey(),
);
}
$ret = $_SESSION[$SESSION_KEY][$id];
return $ret;
}
}

View File

@ -0,0 +1,91 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Provides upload functionalities for the import plugins
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins\import\upload;
use PMA\libraries\plugins\UploadInterface;
/**
* Implementation for upload progress
*
* @package PhpMyAdmin
*/
class UploadProgress implements UploadInterface
{
/**
* Gets the specific upload ID Key
*
* @return string ID Key
*/
public static function getIdKey()
{
return 'UPLOAD_IDENTIFIER';
}
/**
* Returns upload status.
*
* This is implementation for upload progress
*
* @param string $id upload id
*
* @return array|null
*/
public static function getUploadStatus($id)
{
global $SESSION_KEY;
if (trim($id) == "") {
return null;
}
if (!array_key_exists($id, $_SESSION[$SESSION_KEY])) {
$_SESSION[$SESSION_KEY][$id] = array(
'id' => $id,
'finished' => false,
'percent' => 0,
'total' => 0,
'complete' => 0,
'plugin' => UploadProgress::getIdKey(),
);
}
$ret = $_SESSION[$SESSION_KEY][$id];
if (!PMA_Import_progressCheck() || $ret['finished']) {
return $ret;
}
$status = uploadprogress_get_info($id);
if ($status) {
if ($status['bytes_uploaded'] == $status['bytes_total']) {
$ret['finished'] = true;
} else {
$ret['finished'] = false;
}
$ret['total'] = $status['bytes_total'];
$ret['complete'] = $status['bytes_uploaded'];
if ($ret['total'] > 0) {
$ret['percent'] = $ret['complete'] / $ret['total'] * 100;
}
} else {
$ret = array(
'id' => $id,
'finished' => true,
'percent' => 100,
'total' => $ret['total'],
'complete' => $ret['total'],
'plugin' => UploadProgress::getIdKey(),
);
}
$_SESSION[$SESSION_KEY][$id] = $ret;
return $ret;
}
}

View File

@ -0,0 +1,92 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Provides upload functionalities for the import plugins
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins\import\upload;
use PMA\libraries\plugins\UploadInterface;
/**
* Implementation for session
*
* @package PhpMyAdmin
*/
class UploadSession implements UploadInterface
{
/**
* Gets the specific upload ID Key
*
* @return string ID Key
*/
public static function getIdKey()
{
return ini_get('session.upload_progress.name');
}
/**
* Returns upload status.
*
* This is implementation for session.upload_progress in PHP 5.4+.
*
* @param string $id upload id
*
* @return array|null
*/
public static function getUploadStatus($id)
{
global $SESSION_KEY;
if (trim($id) == '') {
return null;
}
if (!array_key_exists($id, $_SESSION[$SESSION_KEY])) {
$_SESSION[$SESSION_KEY][$id] = array(
'id' => $id,
'finished' => false,
'percent' => 0,
'total' => 0,
'complete' => 0,
'plugin' => UploadSession::getIdKey(),
);
}
$ret = $_SESSION[$SESSION_KEY][$id];
if (!PMA_Import_sessionCheck() || $ret['finished']) {
return $ret;
}
$status = false;
$sessionkey = ini_get('session.upload_progress.prefix') . $id;
if (isset($_SESSION[$sessionkey])) {
$status = $_SESSION[$sessionkey];
}
if ($status) {
$ret['finished'] = $status['done'];
$ret['total'] = $status['content_length'];
$ret['complete'] = $status['bytes_processed'];
if ($ret['total'] > 0) {
$ret['percent'] = $ret['complete'] / $ret['total'] * 100;
}
} else {
$ret = array(
'id' => $id,
'finished' => true,
'percent' => 100,
'total' => $ret['total'],
'complete' => $ret['total'],
'plugin' => UploadSession::getIdKey(),
);
}
$_SESSION[$SESSION_KEY][$id] = $ret;
return $ret;
}
}

View File

@ -0,0 +1,301 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Contains PMA\libraries\plugins\schema\ExportRelationSchema class which is
* inherited by all schema classes.
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins\schema;
use PMA;
/**
* This class is inherited by all schema classes
* It contains those methods which are common in them
* it works like factory pattern
*
* @package PhpMyAdmin
*/
class ExportRelationSchema
{
/**
* Constructor.
*
* @param string $db database name
* @param object $diagram schema diagram
*/
public function __construct($db, $diagram)
{
$this->db = $db;
$this->diagram = $diagram;
$this->setPageNumber($_REQUEST['page_number']);
$this->setOffline(isset($_REQUEST['offline_export']));
}
protected $db;
protected $diagram;
protected $showColor;
protected $tableDimension;
protected $sameWide;
protected $showKeys;
protected $orientation;
protected $paper;
protected $pageNumber;
protected $offline;
/**
* Set Page Number
*
* @param integer $value Page Number of the document to be created
*
* @return void
*/
public function setPageNumber($value)
{
$this->pageNumber = intval($value);
}
/**
* Returns the schema page number
*
* @return integer schema page number
*/
public function getPageNumber()
{
return $this->pageNumber;
}
/**
* Sets showColor
*
* @param boolean $value whether to show colors
*
* @return void
*/
public function setShowColor($value)
{
$this->showColor = $value;
}
/**
* Returns whether to show colors
*
* @return boolean whether to show colors
*/
public function isShowColor()
{
return $this->showColor;
}
/**
* Set Table Dimension
*
* @param boolean $value show table co-ordinates or not
*
* @return void
*/
public function setTableDimension($value)
{
$this->tableDimension = $value;
}
/**
* Returns whether to show table dimensions
*
* @return boolean whether to show table dimensions
*/
public function isTableDimension()
{
return $this->tableDimension;
}
/**
* Set same width of All Tables
*
* @param boolean $value set same width of all tables or not
*
* @return void
*/
public function setAllTablesSameWidth($value)
{
$this->sameWide = $value;
}
/**
* Returns whether to use same width for all tables or not
*
* @return boolean whether to use same width for all tables or not
*/
public function isAllTableSameWidth()
{
return $this->sameWide;
}
/**
* Set Show only keys
*
* @param boolean $value show only keys or not
*
* @return void
*
* @access public
*/
public function setShowKeys($value)
{
$this->showKeys = $value;
}
/**
* Returns whether to show keys
*
* @return boolean whether to show keys
*/
public function isShowKeys()
{
return $this->showKeys;
}
/**
* Set Orientation
*
* @param string $value Orientation will be portrait or landscape
*
* @return void
*
* @access public
*/
public function setOrientation($value)
{
$this->orientation = ($value == 'P') ? 'P' : 'L';
}
/**
* Returns orientation
*
* @return string orientation
*/
public function getOrientation()
{
return $this->orientation;
}
/**
* Set type of paper
*
* @param string $value paper type can be A4 etc
*
* @return void
*
* @access public
*/
public function setPaper($value)
{
$this->paper = $value;
}
/**
* Returns the paper size
*
* @return string paper size
*/
public function getPaper()
{
return $this->paper;
}
/**
* Set whether the document is generated from client side DB
*
* @param boolean $value offline or not
*
* @return void
*
* @access public
*/
public function setOffline($value)
{
$this->offline = $value;
}
/**
* Returns whether the client side database is used
*
* @return boolean
*
* @access public
*/
public function isOffline()
{
return $this->offline;
}
/**
* Get the table names from the request
*
* @return array an array of table names
*/
protected function getTablesFromRequest()
{
$tables = array();
$dbLength = mb_strlen($this->db);
foreach ($_REQUEST['t_h'] as $key => $value) {
if ($value) {
$tables[] = mb_substr($key, $dbLength + 1);
}
}
return $tables;
}
/**
* Returns the file name
*
* @param String $extension file extension
*
* @return string file name
*/
protected function getFileName($extension)
{
$filename = $this->db . $extension;
// Get the name of this page to use as filename
if ($this->pageNumber != -1 && !$this->offline) {
$_name_sql = 'SELECT page_descr FROM '
. PMA\libraries\Util::backquote($GLOBALS['cfgRelation']['db']) . '.'
. PMA\libraries\Util::backquote($GLOBALS['cfgRelation']['pdf_pages'])
. ' WHERE page_nr = ' . $this->pageNumber;
$_name_rs = PMA_queryAsControlUser($_name_sql);
$_name_row = $GLOBALS['dbi']->fetchRow($_name_rs);
$filename = $_name_row[0] . $extension;
}
return $filename;
}
/**
* Displays an error message
*
* @param integer $pageNumber ID of the chosen page
* @param string $type Schema Type
* @param string $error_message The error message
*
* @access public
*
* @return void
*/
public static function dieSchema($pageNumber, $type = '', $error_message = '')
{
echo "<p><strong>" , __("SCHEMA ERROR: ") , $type , "</strong></p>" , "\n";
if (!empty($error_message)) {
$error_message = htmlspecialchars($error_message);
}
echo '<p>' , "\n";
echo ' ' , $error_message , "\n";
echo '</p>' , "\n";
echo '<a href="db_designer.php'
, PMA_URL_getCommon(array('db' => $GLOBALS['db']))
, '&page=' . htmlspecialchars($pageNumber) , '">' , __('Back') , '</a>';
echo "\n";
exit;
}
}

View File

@ -0,0 +1,114 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Contains abstract class to hold relation preferences/statistics
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins\schema;
/**
* Relations preferences/statistics
*
* This class fetches the table master and foreign fields positions
* and helps in generating the Table references and then connects
* master table's master field to foreign table's foreign key.
*
* @package PhpMyAdmin
* @abstract
*/
abstract class RelationStats
{
protected $diagram;
/**
* Defines properties
*/
public $xSrc, $ySrc;
public $srcDir;
public $destDir;
public $xDest, $yDest;
public $wTick;
/**
* The constructor
*
* @param object $diagram The diagram
* @param string $master_table The master table name
* @param string $master_field The relation field in the master table
* @param string $foreign_table The foreign table name
* @param string $foreign_field The relation field in the foreign table
*/
public function __construct(
$diagram,
$master_table,
$master_field,
$foreign_table,
$foreign_field
) {
$this->diagram = $diagram;
$src_pos = $this->_getXy($master_table, $master_field);
$dest_pos = $this->_getXy($foreign_table, $foreign_field);
/*
* [0] is x-left
* [1] is x-right
* [2] is y
*/
$src_left = $src_pos[0] - $this->wTick;
$src_right = $src_pos[1] + $this->wTick;
$dest_left = $dest_pos[0] - $this->wTick;
$dest_right = $dest_pos[1] + $this->wTick;
$d1 = abs($src_left - $dest_left);
$d2 = abs($src_right - $dest_left);
$d3 = abs($src_left - $dest_right);
$d4 = abs($src_right - $dest_right);
$d = min($d1, $d2, $d3, $d4);
if ($d == $d1) {
$this->xSrc = $src_pos[0];
$this->srcDir = -1;
$this->xDest = $dest_pos[0];
$this->destDir = -1;
} elseif ($d == $d2) {
$this->xSrc = $src_pos[1];
$this->srcDir = 1;
$this->xDest = $dest_pos[0];
$this->destDir = -1;
} elseif ($d == $d3) {
$this->xSrc = $src_pos[0];
$this->srcDir = -1;
$this->xDest = $dest_pos[1];
$this->destDir = 1;
} else {
$this->xSrc = $src_pos[1];
$this->srcDir = 1;
$this->xDest = $dest_pos[1];
$this->destDir = 1;
}
$this->ySrc = $src_pos[2];
$this->yDest = $dest_pos[2];
}
/**
* Gets arrows coordinates
*
* @param string $table The current table name
* @param string $column The relation column name
*
* @return array Arrows coordinates
*
* @access private
*/
private function _getXy($table, $column)
{
$pos = array_search($column, $table->fields);
// x_left, x_right, y
return array(
$table->x,
$table->x + $table->width,
$table->y + ($pos + 1.5) * $table->heightCell,
);
}
}

View File

@ -0,0 +1,97 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Dia schema export code
*
* @package PhpMyAdmin-Schema
* @subpackage Dia
*/
namespace PMA\libraries\plugins\schema;
use PMA\libraries\properties\options\groups\OptionsPropertyMainGroup;
use PMA\libraries\properties\options\groups\OptionsPropertyRootGroup;
use PMA\libraries\plugins\SchemaPlugin;
use PMA\libraries\plugins\schema\dia\DiaRelationSchema;
use PMA\libraries\properties\plugins\SchemaPluginProperties;
use PMA\libraries\properties\options\items\SelectPropertyItem;
/**
* Handles the schema export for the Dia format
*
* @package PhpMyAdmin-Schema
* @subpackage Dia
*/
class SchemaDia extends SchemaPlugin
{
/**
* Constructor
*/
public function __construct()
{
$this->setProperties();
}
/**
* Sets the schema export Dia properties
*
* @return void
*/
protected function setProperties()
{
$schemaPluginProperties = new SchemaPluginProperties();
$schemaPluginProperties->setText('Dia');
$schemaPluginProperties->setExtension('dia');
$schemaPluginProperties->setMimeType('application/dia');
// create the root group that will be the options field for
// $schemaPluginProperties
// this will be shown as "Format specific options"
$exportSpecificOptions = new OptionsPropertyRootGroup(
"Format Specific Options"
);
// specific options main group
$specificOptions = new OptionsPropertyMainGroup("general_opts");
// add options common to all plugins
$this->addCommonOptions($specificOptions);
$leaf = new SelectPropertyItem(
"orientation",
__('Orientation')
);
$leaf->setValues(
array(
'L' => __('Landscape'),
'P' => __('Portrait'),
)
);
$specificOptions->addProperty($leaf);
$leaf = new SelectPropertyItem(
"paper",
__('Paper size')
);
$leaf->setValues($this->getPaperSizeArray());
$specificOptions->addProperty($leaf);
// add the main group to the root group
$exportSpecificOptions->addProperty($specificOptions);
// set the options for the schema export plugin property item
$schemaPluginProperties->setOptions($exportSpecificOptions);
$this->properties = $schemaPluginProperties;
}
/**
* Exports the schema into DIA format.
*
* @param string $db database name
*
* @return bool Whether it succeeded
*/
public function exportSchema($db)
{
$export = new DiaRelationSchema($db);
$export->showOutput();
}
}

View File

@ -0,0 +1,98 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* PDF schema export code
*
* @package PhpMyAdmin-Schema
* @subpackage EPS
*/
namespace PMA\libraries\plugins\schema;
use PMA\libraries\properties\options\items\BoolPropertyItem;
use PMA\libraries\properties\options\groups\OptionsPropertyMainGroup;
use PMA\libraries\properties\options\groups\OptionsPropertyRootGroup;
use PMA\libraries\plugins\schema\eps\EpsRelationSchema;
use PMA\libraries\plugins\SchemaPlugin;
use PMA\libraries\properties\plugins\SchemaPluginProperties;
use PMA\libraries\properties\options\items\SelectPropertyItem;
/**
* Handles the schema export for the EPS format
*
* @package PhpMyAdmin-Schema
* @subpackage EPS
*/
class SchemaEps extends SchemaPlugin
{
/**
* Constructor
*/
public function __construct()
{
$this->setProperties();
}
/**
* Sets the schema export EPS properties
*
* @return void
*/
protected function setProperties()
{
$schemaPluginProperties = new SchemaPluginProperties();
$schemaPluginProperties->setText('EPS');
$schemaPluginProperties->setExtension('eps');
$schemaPluginProperties->setMimeType('application/eps');
// create the root group that will be the options field for
// $schemaPluginProperties
// this will be shown as "Format specific options"
$exportSpecificOptions = new OptionsPropertyRootGroup(
"Format Specific Options"
);
// specific options main group
$specificOptions = new OptionsPropertyMainGroup("general_opts");
// add options common to all plugins
$this->addCommonOptions($specificOptions);
// create leaf items and add them to the group
$leaf = new BoolPropertyItem(
'all_tables_same_width',
__('Same width for all tables')
);
$specificOptions->addProperty($leaf);
$leaf = new SelectPropertyItem(
"orientation",
__('Orientation')
);
$leaf->setValues(
array(
'L' => __('Landscape'),
'P' => __('Portrait'),
)
);
$specificOptions->addProperty($leaf);
// add the main group to the root group
$exportSpecificOptions->addProperty($specificOptions);
// set the options for the schema export plugin property item
$schemaPluginProperties->setOptions($exportSpecificOptions);
$this->properties = $schemaPluginProperties;
}
/**
* Exports the schema into EPS format.
*
* @param string $db database name
*
* @return bool Whether it succeeded
*/
public function exportSchema($db)
{
$export = new EpsRelationSchema($db);
$export->showOutput();
}
}

View File

@ -0,0 +1,130 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* PDF schema export code
*
* @package PhpMyAdmin-Schema
* @subpackage PDF
*/
namespace PMA\libraries\plugins\schema;
use PMA\libraries\properties\options\items\BoolPropertyItem;
use PMA\libraries\properties\options\groups\OptionsPropertyMainGroup;
use PMA\libraries\properties\options\groups\OptionsPropertyRootGroup;
use PMA\libraries\plugins\schema\pdf\PdfRelationSchema;
use PMA\libraries\plugins\SchemaPlugin;
use PMA\libraries\properties\plugins\SchemaPluginProperties;
use PMA\libraries\properties\options\items\SelectPropertyItem;
/**
* Handles the schema export for the PDF format
*
* @package PhpMyAdmin-Schema
* @subpackage PDF
*/
class SchemaPdf extends SchemaPlugin
{
/**
* Constructor
*/
public function __construct()
{
$this->setProperties();
}
/**
* Sets the schema export PDF properties
*
* @return void
*/
protected function setProperties()
{
$schemaPluginProperties = new SchemaPluginProperties();
$schemaPluginProperties->setText('PDF');
$schemaPluginProperties->setExtension('pdf');
$schemaPluginProperties->setMimeType('application/pdf');
// create the root group that will be the options field for
// $schemaPluginProperties
// this will be shown as "Format specific options"
$exportSpecificOptions = new OptionsPropertyRootGroup(
"Format Specific Options"
);
// specific options main group
$specificOptions = new OptionsPropertyMainGroup("general_opts");
// add options common to all plugins
$this->addCommonOptions($specificOptions);
// create leaf items and add them to the group
$leaf = new BoolPropertyItem(
'all_tables_same_width',
__('Same width for all tables')
);
$specificOptions->addProperty($leaf);
$leaf = new SelectPropertyItem(
"orientation",
__('Orientation')
);
$leaf->setValues(
array(
'L' => __('Landscape'),
'P' => __('Portrait'),
)
);
$specificOptions->addProperty($leaf);
$leaf = new SelectPropertyItem(
"paper",
__('Paper size')
);
$leaf->setValues($this->getPaperSizeArray());
$specificOptions->addProperty($leaf);
$leaf = new BoolPropertyItem(
'show_grid',
__('Show grid')
);
$specificOptions->addProperty($leaf);
$leaf = new BoolPropertyItem(
'with_doc',
__('Data dictionary')
);
$specificOptions->addProperty($leaf);
$leaf = new SelectPropertyItem(
"table_order",
__('Order of the tables')
);
$leaf->setValues(
array(
'' => __('None'),
'name_asc' => __('Name (Ascending)'),
'name_desc' => __('Name (Descending)'),
)
);
$specificOptions->addProperty($leaf);
// add the main group to the root group
$exportSpecificOptions->addProperty($specificOptions);
// set the options for the schema export plugin property item
$schemaPluginProperties->setOptions($exportSpecificOptions);
$this->properties = $schemaPluginProperties;
}
/**
* Exports the schema into PDF format.
*
* @param string $db database name
*
* @return bool Whether it succeeded
*/
public function exportSchema($db)
{
$export = new PdfRelationSchema($db);
$export->showOutput();
}
}

View File

@ -0,0 +1,85 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* PDF schema export code
*
* @package PhpMyAdmin-Schema
* @subpackage SVG
*/
namespace PMA\libraries\plugins\schema;
use PMA\libraries\properties\options\items\BoolPropertyItem;
use PMA\libraries\properties\options\groups\OptionsPropertyMainGroup;
use PMA\libraries\properties\options\groups\OptionsPropertyRootGroup;
use PMA\libraries\plugins\SchemaPlugin;
use PMA\libraries\plugins\schema\svg\SvgRelationSchema;
use PMA\libraries\properties\plugins\SchemaPluginProperties;
/**
* Handles the schema export for the SVG format
*
* @package PhpMyAdmin-Schema
* @subpackage SVG
*/
class SchemaSvg extends SchemaPlugin
{
/**
* Constructor
*/
public function __construct()
{
$this->setProperties();
}
/**
* Sets the schema export SVG properties
*
* @return void
*/
protected function setProperties()
{
$schemaPluginProperties = new SchemaPluginProperties();
$schemaPluginProperties->setText('SVG');
$schemaPluginProperties->setExtension('svg');
$schemaPluginProperties->setMimeType('application/svg');
// create the root group that will be the options field for
// $schemaPluginProperties
// this will be shown as "Format specific options"
$exportSpecificOptions = new OptionsPropertyRootGroup(
"Format Specific Options"
);
// specific options main group
$specificOptions = new OptionsPropertyMainGroup("general_opts");
// add options common to all plugins
$this->addCommonOptions($specificOptions);
// create leaf items and add them to the group
$leaf = new BoolPropertyItem(
'all_tables_same_width',
__('Same width for all tables')
);
$specificOptions->addProperty($leaf);
// add the main group to the root group
$exportSpecificOptions->addProperty($specificOptions);
// set the options for the schema export plugin property item
$schemaPluginProperties->setOptions($exportSpecificOptions);
$this->properties = $schemaPluginProperties;
}
/**
* Exports the schema into SVG format.
*
* @param string $db database name
*
* @return bool Whether it succeeded
*/
public function exportSchema($db)
{
$export = new SvgRelationSchema($db);
$export->showOutput();
}
}

View File

@ -0,0 +1,174 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Contains abstract class to hold table preferences/statistics
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins\schema;
use PMA;
/**
* Table preferences/statistics
*
* This class preserves the table co-ordinates,fields
* and helps in drawing/generating the tables.
*
* @package PhpMyAdmin
* @abstract
*/
abstract class TableStats
{
protected $diagram;
protected $db;
protected $pageNumber;
protected $tableName;
protected $showKeys;
protected $tableDimension;
public $displayfield;
public $fields = array();
public $primary = array();
public $x, $y;
public $width = 0;
public $heightCell = 0;
protected $offline;
/**
* Constructor
*
* @param object $diagram schema diagram
* @param string $db current db name
* @param integer $pageNumber current page number (from the
* $cfg['Servers'][$i]['table_coords'] table)
* @param string $tableName table name
* @param boolean $showKeys whether to display keys or not
* @param boolean $tableDimension whether to display table position or not
* @param boolean $offline whether the coordinates are sent
* from the browser
*/
public function __construct(
$diagram, $db, $pageNumber, $tableName, $showKeys, $tableDimension, $offline
) {
$this->diagram = $diagram;
$this->db = $db;
$this->pageNumber = $pageNumber;
$this->tableName = $tableName;
$this->showKeys = $showKeys;
$this->tableDimension = $tableDimension;
$this->offline = $offline;
// checks whether the table exists
// and loads fields
$this->validateTableAndLoadFields();
// load table coordinates
$this->loadCoordinates();
// loads display field
$this->loadDisplayField();
// loads primary keys
$this->loadPrimaryKey();
}
/**
* Validate whether the table exists.
*
* @return void
*/
protected function validateTableAndLoadFields()
{
$sql = 'DESCRIBE ' . PMA\libraries\Util::backquote($this->tableName);
$result = $GLOBALS['dbi']->tryQuery(
$sql, null, PMA\libraries\DatabaseInterface::QUERY_STORE
);
if (! $result || ! $GLOBALS['dbi']->numRows($result)) {
$this->showMissingTableError();
}
if ($this->showKeys) {
$indexes = PMA\libraries\Index::getFromTable($this->tableName, $this->db);
$all_columns = array();
foreach ($indexes as $index) {
$all_columns = array_merge(
$all_columns,
array_flip(array_keys($index->getColumns()))
);
}
$this->fields = array_keys($all_columns);
} else {
while ($row = $GLOBALS['dbi']->fetchRow($result)) {
$this->fields[] = $row[0];
}
}
}
/**
* Displays an error when the table cannot be found.
*
* @return void
* @abstract
*/
protected abstract function showMissingTableError();
/**
* Loads coordinates of a table
*
* @return void
*/
protected function loadCoordinates()
{
foreach ($_REQUEST['t_h'] as $key => $value) {
if ($this->db . '.' . $this->tableName == $key) {
$this->x = (double) $_REQUEST['t_x'][$key];
$this->y = (double) $_REQUEST['t_y'][$key];
break;
}
}
}
/**
* Loads the table's display field
*
* @return void
*/
protected function loadDisplayField()
{
$this->displayfield = PMA_getDisplayField($this->db, $this->tableName);
}
/**
* Loads the PRIMARY key.
*
* @return void
*/
protected function loadPrimaryKey()
{
$result = $GLOBALS['dbi']->query(
'SHOW INDEX FROM ' . PMA\libraries\Util::backquote($this->tableName) . ';',
null, PMA\libraries\DatabaseInterface::QUERY_STORE
);
if ($GLOBALS['dbi']->numRows($result) > 0) {
while ($row = $GLOBALS['dbi']->fetchAssoc($result)) {
if ($row['Key_name'] == 'PRIMARY') {
$this->primary[] = $row['Column_name'];
}
}
}
}
/**
* Returns title of the current table,
* title can have the dimensions/co-ordinates of the table
*
* @return string title of the current table
*/
protected function getTitle()
{
return ($this->tableDimension
? sprintf('%.0fx%0.f', $this->width, $this->heightCell)
: ''
)
. ' ' . $this->tableName;
}
}

View File

@ -0,0 +1,188 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Classes to create relation schema in Dia format.
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins\schema\dia;
use PMA;
use XMLWriter;
/**
* This Class inherits the XMLwriter class and
* helps in developing structure of DIA Schema Export
*
* @package PhpMyAdmin
* @access public
* @see https://php.net/manual/en/book.xmlwriter.php
*/
class Dia extends XMLWriter
{
/**
* The "Dia" constructor
*
* Upon instantiation This starts writing the Dia XML document
*
* @see XMLWriter::openMemory(),XMLWriter::setIndent(),XMLWriter::startDocument()
*/
public function __construct()
{
$this->openMemory();
/*
* Set indenting using three spaces,
* so output is formatted
*/
$this->setIndent(true);
$this->setIndentString(' ');
/*
* Create the XML document
*/
$this->startDocument('1.0', 'UTF-8');
}
/**
* Starts Dia Document
*
* dia document starts by first initializing dia:diagram tag
* then dia:diagramdata contains all the attributes that needed
* to define the document, then finally a Layer starts which
* holds all the objects.
*
* @param string $paper the size of the paper/document
* @param float $topMargin top margin of the paper/document in cm
* @param float $bottomMargin bottom margin of the paper/document in cm
* @param float $leftMargin left margin of the paper/document in cm
* @param float $rightMargin right margin of the paper/document in cm
* @param string $orientation orientation of the document, portrait or landscape
*
* @return void
*
* @access public
* @see XMLWriter::startElement(),XMLWriter::writeAttribute(),
* XMLWriter::writeRaw()
*/
public function startDiaDoc(
$paper,
$topMargin,
$bottomMargin,
$leftMargin,
$rightMargin,
$orientation
) {
if ($orientation == 'P') {
$isPortrait = 'true';
} else {
$isPortrait = 'false';
}
$this->startElement('dia:diagram');
$this->writeAttribute('xmlns:dia', 'http://www.lysator.liu.se/~alla/dia/');
$this->startElement('dia:diagramdata');
$this->writeRaw(
'<dia:attribute name="background">
<dia:color val="#ffffff"/>
</dia:attribute>
<dia:attribute name="pagebreak">
<dia:color val="#000099"/>
</dia:attribute>
<dia:attribute name="paper">
<dia:composite type="paper">
<dia:attribute name="name">
<dia:string>#' . $paper . '#</dia:string>
</dia:attribute>
<dia:attribute name="tmargin">
<dia:real val="' . $topMargin . '"/>
</dia:attribute>
<dia:attribute name="bmargin">
<dia:real val="' . $bottomMargin . '"/>
</dia:attribute>
<dia:attribute name="lmargin">
<dia:real val="' . $leftMargin . '"/>
</dia:attribute>
<dia:attribute name="rmargin">
<dia:real val="' . $rightMargin . '"/>
</dia:attribute>
<dia:attribute name="is_portrait">
<dia:boolean val="' . $isPortrait . '"/>
</dia:attribute>
<dia:attribute name="scaling">
<dia:real val="1"/>
</dia:attribute>
<dia:attribute name="fitto">
<dia:boolean val="false"/>
</dia:attribute>
</dia:composite>
</dia:attribute>
<dia:attribute name="grid">
<dia:composite type="grid">
<dia:attribute name="width_x">
<dia:real val="1"/>
</dia:attribute>
<dia:attribute name="width_y">
<dia:real val="1"/>
</dia:attribute>
<dia:attribute name="visible_x">
<dia:int val="1"/>
</dia:attribute>
<dia:attribute name="visible_y">
<dia:int val="1"/>
</dia:attribute>
<dia:composite type="color"/>
</dia:composite>
</dia:attribute>
<dia:attribute name="color">
<dia:color val="#d8e5e5"/>
</dia:attribute>
<dia:attribute name="guides">
<dia:composite type="guides">
<dia:attribute name="hguides"/>
<dia:attribute name="vguides"/>
</dia:composite>
</dia:attribute>'
);
$this->endElement();
$this->startElement('dia:layer');
$this->writeAttribute('name', 'Background');
$this->writeAttribute('visible', 'true');
$this->writeAttribute('active', 'true');
}
/**
* Ends Dia Document
*
* @return void
* @access public
* @see XMLWriter::endElement(),XMLWriter::endDocument()
*/
public function endDiaDoc()
{
$this->endElement();
$this->endDocument();
}
/**
* Output Dia Document for download
*
* @param string $fileName name of the dia document
*
* @return void
* @access public
* @see XMLWriter::flush()
*/
public function showOutput($fileName)
{
if (ob_get_clean()) {
ob_end_clean();
}
$output = $this->flush();
PMA\libraries\Response::getInstance()
->disable();
PMA_downloadHeader(
$fileName,
'application/x-dia-diagram',
strlen($output)
);
print $output;
}
}

View File

@ -0,0 +1,227 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Classes to create relation schema in Dia format.
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins\schema\dia;
use PMA\libraries\plugins\schema\eps\TableStatsEps;
use PMA\libraries\plugins\schema\ExportRelationSchema;
use PMA\libraries\plugins\schema\pdf\TableStatsPdf;
use PMA\libraries\plugins\schema\svg\TableStatsSvg;
use PMA\libraries\plugins\schema\dia\TableStatsDia;
/**
* Dia Relation Schema Class
*
* Purpose of this class is to generate the Dia XML Document
* which is used for representing the database diagrams in Dia IDE
* This class uses Database Table and Reference Objects of Dia and with
* the combination of these objects actually helps in preparing Dia XML.
*
* Dia XML is generated by using XMLWriter php extension and this class
* inherits ExportRelationSchema class has common functionality added
* to this class
*
* @package PhpMyAdmin
* @name Dia_Relation_Schema
*/
class DiaRelationSchema extends ExportRelationSchema
{
/**
* @var TableStatsDia[]|TableStatsEps[]|TableStatsPdf[]|TableStatsSvg[]
*/
private $_tables = array();
/** @var RelationStatsDia[] Relations */
private $_relations = array();
private $_topMargin = 2.8222000598907471;
private $_bottomMargin = 2.8222000598907471;
private $_leftMargin = 2.8222000598907471;
private $_rightMargin = 2.8222000598907471;
public static $objectId = 0;
/**
* The "PMA\libraries\plugins\schema\dia\DiaRelationSchema" constructor
*
* Upon instantiation This outputs the Dia XML document
* that user can download
*
* @param string $db database name
*
* @see Dia,TableStatsDia,RelationStatsDia
*/
public function __construct($db)
{
parent::__construct($db, new Dia());
$this->setShowColor(isset($_REQUEST['dia_show_color']));
$this->setShowKeys(isset($_REQUEST['dia_show_keys']));
$this->setOrientation($_REQUEST['dia_orientation']);
$this->setPaper($_REQUEST['dia_paper']);
$this->diagram->startDiaDoc(
$this->paper,
$this->_topMargin,
$this->_bottomMargin,
$this->_leftMargin,
$this->_rightMargin,
$this->orientation
);
$alltables = $this->getTablesFromRequest();
foreach ($alltables as $table) {
if (!isset($this->tables[$table])) {
$this->_tables[$table] = new TableStatsDia(
$this->diagram, $this->db, $table, $this->pageNumber,
$this->showKeys, $this->offline
);
}
}
$seen_a_relation = false;
foreach ($alltables as $one_table) {
$exist_rel = PMA_getForeigners($this->db, $one_table, '', 'both');
if (!$exist_rel) {
continue;
}
$seen_a_relation = true;
foreach ($exist_rel as $master_field => $rel) {
/* put the foreign table on the schema only if selected
* by the user
* (do not use array_search() because we would have to
* to do a === false and this is not PHP3 compatible)
*/
if ($master_field != 'foreign_keys_data') {
if (in_array($rel['foreign_table'], $alltables)) {
$this->_addRelation(
$one_table,
$master_field,
$rel['foreign_table'],
$rel['foreign_field'],
$this->showKeys
);
}
continue;
}
foreach ($rel as $one_key) {
if (!in_array($one_key['ref_table_name'], $alltables)) {
continue;
}
foreach ($one_key['index_list'] as $index => $one_field) {
$this->_addRelation(
$one_table,
$one_field,
$one_key['ref_table_name'],
$one_key['ref_index_list'][$index],
$this->showKeys
);
}
}
}
}
$this->_drawTables();
if ($seen_a_relation) {
$this->_drawRelations();
}
$this->diagram->endDiaDoc();
}
/**
* Output Dia Document for download
*
* @return void
* @access public
*/
public function showOutput()
{
$this->diagram->showOutput($this->getFileName('.dia'));
}
/**
* Defines relation objects
*
* @param string $masterTable The master table name
* @param string $masterField The relation field in the master table
* @param string $foreignTable The foreign table name
* @param string $foreignField The relation field in the foreign table
* @param bool $showKeys Whether to display ONLY keys or not
*
* @return void
*
* @access private
* @see TableStatsDia::__construct(),RelationStatsDia::__construct()
*/
private function _addRelation(
$masterTable,
$masterField,
$foreignTable,
$foreignField,
$showKeys
) {
if (!isset($this->_tables[$masterTable])) {
$this->_tables[$masterTable] = new TableStatsDia(
$this->diagram, $this->db, $masterTable, $this->pageNumber, $showKeys
);
}
if (!isset($this->_tables[$foreignTable])) {
$this->_tables[$foreignTable] = new TableStatsDia(
$this->diagram,
$this->db,
$foreignTable,
$this->pageNumber,
$showKeys
);
}
$this->_relations[] = new RelationStatsDia(
$this->diagram,
$this->_tables[$masterTable],
$masterField,
$this->_tables[$foreignTable],
$foreignField
);
}
/**
* Draws relation references
*
* connects master table's master field to
* foreign table's foreign field using Dia object
* type Database - Reference
*
* @return void
*
* @access private
* @see RelationStatsDia::relationDraw()
*/
private function _drawRelations()
{
foreach ($this->_relations as $relation) {
$relation->relationDraw($this->showColor);
}
}
/**
* Draws tables
*
* Tables are generated using Dia object type Database - Table
* primary fields are underlined and bold in tables
*
* @return void
*
* @access private
* @see TableStatsDia::tableDraw()
*/
private function _drawTables()
{
foreach ($this->_tables as $table) {
$table->tableDraw($this->showColor);
}
}
}

View File

@ -0,0 +1,214 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Contains PMA\libraries\plugins\schema\dia\RelationStatsDia class
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins\schema\dia;
/**
* Relation preferences/statistics
*
* This class fetches the table master and foreign fields positions
* and helps in generating the Table references and then connects
* master table's master field to foreign table's foreign key
* in dia XML document.
*
* @package PhpMyAdmin
* @name Relation_Stats_Dia
* @see PMA_DIA
*/
class RelationStatsDia
{
protected $diagram;
/**
* Defines properties
*/
public $srcConnPointsRight;
public $srcConnPointsLeft;
public $destConnPointsRight;
public $destConnPointsLeft;
public $masterTableId;
public $foreignTableId;
public $masterTablePos;
public $foreignTablePos;
public $referenceColor;
/**
* The "PMA\libraries\plugins\schema\dia\RelationStatsDia" constructor
*
* @param object $diagram The DIA diagram
* @param string $master_table The master table name
* @param string $master_field The relation field in the master table
* @param string $foreign_table The foreign table name
* @param string $foreign_field The relation field in the foreign table
*
* @see Relation_Stats_Dia::_getXy
*/
public function __construct(
$diagram, $master_table, $master_field, $foreign_table, $foreign_field
) {
$this->diagram = $diagram;
$src_pos = $this->_getXy($master_table, $master_field);
$dest_pos = $this->_getXy($foreign_table, $foreign_field);
$this->srcConnPointsLeft = $src_pos[0];
$this->srcConnPointsRight = $src_pos[1];
$this->destConnPointsLeft = $dest_pos[0];
$this->destConnPointsRight = $dest_pos[1];
$this->masterTablePos = $src_pos[2];
$this->foreignTablePos = $dest_pos[2];
$this->masterTableId = $master_table->tableId;
$this->foreignTableId = $foreign_table->tableId;
}
/**
* Each Table object have connection points
* which is used to connect to other objects in Dia
* we detect the position of key in fields and
* then determines its left and right connection
* points.
*
* @param string $table The current table name
* @param string $column The relation column name
*
* @return array Table right,left connection points and key position
*
* @access private
*/
private function _getXy($table, $column)
{
$pos = array_search($column, $table->fields);
// left, right, position
$value = 12;
if ($pos != 0) {
return array($pos + $value + $pos, $pos + $value + $pos + 1, $pos);
}
return array($pos + $value , $pos + $value + 1, $pos);
}
/**
* Draws relation references
*
* connects master table's master field to foreign table's
* foreign field using Dia object type Database - Reference
* Dia object is used to generate the XML of Dia Document.
* Database reference Object and their attributes are involved
* in the combination of displaying Database - reference on Dia Document.
*
* @param boolean $showColor Whether to use one color per relation or not
* if showColor is true then an array of $listOfColors
* will be used to choose the random colors for
* references lines. we can change/add more colors to
* this
*
* @return boolean|void
*
* @access public
* @see PDF
*/
public function relationDraw($showColor)
{
++DiaRelationSchema::$objectId;
/*
* if source connection points and destination connection
* points are same then return it false and don't draw that
* relation
*/
if ($this->srcConnPointsRight == $this->destConnPointsRight) {
if ($this->srcConnPointsLeft == $this->destConnPointsLeft) {
return false;
}
}
if ($showColor) {
$listOfColors = array(
'FF0000',
'000099',
'00FF00',
);
shuffle($listOfColors);
$this->referenceColor = '#' . $listOfColors[0] . '';
} else {
$this->referenceColor = '#000000';
}
$this->diagram->writeRaw(
'<dia:object type="Database - Reference" version="0" id="'
. DiaRelationSchema::$objectId . '">
<dia:attribute name="obj_pos">
<dia:point val="3.27,18.9198"/>
</dia:attribute>
<dia:attribute name="obj_bb">
<dia:rectangle val="2.27,8.7175;17.7679,18.9198"/>
</dia:attribute>
<dia:attribute name="meta">
<dia:composite type="dict"/>
</dia:attribute>
<dia:attribute name="orth_points">
<dia:point val="3.27,18.9198"/>
<dia:point val="2.27,18.9198"/>
<dia:point val="2.27,14.1286"/>
<dia:point val="17.7679,14.1286"/>
<dia:point val="17.7679,9.3375"/>
<dia:point val="16.7679,9.3375"/>
</dia:attribute>
<dia:attribute name="orth_orient">
<dia:enum val="0"/>
<dia:enum val="1"/>
<dia:enum val="0"/>
<dia:enum val="1"/>
<dia:enum val="0"/>
</dia:attribute>
<dia:attribute name="orth_autoroute">
<dia:boolean val="true"/>
</dia:attribute>
<dia:attribute name="text_colour">
<dia:color val="#000000"/>
</dia:attribute>
<dia:attribute name="line_colour">
<dia:color val="' . $this->referenceColor . '"/>
</dia:attribute>
<dia:attribute name="line_width">
<dia:real val="0.10000000000000001"/>
</dia:attribute>
<dia:attribute name="line_style">
<dia:enum val="0"/>
<dia:real val="1"/>
</dia:attribute>
<dia:attribute name="corner_radius">
<dia:real val="0"/>
</dia:attribute>
<dia:attribute name="end_arrow">
<dia:enum val="22"/>
</dia:attribute>
<dia:attribute name="end_arrow_length">
<dia:real val="0.5"/>
</dia:attribute>
<dia:attribute name="end_arrow_width">
<dia:real val="0.5"/>
</dia:attribute>
<dia:attribute name="start_point_desc">
<dia:string>#1#</dia:string>
</dia:attribute>
<dia:attribute name="end_point_desc">
<dia:string>#n#</dia:string>
</dia:attribute>
<dia:attribute name="normal_font">
<dia:font family="monospace" style="0" name="Courier"/>
</dia:attribute>
<dia:attribute name="normal_font_height">
<dia:real val="0.59999999999999998"/>
</dia:attribute>
<dia:connections>
<dia:connection handle="0" to="'
. $this->masterTableId . '" connection="'
. $this->srcConnPointsRight . '"/>
<dia:connection handle="1" to="'
. $this->foreignTableId . '" connection="'
. $this->destConnPointsRight . '"/>
</dia:connections>
</dia:object>'
);
}
}

View File

@ -0,0 +1,229 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Contains PMA\libraries\plugins\schema\dia\TableStatsDia class
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins\schema\dia;
use PMA\libraries\plugins\schema\ExportRelationSchema;
use PMA\libraries\plugins\schema\TableStats;
/**
* Table preferences/statistics
*
* This class preserves the table co-ordinates,fields
* and helps in drawing/generating the Tables in dia XML document.
*
* @package PhpMyAdmin
* @name Table_Stats_Dia
* @see PMA_DIA
*/
class TableStatsDia extends TableStats
{
public $tableId;
public $tableColor;
/**
* The "PMA\libraries\plugins\schema\dia\TableStatsDia" constructor
*
* @param object $diagram The current dia document
* @param string $db The database name
* @param string $tableName The table name
* @param integer $pageNumber The current page number (from the
* $cfg['Servers'][$i]['table_coords'] table)
* @param boolean $showKeys Whether to display ONLY keys or not
* @param boolean $offline Whether the coordinates are sent from the browser
*/
public function __construct(
$diagram,
$db,
$tableName,
$pageNumber,
$showKeys = false,
$offline = false
) {
parent::__construct(
$diagram,
$db,
$pageNumber,
$tableName,
$showKeys,
false,
$offline
);
/**
* Every object in Dia document needs an ID to identify
* so, we used a static variable to keep the things unique
*/
$this->tableId = ++DiaRelationSchema::$objectId;
}
/**
* Displays an error when the table cannot be found.
*
* @return void
*/
protected function showMissingTableError()
{
ExportRelationSchema::dieSchema(
$this->pageNumber,
"DIA",
sprintf(__('The %s table doesn\'t exist!'), $this->tableName)
);
}
/**
* Do draw the table
*
* Tables are generated using object type Database - Table
* primary fields are underlined in tables. Dia object
* is used to generate the XML of Dia Document. Database Table
* Object and their attributes are involved in the combination
* of displaying Database - Table on Dia Document.
*
* @param boolean $showColor Whether to show color for tables text or not
* if showColor is true then an array of $listOfColors
* will be used to choose the random colors for tables
* text we can change/add more colors to this array
*
* @return void
*
* @access public
* @see Dia
*/
public function tableDraw($showColor)
{
if ($showColor) {
$listOfColors = array(
'FF0000',
'000099',
'00FF00'
);
shuffle($listOfColors);
$this->tableColor = '#' . $listOfColors[0] . '';
} else {
$this->tableColor = '#000000';
}
$factor = 0.1;
$this->diagram->startElement('dia:object');
$this->diagram->writeAttribute('type', 'Database - Table');
$this->diagram->writeAttribute('version', '0');
$this->diagram->writeAttribute('id', '' . $this->tableId . '');
$this->diagram->writeRaw(
'<dia:attribute name="obj_pos">
<dia:point val="'
. ($this->x * $factor) . ',' . ($this->y * $factor) . '"/>
</dia:attribute>
<dia:attribute name="obj_bb">
<dia:rectangle val="'
. ($this->x * $factor) . ',' . ($this->y * $factor) . ';9.97,9.2"/>
</dia:attribute>
<dia:attribute name="meta">
<dia:composite type="dict"/>
</dia:attribute>
<dia:attribute name="elem_corner">
<dia:point val="'
. ($this->x * $factor) . ',' . ($this->y * $factor) . '"/>
</dia:attribute>
<dia:attribute name="elem_width">
<dia:real val="5.9199999999999999"/>
</dia:attribute>
<dia:attribute name="elem_height">
<dia:real val="3.5"/>
</dia:attribute>
<dia:attribute name="text_colour">
<dia:color val="' . $this->tableColor . '"/>
</dia:attribute>
<dia:attribute name="line_colour">
<dia:color val="#000000"/>
</dia:attribute>
<dia:attribute name="fill_colour">
<dia:color val="#ffffff"/>
</dia:attribute>
<dia:attribute name="line_width">
<dia:real val="0.10000000000000001"/>
</dia:attribute>
<dia:attribute name="name">
<dia:string>#' . $this->tableName . '#</dia:string>
</dia:attribute>
<dia:attribute name="comment">
<dia:string>##</dia:string>
</dia:attribute>
<dia:attribute name="visible_comment">
<dia:boolean val="false"/>
</dia:attribute>
<dia:attribute name="tagging_comment">
<dia:boolean val="false"/>
</dia:attribute>
<dia:attribute name="underline_primary_key">
<dia:boolean val="true"/>
</dia:attribute>
<dia:attribute name="bold_primary_keys">
<dia:boolean val="true"/>
</dia:attribute>
<dia:attribute name="normal_font">
<dia:font family="monospace" style="0" name="Courier"/>
</dia:attribute>
<dia:attribute name="name_font">
<dia:font family="sans" style="80" name="Helvetica-Bold"/>
</dia:attribute>
<dia:attribute name="comment_font">
<dia:font family="sans" style="0" name="Helvetica"/>
</dia:attribute>
<dia:attribute name="normal_font_height">
<dia:real val="0.80000000000000004"/>
</dia:attribute>
<dia:attribute name="name_font_height">
<dia:real val="0.69999999999999996"/>
</dia:attribute>
<dia:attribute name="comment_font_height">
<dia:real val="0.69999999999999996"/>
</dia:attribute>'
);
$this->diagram->startElement('dia:attribute');
$this->diagram->writeAttribute('name', 'attributes');
foreach ($this->fields as $field) {
$this->diagram->writeRaw(
'<dia:composite type="table_attribute">
<dia:attribute name="name">
<dia:string>#' . $field . '#</dia:string>
</dia:attribute>
<dia:attribute name="type">
<dia:string>##</dia:string>
</dia:attribute>
<dia:attribute name="comment">
<dia:string>##</dia:string>
</dia:attribute>'
);
unset($pm);
$pm = 'false';
if (in_array($field, $this->primary)) {
$pm = 'true';
}
if ($field == $this->displayfield) {
$pm = 'false';
}
$this->diagram->writeRaw(
'<dia:attribute name="primary_key">
<dia:boolean val="' . $pm . '"/>
</dia:attribute>
<dia:attribute name="nullable">
<dia:boolean val="false"/>
</dia:attribute>
<dia:attribute name="unique">
<dia:boolean val="' . $pm . '"/>
</dia:attribute>
</dia:composite>'
);
}
$this->diagram->endElement();
$this->diagram->endElement();
}
}

View File

@ -0,0 +1,277 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Classes to create relation schema in EPS format.
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins\schema\eps;
use PMA\libraries\Response;
/**
* This Class is EPS Library and
* helps in developing structure of EPS Schema Export
*
* @package PhpMyAdmin
* @access public
* @see https://php.net/manual/en/book.xmlwriter.php
*/
class Eps
{
public $font;
public $fontSize;
public $stringCommands;
/**
* The "Eps" constructor
*
* Upon instantiation This starts writing the EPS Document.
* %!PS-Adobe-3.0 EPSF-3.0 This is the MUST first comment to include
* it shows/tells that the Post Script document is purely under
* Document Structuring Convention [DSC] and is Compliant
* Encapsulated Post Script Document
*/
public function __construct()
{
$this->stringCommands = "";
$this->stringCommands .= "%!PS-Adobe-3.0 EPSF-3.0 \n";
}
/**
* Set document title
*
* @param string $value sets the title text
*
* @return void
*/
public function setTitle($value)
{
$this->stringCommands .= '%%Title: ' . $value . "\n";
}
/**
* Set document author
*
* @param string $value sets the author
*
* @return void
*/
public function setAuthor($value)
{
$this->stringCommands .= '%%Creator: ' . $value . "\n";
}
/**
* Set document creation date
*
* @param string $value sets the date
*
* @return void
*/
public function setDate($value)
{
$this->stringCommands .= '%%CreationDate: ' . $value . "\n";
}
/**
* Set document orientation
*
* @param string $orientation sets the orientation
*
* @return void
*/
public function setOrientation($orientation)
{
$this->stringCommands .= "%%PageOrder: Ascend \n";
if ($orientation == "L") {
$orientation = "Landscape";
$this->stringCommands .= '%%Orientation: ' . $orientation . "\n";
} else {
$orientation = "Portrait";
$this->stringCommands .= '%%Orientation: ' . $orientation . "\n";
}
$this->stringCommands .= "%%EndComments \n";
$this->stringCommands .= "%%Pages 1 \n";
$this->stringCommands .= "%%BoundingBox: 72 150 144 170 \n";
}
/**
* Set the font and size
*
* font can be set whenever needed in EPS
*
* @param string $value sets the font name e.g Arial
* @param integer $size sets the size of the font e.g 10
*
* @return void
*/
public function setFont($value, $size)
{
$this->font = $value;
$this->fontSize = $size;
$this->stringCommands .= "/" . $value . " findfont % Get the basic font\n";
$this->stringCommands .= ""
. $size . " scalefont % Scale the font to $size points\n";
$this->stringCommands
.= "setfont % Make it the current font\n";
}
/**
* Get the font
*
* @return string return the font name e.g Arial
*/
public function getFont()
{
return $this->font;
}
/**
* Get the font Size
*
* @return string return the size of the font e.g 10
*/
public function getFontSize()
{
return $this->fontSize;
}
/**
* Draw the line
*
* drawing the lines from x,y source to x,y destination and set the
* width of the line. lines helps in showing relationships of tables
*
* @param integer $x_from The x_from attribute defines the start
* left position of the element
* @param integer $y_from The y_from attribute defines the start
* right position of the element
* @param integer $x_to The x_to attribute defines the end
* left position of the element
* @param integer $y_to The y_to attribute defines the end
* right position of the element
* @param integer $lineWidth Sets the width of the line e.g 2
*
* @return void
*/
public function line(
$x_from = 0,
$y_from = 0,
$x_to = 0,
$y_to = 0,
$lineWidth = 0
) {
$this->stringCommands .= $lineWidth . " setlinewidth \n";
$this->stringCommands .= $x_from . ' ' . $y_from . " moveto \n";
$this->stringCommands .= $x_to . ' ' . $y_to . " lineto \n";
$this->stringCommands .= "stroke \n";
}
/**
* Draw the rectangle
*
* drawing the rectangle from x,y source to x,y destination and set the
* width of the line. rectangles drawn around the text shown of fields
*
* @param integer $x_from The x_from attribute defines the start
* left position of the element
* @param integer $y_from The y_from attribute defines the start
* right position of the element
* @param integer $x_to The x_to attribute defines the end
* left position of the element
* @param integer $y_to The y_to attribute defines the end
* right position of the element
* @param integer $lineWidth Sets the width of the line e.g 2
*
* @return void
*/
public function rect($x_from, $y_from, $x_to, $y_to, $lineWidth)
{
$this->stringCommands .= $lineWidth . " setlinewidth \n";
$this->stringCommands .= "newpath \n";
$this->stringCommands .= $x_from . " " . $y_from . " moveto \n";
$this->stringCommands .= "0 " . $y_to . " rlineto \n";
$this->stringCommands .= $x_to . " 0 rlineto \n";
$this->stringCommands .= "0 -" . $y_to . " rlineto \n";
$this->stringCommands .= "closepath \n";
$this->stringCommands .= "stroke \n";
}
/**
* Set the current point
*
* The moveto operator takes two numbers off the stack and treats
* them as x and y coordinates to which to move. The coordinates
* specified become the current point.
*
* @param integer $x The x attribute defines the left position of the element
* @param integer $y The y attribute defines the right position of the element
*
* @return void
*/
public function moveTo($x, $y)
{
$this->stringCommands .= $x . ' ' . $y . " moveto \n";
}
/**
* Output/Display the text
*
* @param string $text The string to be displayed
*
* @return void
*/
public function show($text)
{
$this->stringCommands .= '(' . $text . ") show \n";
}
/**
* Output the text at specified co-ordinates
*
* @param string $text String to be displayed
* @param integer $x X attribute defines the left position of the element
* @param integer $y Y attribute defines the right position of the element
*
* @return void
*/
public function showXY($text, $x, $y)
{
$this->moveTo($x, $y);
$this->show($text);
}
/**
* Ends EPS Document
*
* @return void
*/
public function endEpsDoc()
{
$this->stringCommands .= "showpage \n";
}
/**
* Output EPS Document for download
*
* @param string $fileName name of the eps document
*
* @return void
*/
public function showOutput($fileName)
{
// if(ob_get_clean()){
//ob_end_clean();
//}
$output = $this->stringCommands;
Response::getInstance()
->disable();
PMA_downloadHeader(
$fileName,
'image/x-eps',
strlen($output)
);
print $output;
}
}

View File

@ -0,0 +1,223 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Classes to create relation schema in EPS format.
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins\schema\eps;
use PMA\libraries\plugins\schema\dia\RelationStatsDia;
use PMA\libraries\plugins\schema\dia\TableStatsDia;
use PMA\libraries\plugins\schema\ExportRelationSchema;
use PMA\libraries\plugins\schema\pdf\TableStatsPdf;
use PMA\libraries\plugins\schema\svg\TableStatsSvg;
/**
* EPS Relation Schema Class
*
* Purpose of this class is to generate the EPS Document
* which is used for representing the database diagrams.
* This class uses post script commands and with
* the combination of these commands actually helps in preparing EPS Document.
*
* This class inherits ExportRelationSchema class has common functionality added
* to this class
*
* @package PhpMyAdmin
* @name Eps_Relation_Schema
*/
class EpsRelationSchema extends ExportRelationSchema
{
/**
* @var TableStatsDia[]|TableStatsEps[]|TableStatsPdf[]|TableStatsSvg[]
*/
private $_tables = array();
/** @var RelationStatsDia[] Relations */
private $_relations = array();
private $_tablewidth;
/**
* The "PMA_EPS_Relation_Schema" constructor
*
* Upon instantiation This starts writing the EPS document
* user will be prompted for download as .eps extension
*
* @param string $db database name
*
* @see PMA_EPS
*/
public function __construct($db)
{
parent::__construct($db, new Eps());
$this->setShowColor(isset($_REQUEST['eps_show_color']));
$this->setShowKeys(isset($_REQUEST['eps_show_keys']));
$this->setTableDimension(isset($_REQUEST['eps_show_table_dimension']));
$this->setAllTablesSameWidth(isset($_REQUEST['eps_all_tables_same_width']));
$this->setOrientation($_REQUEST['eps_orientation']);
$this->diagram->setTitle(
sprintf(
__('Schema of the %s database - Page %s'),
$this->db,
$this->pageNumber
)
);
$this->diagram->setAuthor('phpMyAdmin ' . PMA_VERSION);
$this->diagram->setDate(date("j F Y, g:i a"));
$this->diagram->setOrientation($this->orientation);
$this->diagram->setFont('Verdana', '10');
$alltables = $this->getTablesFromRequest();
foreach ($alltables as $table) {
if (! isset($this->_tables[$table])) {
$this->_tables[$table] = new TableStatsEps(
$this->diagram, $this->db,
$table, $this->diagram->getFont(),
$this->diagram->getFontSize(), $this->pageNumber,
$this->_tablewidth, $this->showKeys,
$this->tableDimension, $this->offline
);
}
if ($this->sameWide) {
$this->_tables[$table]->width = $this->_tablewidth;
}
}
$seen_a_relation = false;
foreach ($alltables as $one_table) {
$exist_rel = PMA_getForeigners($this->db, $one_table, '', 'both');
if (!$exist_rel) {
continue;
}
$seen_a_relation = true;
foreach ($exist_rel as $master_field => $rel) {
/* put the foreign table on the schema only if selected
* by the user
* (do not use array_search() because we would have to
* to do a === false and this is not PHP3 compatible)
*/
if ($master_field != 'foreign_keys_data') {
if (in_array($rel['foreign_table'], $alltables)) {
$this->_addRelation(
$one_table, $this->diagram->getFont(), $this->diagram->getFontSize(),
$master_field, $rel['foreign_table'],
$rel['foreign_field'], $this->tableDimension
);
}
continue;
}
foreach ($rel as $one_key) {
if (!in_array($one_key['ref_table_name'], $alltables)) {
continue;
}
foreach ($one_key['index_list']
as $index => $one_field
) {
$this->_addRelation(
$one_table, $this->diagram->getFont(),
$this->diagram->getFontSize(),
$one_field, $one_key['ref_table_name'],
$one_key['ref_index_list'][$index],
$this->tableDimension
);
}
}
}
}
if ($seen_a_relation) {
$this->_drawRelations();
}
$this->_drawTables();
$this->diagram->endEpsDoc();
}
/**
* Output Eps Document for download
*
* @return void
*/
public function showOutput()
{
$this->diagram->showOutput($this->getFileName('.eps'));
}
/**
* Defines relation objects
*
* @param string $masterTable The master table name
* @param string $font The font
* @param int $fontSize The font size
* @param string $masterField The relation field in the master table
* @param string $foreignTable The foreign table name
* @param string $foreignField The relation field in the foreign table
* @param boolean $tableDimension Whether to display table position or not
*
* @return void
*
* @see _setMinMax,Table_Stats_Eps::__construct(),
* PMA\libraries\plugins\schema\eps\RelationStatsEps::__construct()
*/
private function _addRelation(
$masterTable, $font, $fontSize, $masterField,
$foreignTable, $foreignField, $tableDimension
) {
if (! isset($this->_tables[$masterTable])) {
$this->_tables[$masterTable] = new TableStatsEps(
$this->diagram, $this->db, $masterTable, $font, $fontSize,
$this->pageNumber, $this->_tablewidth, false, $tableDimension
);
}
if (! isset($this->_tables[$foreignTable])) {
$this->_tables[$foreignTable] = new TableStatsEps(
$this->diagram, $this->db, $foreignTable, $font, $fontSize,
$this->pageNumber, $this->_tablewidth, false, $tableDimension
);
}
$this->_relations[] = new RelationStatsEps(
$this->diagram,
$this->_tables[$masterTable],
$masterField,
$this->_tables[$foreignTable],
$foreignField
);
}
/**
* Draws relation arrows and lines connects master table's master field to
* foreign table's foreign field
*
* @return void
*
* @see Relation_Stats_Eps::relationDraw()
*/
private function _drawRelations()
{
foreach ($this->_relations as $relation) {
$relation->relationDraw();
}
}
/**
* Draws tables
*
* @return void
*
* @see Table_Stats_Eps::Table_Stats_tableDraw()
*/
private function _drawTables()
{
foreach ($this->_tables as $table) {
$table->tableDraw($this->showColor);
}
}
}

View File

@ -0,0 +1,110 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Contains PMA\libraries\plugins\schema\eps\RelationStatsEps class
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins\schema\eps;
use PMA\libraries\plugins\schema\RelationStats;
/**
* Relation preferences/statistics
*
* This class fetches the table master and foreign fields positions
* and helps in generating the Table references and then connects
* master table's master field to foreign table's foreign key
* in EPS document.
*
* @package PhpMyAdmin
* @name Relation_Stats_Eps
* @see PMA_EPS
*/
class RelationStatsEps extends RelationStats
{
/**
* The "PMA\libraries\plugins\schema\eps\RelationStatsEps" constructor
*
* @param object $diagram The EPS diagram
* @param string $master_table The master table name
* @param string $master_field The relation field in the master table
* @param string $foreign_table The foreign table name
* @param string $foreign_field The relation field in the foreign table
*/
public function __construct(
$diagram, $master_table, $master_field, $foreign_table, $foreign_field
) {
$this->wTick = 10;
parent::__construct(
$diagram, $master_table, $master_field, $foreign_table, $foreign_field
);
$this->ySrc += 10;
$this->yDest += 10;
}
/**
* draws relation links and arrows
* shows foreign key relations
*
* @see PMA_EPS
*
* @return void
*/
public function relationDraw()
{
// draw a line like -- to foreign field
$this->diagram->line(
$this->xSrc,
$this->ySrc,
$this->xSrc + $this->srcDir * $this->wTick,
$this->ySrc,
1
);
// draw a line like -- to master field
$this->diagram->line(
$this->xDest + $this->destDir * $this->wTick,
$this->yDest,
$this->xDest,
$this->yDest,
1
);
// draw a line that connects to master field line and foreign field line
$this->diagram->line(
$this->xSrc + $this->srcDir * $this->wTick,
$this->ySrc,
$this->xDest + $this->destDir * $this->wTick,
$this->yDest,
1
);
$root2 = 2 * sqrt(2);
$this->diagram->line(
$this->xSrc + $this->srcDir * $this->wTick * 0.75,
$this->ySrc,
$this->xSrc + $this->srcDir * (0.75 - 1 / $root2) * $this->wTick,
$this->ySrc + $this->wTick / $root2,
1
);
$this->diagram->line(
$this->xSrc + $this->srcDir * $this->wTick * 0.75,
$this->ySrc,
$this->xSrc + $this->srcDir * (0.75 - 1 / $root2) * $this->wTick,
$this->ySrc - $this->wTick / $root2,
1
);
$this->diagram->line(
$this->xDest + $this->destDir * $this->wTick / 2,
$this->yDest,
$this->xDest + $this->destDir * (0.5 + 1 / $root2) * $this->wTick,
$this->yDest + $this->wTick / $root2,
1
);
$this->diagram->line(
$this->xDest + $this->destDir * $this->wTick / 2,
$this->yDest,
$this->xDest + $this->destDir * (0.5 + 1 / $root2) * $this->wTick,
$this->yDest - $this->wTick / $root2,
1
);
}
}

View File

@ -0,0 +1,182 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Contains PMA\libraries\plugins\schema\eps\TableStatsEps class
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins\schema\eps;
use PMA;
use PMA\libraries\plugins\schema\ExportRelationSchema;
use PMA\libraries\plugins\schema\TableStats;
/**
* Table preferences/statistics
*
* This class preserves the table co-ordinates,fields
* and helps in drawing/generating the Tables in EPS.
*
* @package PhpMyAdmin
* @name Table_Stats_Eps
* @see PMA_EPS
*/
class TableStatsEps extends TableStats
{
/**
* Defines properties
*/
public $height;
public $currentCell = 0;
/**
* The "PMA\libraries\plugins\schema\eps\TableStatsEps" constructor
*
* @param object $diagram The EPS diagram
* @param string $db The database name
* @param string $tableName The table name
* @param string $font The font name
* @param integer $fontSize The font size
* @param integer $pageNumber Page number
* @param integer &$same_wide_width The max width among tables
* @param boolean $showKeys Whether to display keys or not
* @param boolean $tableDimension Whether to display table position or not
* @param boolean $offline Whether the coordinates are sent
* from the browser
*
* @see PMA_EPS, Table_Stats_Eps::Table_Stats_setWidth,
* PMA\libraries\plugins\schema\eps\TableStatsEps::Table_Stats_setHeight
*/
public function __construct(
$diagram,
$db,
$tableName,
$font,
$fontSize,
$pageNumber,
&$same_wide_width,
$showKeys = false,
$tableDimension = false,
$offline = false
) {
parent::__construct(
$diagram,
$db,
$pageNumber,
$tableName,
$showKeys,
$tableDimension,
$offline
);
// height and width
$this->_setHeightTable($fontSize);
// setWidth must me after setHeight, because title
// can include table height which changes table width
$this->_setWidthTable($font, $fontSize);
if ($same_wide_width < $this->width) {
$same_wide_width = $this->width;
}
}
/**
* Displays an error when the table cannot be found.
*
* @return void
*/
protected function showMissingTableError()
{
ExportRelationSchema::dieSchema(
$this->pageNumber,
"EPS",
sprintf(__('The %s table doesn\'t exist!'), $this->tableName)
);
}
/**
* Sets the width of the table
*
* @param string $font The font name
* @param integer $fontSize The font size
*
* @return void
*
* @see PMA_EPS
*/
private function _setWidthTable($font, $fontSize)
{
foreach ($this->fields as $field) {
$this->width = max(
$this->width,
PMA\libraries\Font::getStringWidth($field, $font, $fontSize)
);
}
$this->width += PMA\libraries\Font::getStringWidth(
' ',
$font,
$fontSize
);
/*
* it is unknown what value must be added, because
* table title is affected by the table width value
*/
while ($this->width
< PMA\libraries\Font::getStringWidth(
$this->getTitle(),
$font,
$fontSize
)) {
$this->width += 7;
}
}
/**
* Sets the height of the table
*
* @param integer $fontSize The font size
*
* @return void
*/
private function _setHeightTable($fontSize)
{
$this->heightCell = $fontSize + 4;
$this->height = (count($this->fields) + 1) * $this->heightCell;
}
/**
* Draw the table
*
* @param boolean $showColor Whether to display color
*
* @return void
*
* @see PMA_EPS,PMA_EPS::line,PMA_EPS::rect
*/
public function tableDraw($showColor)
{
//echo $this->tableName.'<br />';
$this->diagram->rect(
$this->x,
$this->y + 12,
$this->width,
$this->heightCell,
1
);
$this->diagram->showXY($this->getTitle(), $this->x + 5, $this->y + 14);
foreach ($this->fields as $field) {
$this->currentCell += $this->heightCell;
$this->diagram->rect(
$this->x,
$this->y + 12 + $this->currentCell,
$this->width,
$this->heightCell,
1
);
$this->diagram->showXY(
$field,
$this->x + 5,
$this->y + 14 + $this->currentCell
);
}
}
}

View File

@ -0,0 +1,396 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* PDF schema handling
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins\schema\pdf;
use PMA\libraries\PDF as PDF_lib;
use PMA\libraries\Util;
/**
* Skip the plugin if TCPDF is not available.
*/
if (! file_exists(TCPDF_INC)) {
$GLOBALS['skip_import'] = true;
return;
}
/**
* block attempts to directly run this script
*/
if (getcwd() == dirname(__FILE__)) {
die('Attack stopped');
}
require_once 'libraries/transformations.lib.php';
/**
* Extends the "TCPDF" class and helps
* in developing the structure of PDF Schema Export
*
* @access public
* @package PhpMyAdmin
* @see TCPDF
*/
class Pdf extends PDF_lib
{
/**
* Defines properties
*/
var $_xMin;
var $_yMin;
var $leftMargin = 10;
var $topMargin = 10;
var $scale;
var $PMA_links;
var $Outlines = array();
var $def_outlines;
var $widths;
private $_ff = PDF_lib::PMA_PDF_FONT;
private $_offline;
private $_pageNumber;
private $_withDoc;
private $_db;
/**
* Constructs PDF for schema export.
*
* @param string $orientation page orientation
* @param string $unit unit
* @param string $paper the format used for pages
* @param int $pageNumber schema page number that is being exported
* @param boolean $withDoc with document dictionary
* @param string $db the database name
*
* @access public
*/
public function __construct(
$orientation, $unit, $paper, $pageNumber, $withDoc, $db
) {
parent::__construct($orientation, $unit, $paper);
$this->_pageNumber = $pageNumber;
$this->_withDoc = $withDoc;
$this->_db = $db;
}
/**
* Sets the value for margins
*
* @param float $c_margin margin
*
* @return void
*/
public function setCMargin($c_margin)
{
$this->cMargin = $c_margin;
}
/**
* Sets the scaling factor, defines minimum coordinates and margins
*
* @param float|int $scale The scaling factor
* @param float|int $xMin The minimum X coordinate
* @param float|int $yMin The minimum Y coordinate
* @param float|int $leftMargin The left margin
* @param float|int $topMargin The top margin
*
* @return void
*/
public function setScale($scale = 1, $xMin = 0, $yMin = 0,
$leftMargin = -1, $topMargin = -1
) {
$this->scale = $scale;
$this->_xMin = $xMin;
$this->_yMin = $yMin;
if ($this->leftMargin != -1) {
$this->leftMargin = $leftMargin;
}
if ($this->topMargin != -1) {
$this->topMargin = $topMargin;
}
}
/**
* Outputs a scaled cell
*
* @param float|int $w The cell width
* @param float|int $h The cell height
* @param string $txt The text to output
* @param mixed $border Whether to add borders or not
* @param integer $ln Where to put the cursor once the output is done
* @param string $align Align mode
* @param integer $fill Whether to fill the cell with a color or not
* @param string $link Link
*
* @return void
*
* @see TCPDF::Cell()
*/
public function cellScale($w, $h = 0, $txt = '', $border = 0, $ln = 0,
$align = '', $fill = 0, $link = ''
) {
$h = $h / $this->scale;
$w = $w / $this->scale;
$this->Cell($w, $h, $txt, $border, $ln, $align, $fill, $link);
}
/**
* Draws a scaled line
*
* @param float $x1 The horizontal position of the starting point
* @param float $y1 The vertical position of the starting point
* @param float $x2 The horizontal position of the ending point
* @param float $y2 The vertical position of the ending point
*
* @return void
*
* @see TCPDF::Line()
*/
public function lineScale($x1, $y1, $x2, $y2)
{
$x1 = ($x1 - $this->_xMin) / $this->scale + $this->leftMargin;
$y1 = ($y1 - $this->_yMin) / $this->scale + $this->topMargin;
$x2 = ($x2 - $this->_xMin) / $this->scale + $this->leftMargin;
$y2 = ($y2 - $this->_yMin) / $this->scale + $this->topMargin;
$this->Line($x1, $y1, $x2, $y2);
}
/**
* Sets x and y scaled positions
*
* @param float $x The x position
* @param float $y The y position
*
* @return void
*
* @see TCPDF::SetXY()
*/
public function setXyScale($x, $y)
{
$x = ($x - $this->_xMin) / $this->scale + $this->leftMargin;
$y = ($y - $this->_yMin) / $this->scale + $this->topMargin;
$this->SetXY($x, $y);
}
/**
* Sets the X scaled positions
*
* @param float $x The x position
*
* @return void
*
* @see TCPDF::SetX()
*/
public function setXScale($x)
{
$x = ($x - $this->_xMin) / $this->scale + $this->leftMargin;
$this->SetX($x);
}
/**
* Sets the scaled font size
*
* @param float $size The font size (in points)
*
* @return void
*
* @see TCPDF::SetFontSize()
*/
public function setFontSizeScale($size)
{
// Set font size in points
$size = $size / $this->scale;
$this->SetFontSize($size);
}
/**
* Sets the scaled line width
*
* @param float $width The line width
*
* @return void
*
* @see TCPDF::SetLineWidth()
*/
public function setLineWidthScale($width)
{
$width = $width / $this->scale;
$this->SetLineWidth($width);
}
/**
* This method is used to render the page header.
*
* @return void
*
* @see TCPDF::Header()
*/
public function Header()
{
// We only show this if we find something in the new pdf_pages table
// This function must be named "Header" to work with the TCPDF library
if ($this->_withDoc) {
if ($this->_offline || $this->_pageNumber == -1) {
$pg_name = __("PDF export page");
} else {
$test_query = 'SELECT * FROM '
. Util::backquote($GLOBALS['cfgRelation']['db']) . '.'
. Util::backquote($GLOBALS['cfgRelation']['pdf_pages'])
. ' WHERE db_name = \'' . $GLOBALS['dbi']->escapeString($this->_db)
. '\' AND page_nr = \'' . $this->_pageNumber . '\'';
$test_rs = PMA_queryAsControlUser($test_query);
$pages = @$GLOBALS['dbi']->fetchAssoc($test_rs);
$pg_name = ucfirst($pages['page_descr']);
}
$this->SetFont($this->_ff, 'B', 14);
$this->Cell(0, 6, $pg_name, 'B', 1, 'C');
$this->SetFont($this->_ff, '');
$this->Ln();
}
}
/**
* This function must be named "Footer" to work with the TCPDF library
*
* @return void
*
* @see PDF::Footer()
*/
public function Footer()
{
if ($this->_withDoc) {
parent::Footer();
}
}
/**
* Sets widths
*
* @param array $w array of widths
*
* @return void
*/
public function SetWidths($w)
{
// column widths
$this->widths = $w;
}
/**
* Generates table row.
*
* @param array $data Data for table
* @param array $links Links for table cells
*
* @return void
*/
public function Row($data, $links)
{
// line height
$nb = 0;
$data_cnt = count($data);
for ($i = 0;$i < $data_cnt;$i++) {
$nb = max($nb, $this->NbLines($this->widths[$i], $data[$i]));
}
$il = $this->FontSize;
$h = ($il + 1) * $nb;
// page break if necessary
$this->CheckPageBreak($h);
// draw the cells
$data_cnt = count($data);
for ($i = 0;$i < $data_cnt;$i++) {
$w = $this->widths[$i];
// save current position
$x = $this->GetX();
$y = $this->GetY();
// draw the border
$this->Rect($x, $y, $w, $h);
if (isset($links[$i])) {
$this->Link($x, $y, $w, $h, $links[$i]);
}
// print text
$this->MultiCell($w, $il + 1, $data[$i], 0, 'L');
// go to right side
$this->SetXY($x + $w, $y);
}
// go to line
$this->Ln($h);
}
/**
* Compute number of lines used by a multicell of width w
*
* @param int $w width
* @param string $txt text
*
* @return int
*/
public function NbLines($w, $txt)
{
$cw = &$this->CurrentFont['cw'];
if ($w == 0) {
$w = $this->w - $this->rMargin - $this->x;
}
$wmax = ($w-2 * $this->cMargin) * 1000 / $this->FontSize;
$s = str_replace("\r", '', $txt);
$nb = mb_strlen($s);
if ($nb > 0 && $s[$nb-1] == "\n") {
$nb--;
}
$sep = -1;
$i = 0;
$j = 0;
$l = 0;
$nl = 1;
while ($i < $nb) {
$c = $s[$i];
if ($c == "\n") {
$i++;
$sep = -1;
$j = $i;
$l = 0;
$nl++;
continue;
}
if ($c == ' ') {
$sep = $i;
}
$l += isset($cw[mb_ord($c)])?$cw[mb_ord($c)]:0 ;
if ($l > $wmax) {
if ($sep == -1) {
if ($i == $j) {
$i++;
}
} else {
$i = $sep + 1;
}
$sep = -1;
$j = $i;
$l = 0;
$nl++;
} else {
$i++;
}
}
return $nl;
}
/**
* Set whether the document is generated from client side DB
*
* @param string $value whether offline
*
* @return void
*
* @access private
*/
public function setOffline($value)
{
$this->_offline = $value;
}
}

View File

@ -0,0 +1,732 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* PDF schema handling
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins\schema\pdf;
use PMA\libraries\plugins\schema\ExportRelationSchema;
use PMA\libraries\Util;
use PMA\libraries\PDF as PDF_lib;
/**
* Skip the plugin if TCPDF is not available.
*/
if (! @file_exists(TCPDF_INC)) {
$GLOBALS['skip_import'] = true;
return;
}
/**
* block attempts to directly run this script
*/
if (getcwd() == dirname(__FILE__)) {
die('Attack stopped');
}
require_once 'libraries/transformations.lib.php';
/**
* Pdf Relation Schema Class
*
* Purpose of this class is to generate the PDF Document. PDF is widely
* used format for documenting text,fonts,images and 3d vector graphics.
*
* This class inherits ExportRelationSchema class has common functionality added
* to this class
*
* @name Pdf_Relation_Schema
* @package PhpMyAdmin
*/
class PdfRelationSchema extends ExportRelationSchema
{
/**
* Defines properties
*/
private $_showGrid;
private $_withDoc;
private $_tableOrder;
/**
* @var TableStatsPdf[]
*/
private $_tables = array();
private $_ff = PDF_lib::PMA_PDF_FONT;
private $_xMax = 0;
private $_yMax = 0;
private $_scale;
private $_xMin = 100000;
private $_yMin = 100000;
private $_topMargin = 10;
private $_bottomMargin = 10;
private $_leftMargin = 10;
private $_rightMargin = 10;
private $_tablewidth;
/**
* @var RelationStatsPdf[]
*/
protected $relations = array();
/**
* The "PdfRelationSchema" constructor
*
* @param string $db database name
*
* @see PMA_Schema_PDF
*/
public function __construct($db)
{
$this->setShowGrid(isset($_REQUEST['pdf_show_grid']));
$this->setShowColor(isset($_REQUEST['pdf_show_color']));
$this->setShowKeys(isset($_REQUEST['pdf_show_keys']));
$this->setTableDimension(isset($_REQUEST['pdf_show_table_dimension']));
$this->setAllTablesSameWidth(isset($_REQUEST['pdf_all_tables_same_width']));
$this->setWithDataDictionary(isset($_REQUEST['pdf_with_doc']));
$this->setTableOrder($_REQUEST['pdf_table_order']);
$this->setOrientation($_REQUEST['pdf_orientation']);
$this->setPaper($_REQUEST['pdf_paper']);
// Initializes a new document
parent::__construct(
$db,
new Pdf(
$this->orientation, 'mm', $this->paper,
$this->pageNumber, $this->_withDoc, $db
)
);
$this->diagram->SetTitle(
sprintf(
__('Schema of the %s database'),
$this->db
)
);
$this->diagram->setCMargin(0);
$this->diagram->Open();
$this->diagram->SetAutoPageBreak('auto');
$this->diagram->setOffline($this->offline);
$alltables = $this->getTablesFromRequest();
if ($this->getTableOrder() == 'name_asc') {
sort($alltables);
} else if ($this->getTableOrder() == 'name_desc') {
rsort($alltables);
}
if ($this->_withDoc) {
$this->diagram->SetAutoPageBreak('auto', 15);
$this->diagram->setCMargin(1);
$this->dataDictionaryDoc($alltables);
$this->diagram->SetAutoPageBreak('auto');
$this->diagram->setCMargin(0);
}
$this->diagram->Addpage();
if ($this->_withDoc) {
$this->diagram->SetLink($this->diagram->PMA_links['RT']['-'], -1);
$this->diagram->Bookmark(__('Relational schema'));
$this->diagram->SetAlias('{00}', $this->diagram->PageNo());
$this->_topMargin = 28;
$this->_bottomMargin = 28;
}
/* snip */
foreach ($alltables as $table) {
if (! isset($this->_tables[$table])) {
$this->_tables[$table] = new TableStatsPdf(
$this->diagram,
$this->db,
$table,
null,
$this->pageNumber,
$this->_tablewidth,
$this->showKeys,
$this->tableDimension,
$this->offline
);
}
if ($this->sameWide) {
$this->_tables[$table]->width = $this->_tablewidth;
}
$this->_setMinMax($this->_tables[$table]);
}
// Defines the scale factor
$innerWidth = $this->diagram->getPageWidth() - $this->_rightMargin
- $this->_leftMargin;
$innerHeight = $this->diagram->getPageHeight() - $this->_topMargin
- $this->_bottomMargin;
$this->_scale = ceil(
max(
($this->_xMax - $this->_xMin) / $innerWidth,
($this->_yMax - $this->_yMin) / $innerHeight
) * 100
) / 100;
$this->diagram->setScale(
$this->_scale,
$this->_xMin,
$this->_yMin,
$this->_leftMargin,
$this->_topMargin
);
// Builds and save the PDF document
$this->diagram->setLineWidthScale(0.1);
if ($this->_showGrid) {
$this->diagram->SetFontSize(10);
$this->_strokeGrid();
}
$this->diagram->setFontSizeScale(14);
// previous logic was checking master tables and foreign tables
// but I think that looping on every table of the pdf page as a master
// and finding its foreigns is OK (then we can support innodb)
$seen_a_relation = false;
foreach ($alltables as $one_table) {
$exist_rel = PMA_getForeigners($this->db, $one_table, '', 'both');
if (!$exist_rel) {
continue;
}
$seen_a_relation = true;
foreach ($exist_rel as $master_field => $rel) {
// put the foreign table on the schema only if selected
// by the user
// (do not use array_search() because we would have to
// to do a === false and this is not PHP3 compatible)
if ($master_field != 'foreign_keys_data') {
if (in_array($rel['foreign_table'], $alltables)) {
$this->_addRelation(
$one_table,
$master_field,
$rel['foreign_table'],
$rel['foreign_field']
);
}
continue;
}
foreach ($rel as $one_key) {
if (!in_array($one_key['ref_table_name'], $alltables)) {
continue;
}
foreach ($one_key['index_list']
as $index => $one_field
) {
$this->_addRelation(
$one_table,
$one_field,
$one_key['ref_table_name'],
$one_key['ref_index_list'][$index]
);
}
}
} // end while
} // end while
if ($seen_a_relation) {
$this->_drawRelations();
}
$this->_drawTables();
}
/**
* Set Show Grid
*
* @param boolean $value show grid of the document or not
*
* @return void
*/
public function setShowGrid($value)
{
$this->_showGrid = $value;
}
/**
* Returns whether to show grid
*
* @return boolean whether to show grid
*/
public function isShowGrid()
{
return $this->_showGrid;
}
/**
* Set Data Dictionary
*
* @param boolean $value show selected database data dictionary or not
*
* @return void
*/
public function setWithDataDictionary($value)
{
$this->_withDoc = $value;
}
/**
* Return whether to show selected database data dictionary or not
*
* @return boolean whether to show selected database data dictionary or not
*/
public function isWithDataDictionary()
{
return $this->_withDoc;
}
/**
* Sets the order of the table in data dictionary
*
* @param string $value table order
*
* @return void
*/
public function setTableOrder($value)
{
$this->_tableOrder = $value;
}
/**
* Returns the order of the table in data dictionary
*
* @return string table order
*/
public function getTableOrder()
{
return $this->_tableOrder;
}
/**
* Output Pdf Document for download
*
* @return void
*/
public function showOutput()
{
$this->diagram->Download($this->getFileName('.pdf'));
}
/**
* Sets X and Y minimum and maximum for a table cell
*
* @param TableStatsPdf $table The table name of which sets XY co-ordinates
*
* @return void
*/
private function _setMinMax($table)
{
$this->_xMax = max($this->_xMax, $table->x + $table->width);
$this->_yMax = max($this->_yMax, $table->y + $table->height);
$this->_xMin = min($this->_xMin, $table->x);
$this->_yMin = min($this->_yMin, $table->y);
}
/**
* Defines relation objects
*
* @param string $masterTable The master table name
* @param string $masterField The relation field in the master table
* @param string $foreignTable The foreign table name
* @param string $foreignField The relation field in the foreign table
*
* @return void
*
* @see _setMinMax
*/
private function _addRelation($masterTable, $masterField, $foreignTable,
$foreignField
) {
if (! isset($this->_tables[$masterTable])) {
$this->_tables[$masterTable] = new TableStatsPdf(
$this->diagram,
$this->db,
$masterTable,
null,
$this->pageNumber,
$this->_tablewidth,
$this->showKeys,
$this->tableDimension
);
$this->_setMinMax($this->_tables[$masterTable]);
}
if (! isset($this->_tables[$foreignTable])) {
$this->_tables[$foreignTable] = new TableStatsPdf(
$this->diagram,
$this->db,
$foreignTable,
null,
$this->pageNumber,
$this->_tablewidth,
$this->showKeys,
$this->tableDimension
);
$this->_setMinMax($this->_tables[$foreignTable]);
}
$this->relations[] = new RelationStatsPdf(
$this->diagram,
$this->_tables[$masterTable],
$masterField,
$this->_tables[$foreignTable],
$foreignField
);
}
/**
* Draws the grid
*
* @return void
*
* @see PMA_Schema_PDF
*/
private function _strokeGrid()
{
$gridSize = 10;
$labelHeight = 4;
$labelWidth = 5;
if ($this->_withDoc) {
$topSpace = 6;
$bottomSpace = 15;
} else {
$topSpace = 0;
$bottomSpace = 0;
}
$this->diagram->SetMargins(0, 0);
$this->diagram->SetDrawColor(200, 200, 200);
// Draws horizontal lines
$innerHeight = $this->diagram->getPageHeight() - $topSpace - $bottomSpace;
for ($l = 0,
$size = intval($innerHeight / $gridSize);
$l <= $size;
$l++
) {
$this->diagram->line(
0, $l * $gridSize + $topSpace,
$this->diagram->getPageWidth(), $l * $gridSize + $topSpace
);
// Avoid duplicates
if ($l > 0
&& $l <= intval(($innerHeight - $labelHeight) / $gridSize)
) {
$this->diagram->SetXY(0, $l * $gridSize + $topSpace);
$label = (string) sprintf(
'%.0f',
($l * $gridSize + $topSpace - $this->_topMargin)
* $this->_scale + $this->_yMin
);
$this->diagram->Cell($labelWidth, $labelHeight, ' ' . $label);
} // end if
} // end for
// Draws vertical lines
for (
$j = 0, $size = intval($this->diagram->getPageWidth() / $gridSize);
$j <= $size;
$j++
) {
$this->diagram->line(
$j * $gridSize,
$topSpace,
$j * $gridSize,
$this->diagram->getPageHeight() - $bottomSpace
);
$this->diagram->SetXY($j * $gridSize, $topSpace);
$label = (string) sprintf(
'%.0f',
($j * $gridSize - $this->_leftMargin) * $this->_scale + $this->_xMin
);
$this->diagram->Cell($labelWidth, $labelHeight, $label);
}
}
/**
* Draws relation arrows
*
* @return void
*
* @see Relation_Stats_Pdf::relationdraw()
*/
private function _drawRelations()
{
$i = 0;
foreach ($this->relations as $relation) {
$relation->relationDraw($this->showColor, $i);
$i++;
}
}
/**
* Draws tables
*
* @return void
*
* @see Table_Stats_Pdf::tableDraw()
*/
private function _drawTables()
{
foreach ($this->_tables as $table) {
$table->tableDraw(null, $this->_withDoc, $this->showColor);
}
}
/**
* Generates data dictionary pages.
*
* @param array $alltables Tables to document.
*
* @return void
*/
public function dataDictionaryDoc($alltables)
{
// TOC
$this->diagram->addpage($this->orientation);
$this->diagram->Cell(0, 9, __('Table of contents'), 1, 0, 'C');
$this->diagram->Ln(15);
$i = 1;
foreach ($alltables as $table) {
$this->diagram->PMA_links['doc'][$table]['-']
= $this->diagram->AddLink();
$this->diagram->SetX(10);
// $this->diagram->Ln(1);
$this->diagram->Cell(
0, 6, __('Page number:') . ' {' . sprintf("%02d", $i) . '}', 0, 0,
'R', 0, $this->diagram->PMA_links['doc'][$table]['-']
);
$this->diagram->SetX(10);
$this->diagram->Cell(
0, 6, $i . ' ' . $table, 0, 1,
'L', 0, $this->diagram->PMA_links['doc'][$table]['-']
);
// $this->diagram->Ln(1);
$fields = $GLOBALS['dbi']->getColumns($this->db, $table);
foreach ($fields as $row) {
$this->diagram->SetX(20);
$field_name = $row['Field'];
$this->diagram->PMA_links['doc'][$table][$field_name]
= $this->diagram->AddLink();
//$this->diagram->Cell(
// 0, 6, $field_name, 0, 1,
// 'L', 0, $this->diagram->PMA_links['doc'][$table][$field_name]
//);
}
$i++;
}
$this->diagram->PMA_links['RT']['-'] = $this->diagram->AddLink();
$this->diagram->SetX(10);
$this->diagram->Cell(
0, 6, __('Page number:') . ' {00}', 0, 0,
'R', 0, $this->diagram->PMA_links['RT']['-']
);
$this->diagram->SetX(10);
$this->diagram->Cell(
0, 6, $i . ' ' . __('Relational schema'), 0, 1,
'L', 0, $this->diagram->PMA_links['RT']['-']
);
$z = 0;
foreach ($alltables as $table) {
$z++;
$this->diagram->SetAutoPageBreak(true, 15);
$this->diagram->addpage($this->orientation);
$this->diagram->Bookmark($table);
$this->diagram->SetAlias(
'{' . sprintf("%02d", $z) . '}', $this->diagram->PageNo()
);
$this->diagram->PMA_links['RT'][$table]['-']
= $this->diagram->AddLink();
$this->diagram->SetLink(
$this->diagram->PMA_links['doc'][$table]['-'], -1
);
$this->diagram->SetFont($this->_ff, 'B', 18);
$this->diagram->Cell(
0, 8, $z . ' ' . $table, 1, 1,
'C', 0, $this->diagram->PMA_links['RT'][$table]['-']
);
$this->diagram->SetFont($this->_ff, '', 8);
$this->diagram->ln();
$cfgRelation = PMA_getRelationsParam();
$comments = PMA_getComments($this->db, $table);
if ($cfgRelation['mimework']) {
$mime_map = PMA_getMIME($this->db, $table, true);
}
/**
* Gets table information
*/
$showtable = $GLOBALS['dbi']->getTable($this->db, $table)
->getStatusInfo();
$show_comment = isset($showtable['Comment'])
? $showtable['Comment']
: '';
$create_time = isset($showtable['Create_time'])
? Util::localisedDate(
strtotime($showtable['Create_time'])
)
: '';
$update_time = isset($showtable['Update_time'])
? Util::localisedDate(
strtotime($showtable['Update_time'])
)
: '';
$check_time = isset($showtable['Check_time'])
? Util::localisedDate(
strtotime($showtable['Check_time'])
)
: '';
/**
* Gets fields properties
*/
$columns = $GLOBALS['dbi']->getColumns($this->db, $table);
// Find which tables are related with the current one and write it in
// an array
$res_rel = PMA_getForeigners($this->db, $table);
/**
* Displays the comments of the table if MySQL >= 3.23
*/
$break = false;
if (! empty($show_comment)) {
$this->diagram->Cell(
0, 3, __('Table comments:') . ' ' . $show_comment, 0, 1
);
$break = true;
}
if (! empty($create_time)) {
$this->diagram->Cell(
0, 3, __('Creation:') . ' ' . $create_time, 0, 1
);
$break = true;
}
if (! empty($update_time)) {
$this->diagram->Cell(
0, 3, __('Last update:') . ' ' . $update_time, 0, 1
);
$break = true;
}
if (! empty($check_time)) {
$this->diagram->Cell(
0, 3, __('Last check:') . ' ' . $check_time, 0, 1
);
$break = true;
}
if ($break == true) {
$this->diagram->Cell(0, 3, '', 0, 1);
$this->diagram->Ln();
}
$this->diagram->SetFont($this->_ff, 'B');
if (isset($this->orientation) && $this->orientation == 'L') {
$this->diagram->Cell(25, 8, __('Column'), 1, 0, 'C');
$this->diagram->Cell(20, 8, __('Type'), 1, 0, 'C');
$this->diagram->Cell(20, 8, __('Attributes'), 1, 0, 'C');
$this->diagram->Cell(10, 8, __('Null'), 1, 0, 'C');
$this->diagram->Cell(20, 8, __('Default'), 1, 0, 'C');
$this->diagram->Cell(25, 8, __('Extra'), 1, 0, 'C');
$this->diagram->Cell(45, 8, __('Links to'), 1, 0, 'C');
if ($this->paper == 'A4') {
$comments_width = 67;
} else {
// this is really intended for 'letter'
/**
* @todo find optimal width for all formats
*/
$comments_width = 50;
}
$this->diagram->Cell($comments_width, 8, __('Comments'), 1, 0, 'C');
$this->diagram->Cell(45, 8, 'MIME', 1, 1, 'C');
$this->diagram->SetWidths(
array(25, 20, 20, 10, 20, 25, 45, $comments_width, 45)
);
} else {
$this->diagram->Cell(20, 8, __('Column'), 1, 0, 'C');
$this->diagram->Cell(20, 8, __('Type'), 1, 0, 'C');
$this->diagram->Cell(20, 8, __('Attributes'), 1, 0, 'C');
$this->diagram->Cell(10, 8, __('Null'), 1, 0, 'C');
$this->diagram->Cell(15, 8, __('Default'), 1, 0, 'C');
$this->diagram->Cell(15, 8, __('Extra'), 1, 0, 'C');
$this->diagram->Cell(30, 8, __('Links to'), 1, 0, 'C');
$this->diagram->Cell(30, 8, __('Comments'), 1, 0, 'C');
$this->diagram->Cell(30, 8, 'MIME', 1, 1, 'C');
$this->diagram->SetWidths(array(20, 20, 20, 10, 15, 15, 30, 30, 30));
}
$this->diagram->SetFont($this->_ff, '');
foreach ($columns as $row) {
$extracted_columnspec
= Util::extractColumnSpec($row['Type']);
$type = $extracted_columnspec['print_type'];
$attribute = $extracted_columnspec['attribute'];
if (! isset($row['Default'])) {
if ($row['Null'] != '' && $row['Null'] != 'NO') {
$row['Default'] = 'NULL';
}
}
$field_name = $row['Field'];
// $this->diagram->Ln();
$this->diagram->PMA_links['RT'][$table][$field_name]
= $this->diagram->AddLink();
$this->diagram->Bookmark($field_name, 1, -1);
$this->diagram->SetLink(
$this->diagram->PMA_links['doc'][$table][$field_name], -1
);
$foreigner = PMA_searchColumnInForeigners($res_rel, $field_name);
$linksTo = '';
if ($foreigner) {
$linksTo = '-> ';
if ($foreigner['foreign_db'] != $this->db) {
$linksTo .= $foreigner['foreign_db'] . '.';
}
$linksTo .= $foreigner['foreign_table']
. '.' . $foreigner['foreign_field'];
if (isset($foreigner['on_update'])) { // not set for internal
$linksTo .= "\n" . 'ON UPDATE ' . $foreigner['on_update'];
$linksTo .= "\n" . 'ON DELETE ' . $foreigner['on_delete'];
}
}
$this->diagram_row = array(
$field_name,
$type,
$attribute,
(($row['Null'] == '' || $row['Null'] == 'NO')
? __('No')
: __('Yes')),
(isset($row['Default']) ? $row['Default'] : ''),
$row['Extra'],
$linksTo,
(isset($comments[$field_name])
? $comments[$field_name]
: ''),
(isset($mime_map) && isset($mime_map[$field_name])
? str_replace('_', '/', $mime_map[$field_name]['mimetype'])
: '')
);
$links = array();
$links[0] = $this->diagram->PMA_links['RT'][$table][$field_name];
if ($foreigner
&& isset($this->diagram->PMA_links['doc'][$foreigner['foreign_table']][$foreigner['foreign_field']])
) {
$links[6] = $this->diagram->PMA_links['doc']
[$foreigner['foreign_table']][$foreigner['foreign_field']];
} else {
unset($links[6]);
}
$this->diagram->Row($this->diagram_row, $links);
} // end foreach
$this->diagram->SetFont($this->_ff, '', 14);
} //end each
}
}

View File

@ -0,0 +1,130 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Contains PMA\libraries\plugins\schema\pdf\RelationStatsPdf class
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins\schema\pdf;
use PMA\libraries\plugins\schema\RelationStats;
/**
* Relation preferences/statistics
*
* This class fetches the table master and foreign fields positions
* and helps in generating the Table references and then connects
* master table's master field to foreign table's foreign key
* in PDF document.
*
* @name Relation_Stats_Pdf
* @package PhpMyAdmin
* @see PMA_Schema_PDF::SetDrawColor, PMA_Schema_PDF::setLineWidthScale,
* Pdf::lineScale
*/
class RelationStatsPdf extends RelationStats
{
/**
* The "PMA\libraries\plugins\schema\pdf\RelationStatsPdf" constructor
*
* @param object $diagram The PDF diagram
* @param string $master_table The master table name
* @param string $master_field The relation field in the master table
* @param string $foreign_table The foreign table name
* @param string $foreign_field The relation field in the foreign table
*/
public function __construct(
$diagram, $master_table, $master_field, $foreign_table,
$foreign_field
) {
$this->wTick = 5;
parent::__construct(
$diagram, $master_table, $master_field, $foreign_table, $foreign_field
);
}
/**
* draws relation links and arrows shows foreign key relations
*
* @param boolean $showColor Whether to use one color per relation or not
* @param integer $i The id of the link to draw
*
* @access public
*
* @return void
*
* @see Pdf
*/
public function relationDraw($showColor, $i)
{
if ($showColor) {
$d = $i % 6;
$j = ($i - $d) / 6;
$j = $j % 4;
$j++;
$case = array(
array(1, 0, 0),
array(0, 1, 0),
array(0, 0, 1),
array(1, 1, 0),
array(1, 0, 1),
array(0, 1, 1)
);
list ($a, $b, $c) = $case[$d];
$e = (1 - ($j - 1) / 6);
$this->diagram->SetDrawColor($a * 255 * $e, $b * 255 * $e, $c * 255 * $e);
} else {
$this->diagram->SetDrawColor(0);
}
$this->diagram->setLineWidthScale(0.2);
$this->diagram->lineScale(
$this->xSrc,
$this->ySrc,
$this->xSrc + $this->srcDir * $this->wTick,
$this->ySrc
);
$this->diagram->lineScale(
$this->xDest + $this->destDir * $this->wTick,
$this->yDest,
$this->xDest,
$this->yDest
);
$this->diagram->setLineWidthScale(0.1);
$this->diagram->lineScale(
$this->xSrc + $this->srcDir * $this->wTick,
$this->ySrc,
$this->xDest + $this->destDir * $this->wTick,
$this->yDest
);
/*
* Draws arrows ->
*/
$root2 = 2 * sqrt(2);
$this->diagram->lineScale(
$this->xSrc + $this->srcDir * $this->wTick * 0.75,
$this->ySrc,
$this->xSrc + $this->srcDir * (0.75 - 1 / $root2) * $this->wTick,
$this->ySrc + $this->wTick / $root2
);
$this->diagram->lineScale(
$this->xSrc + $this->srcDir * $this->wTick * 0.75,
$this->ySrc,
$this->xSrc + $this->srcDir * (0.75 - 1 / $root2) * $this->wTick,
$this->ySrc - $this->wTick / $root2
);
$this->diagram->lineScale(
$this->xDest + $this->destDir * $this->wTick / 2,
$this->yDest,
$this->xDest + $this->destDir * (0.5 + 1 / $root2) * $this->wTick,
$this->yDest + $this->wTick / $root2
);
$this->diagram->lineScale(
$this->xDest + $this->destDir * $this->wTick / 2,
$this->yDest,
$this->xDest + $this->destDir * (0.5 + 1 / $root2) * $this->wTick,
$this->yDest - $this->wTick / $root2
);
$this->diagram->SetDrawColor(0);
}
}

View File

@ -0,0 +1,232 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Contains PMA\libraries\plugins\schema\pdf\TableStatsPdf class
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins\schema\pdf;
use PMA\libraries\plugins\schema\ExportRelationSchema;
use PMA\libraries\plugins\schema\TableStats;
use PMA\libraries\PDF as PDF_lib;
/**
* Table preferences/statistics
*
* This class preserves the table co-ordinates,fields
* and helps in drawing/generating the Tables in PDF document.
*
* @name Table_Stats_Pdf
* @package PhpMyAdmin
* @see PMA_Schema_PDF
*/
class TableStatsPdf extends TableStats
{
/**
* Defines properties
*/
public $nb_fiels;
public $height;
private $_ff = PDF_lib::PMA_PDF_FONT;
/**
* The "PMA\libraries\plugins\schema\pdf\TableStatsPdf" constructor
*
* @param object $diagram The PDF diagram
* @param string $db The database name
* @param string $tableName The table name
* @param integer $fontSize The font size
* @param integer $pageNumber The current page number (from the
* $cfg['Servers'][$i]['table_coords'] table)
* @param integer &$sameWideWidth The max. width among tables
* @param boolean $showKeys Whether to display keys or not
* @param boolean $tableDimension Whether to display table position or not
* @param boolean $offline Whether the coordinates are sent
* from the browser
*
* @see PMA_Schema_PDF, Table_Stats_Pdf::Table_Stats_setWidth,
* PMA\libraries\plugins\schema\pdf\TableStatsPdf::Table_Stats_setHeight
*/
public function __construct(
$diagram,
$db,
$tableName,
$fontSize,
$pageNumber,
&$sameWideWidth,
$showKeys = false,
$tableDimension = false,
$offline = false
) {
parent::__construct(
$diagram,
$db,
$pageNumber,
$tableName,
$showKeys,
$tableDimension,
$offline
);
$this->heightCell = 6;
$this->_setHeight();
/*
* setWidth must me after setHeight, because title
* can include table height which changes table width
*/
$this->_setWidth($fontSize);
if ($sameWideWidth < $this->width) {
$sameWideWidth = $this->width;
}
}
/**
* Displays an error when the table cannot be found.
*
* @return void
*/
protected function showMissingTableError()
{
ExportRelationSchema::dieSchema(
$this->pageNumber,
"PDF",
sprintf(__('The %s table doesn\'t exist!'), $this->tableName)
);
}
/**
* Returns title of the current table,
* title can have the dimensions of the table
*
* @return string
*/
protected function getTitle()
{
$ret = '';
if ($this->tableDimension) {
$ret = sprintf('%.0fx%0.f', $this->width, $this->height);
}
return $ret . ' ' . $this->tableName;
}
/**
* Sets the width of the table
*
* @param integer $fontSize The font size
*
* @access private
*
* @return void
*
* @see PMA_Schema_PDF
*/
private function _setWidth($fontSize)
{
foreach ($this->fields as $field) {
$this->width = max($this->width, $this->diagram->GetStringWidth($field));
}
$this->width += $this->diagram->GetStringWidth(' ');
$this->diagram->SetFont($this->_ff, 'B', $fontSize);
/*
* it is unknown what value must be added, because
* table title is affected by the table width value
*/
while ($this->width < $this->diagram->GetStringWidth($this->getTitle())) {
$this->width += 5;
}
$this->diagram->SetFont($this->_ff, '', $fontSize);
}
/**
* Sets the height of the table
*
* @return void
*
* @access private
*/
private function _setHeight()
{
$this->height = (count($this->fields) + 1) * $this->heightCell;
}
/**
* Do draw the table
*
* @param integer $fontSize The font size
* @param boolean $withDoc Whether to include links to documentation
* @param boolean|integer $setColor Whether to display color
*
* @access public
*
* @return void
*
* @see PMA_Schema_PDF
*/
public function tableDraw($fontSize, $withDoc, $setColor = 0)
{
$this->diagram->setXyScale($this->x, $this->y);
$this->diagram->SetFont($this->_ff, 'B', $fontSize);
if ($setColor) {
$this->diagram->SetTextColor(200);
$this->diagram->SetFillColor(0, 0, 128);
}
if ($withDoc) {
$this->diagram->SetLink(
$this->diagram->PMA_links['RT'][$this->tableName]['-'],
-1
);
} else {
$this->diagram->PMA_links['doc'][$this->tableName]['-'] = '';
}
$this->diagram->cellScale(
$this->width,
$this->heightCell,
$this->getTitle(),
1,
1,
'C',
$setColor,
$this->diagram->PMA_links['doc'][$this->tableName]['-']
);
$this->diagram->setXScale($this->x);
$this->diagram->SetFont($this->_ff, '', $fontSize);
$this->diagram->SetTextColor(0);
$this->diagram->SetFillColor(255);
foreach ($this->fields as $field) {
if ($setColor) {
if (in_array($field, $this->primary)) {
$this->diagram->SetFillColor(215, 121, 123);
}
if ($field == $this->displayfield) {
$this->diagram->SetFillColor(142, 159, 224);
}
}
if ($withDoc) {
$this->diagram->SetLink(
$this->diagram->PMA_links['RT'][$this->tableName][$field],
-1
);
} else {
$this->diagram->PMA_links['doc'][$this->tableName][$field] = '';
}
$this->diagram->cellScale(
$this->width,
$this->heightCell,
' ' . $field,
1,
1,
'L',
$setColor,
$this->diagram->PMA_links['doc'][$this->tableName][$field]
);
$this->diagram->setXScale($this->x);
$this->diagram->SetFillColor(255);
}
}
}

View File

@ -0,0 +1,138 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Contains PMA\libraries\plugins\schema\svg\RelationStatsSvg class
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins\schema\svg;
use PMA\libraries\plugins\schema\RelationStats;
/**
* Relation preferences/statistics
*
* This class fetches the table master and foreign fields positions
* and helps in generating the Table references and then connects
* master table's master field to foreign table's foreign key
* in SVG XML document.
*
* @package PhpMyAdmin
* @name Relation_Stats_Svg
* @see PMA_SVG::printElementLine
*/
class RelationStatsSvg extends RelationStats
{
/**
* The "PMA\libraries\plugins\schema\svg\RelationStatsSvg" constructor
*
* @param object $diagram The SVG diagram
* @param string $master_table The master table name
* @param string $master_field The relation field in the master table
* @param string $foreign_table The foreign table name
* @param string $foreign_field The relation field in the foreign table
*/
public function __construct(
$diagram,
$master_table,
$master_field,
$foreign_table,
$foreign_field
) {
$this->wTick = 10;
parent::__construct(
$diagram,
$master_table,
$master_field,
$foreign_table,
$foreign_field
);
}
/**
* draws relation links and arrows shows foreign key relations
*
* @param boolean $showColor Whether to use one color per relation or not
*
* @return void
* @access public
*
* @see PMA_SVG
*/
public function relationDraw($showColor)
{
if ($showColor) {
$listOfColors = array(
'#c00',
'#bbb',
'#333',
'#cb0',
'#0b0',
'#0bf',
'#b0b',
);
shuffle($listOfColors);
$color = $listOfColors[0];
} else {
$color = '#333';
}
$this->diagram->printElementLine(
'line',
$this->xSrc,
$this->ySrc,
$this->xSrc + $this->srcDir * $this->wTick,
$this->ySrc,
'stroke:' . $color . ';stroke-width:1;'
);
$this->diagram->printElementLine(
'line',
$this->xDest + $this->destDir * $this->wTick,
$this->yDest,
$this->xDest,
$this->yDest,
'stroke:' . $color . ';stroke-width:1;'
);
$this->diagram->printElementLine(
'line',
$this->xSrc + $this->srcDir * $this->wTick,
$this->ySrc,
$this->xDest + $this->destDir * $this->wTick,
$this->yDest,
'stroke:' . $color . ';stroke-width:1;'
);
$root2 = 2 * sqrt(2);
$this->diagram->printElementLine(
'line',
$this->xSrc + $this->srcDir * $this->wTick * 0.75,
$this->ySrc,
$this->xSrc + $this->srcDir * (0.75 - 1 / $root2) * $this->wTick,
$this->ySrc + $this->wTick / $root2,
'stroke:' . $color . ';stroke-width:2;'
);
$this->diagram->printElementLine(
'line',
$this->xSrc + $this->srcDir * $this->wTick * 0.75,
$this->ySrc,
$this->xSrc + $this->srcDir * (0.75 - 1 / $root2) * $this->wTick,
$this->ySrc - $this->wTick / $root2,
'stroke:' . $color . ';stroke-width:2;'
);
$this->diagram->printElementLine(
'line',
$this->xDest + $this->destDir * $this->wTick / 2,
$this->yDest,
$this->xDest + $this->destDir * (0.5 + 1 / $root2) * $this->wTick,
$this->yDest + $this->wTick / $root2,
'stroke:' . $color . ';stroke-width:2;'
);
$this->diagram->printElementLine(
'line',
$this->xDest + $this->destDir * $this->wTick / 2,
$this->yDest,
$this->xDest + $this->destDir * (0.5 + 1 / $root2) * $this->wTick,
$this->yDest - $this->wTick / $root2,
'stroke:' . $color . ';stroke-width:2;'
);
}
}

View File

@ -0,0 +1,279 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Classes to create relation schema in SVG format.
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins\schema\svg;
use PMA;
use XMLWriter;
/**
* This Class inherits the XMLwriter class and
* helps in developing structure of SVG Schema Export
*
* @package PhpMyAdmin
* @access public
* @see https://php.net/manual/en/book.xmlwriter.php
*/
class Svg extends XMLWriter
{
public $title;
public $author;
public $font;
public $fontSize;
/**
* The "PMA\libraries\plugins\schema\svg\Svg" constructor
*
* Upon instantiation This starts writing the RelationStatsSvg XML document
*
* @see XMLWriter::openMemory(),XMLWriter::setIndent(),XMLWriter::startDocument()
*/
public function __construct()
{
$this->openMemory();
/*
* Set indenting using three spaces,
* so output is formatted
*/
$this->setIndent(true);
$this->setIndentString(' ');
/*
* Create the XML document
*/
$this->startDocument('1.0', 'UTF-8');
$this->startDtd(
'svg',
'-//W3C//DTD SVG 1.1//EN',
'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'
);
$this->endDtd();
}
/**
* Set document title
*
* @param string $value sets the title text
*
* @return void
*/
public function setTitle($value)
{
$this->title = $value;
}
/**
* Set document author
*
* @param string $value sets the author
*
* @return void
*/
public function setAuthor($value)
{
$this->author = $value;
}
/**
* Set document font
*
* @param string $value sets the font e.g Arial, Sans-serif etc
*
* @return void
*/
public function setFont($value)
{
$this->font = $value;
}
/**
* Get document font
*
* @return string returns the font name
*/
public function getFont()
{
return $this->font;
}
/**
* Set document font size
*
* @param string $value sets the font size in pixels
*
* @return void
*/
public function setFontSize($value)
{
$this->fontSize = $value;
}
/**
* Get document font size
*
* @return string returns the font size
*/
public function getFontSize()
{
return $this->fontSize;
}
/**
* Starts RelationStatsSvg Document
*
* svg document starts by first initializing svg tag
* which contains all the attributes and namespace that needed
* to define the svg document
*
* @param integer $width total width of the RelationStatsSvg document
* @param integer $height total height of the RelationStatsSvg document
* @param integer $x min-x of the view box
* @param integer $y min-y of the view box
*
* @return void
*
* @see XMLWriter::startElement(),XMLWriter::writeAttribute()
*/
public function startSvgDoc($width, $height, $x = 0, $y = 0)
{
$this->startElement('svg');
if (!is_int($width)) {
$width = intval($width);
}
if (!is_int($height)) {
$height = intval($height);
}
if ($x != 0 || $y != 0) {
$this->writeAttribute('viewBox', "$x $y $width $height");
}
$this->writeAttribute('width', ($width - $x) . 'px');
$this->writeAttribute('height', ($height - $y) . 'px');
$this->writeAttribute('xmlns', 'http://www.w3.org/2000/svg');
$this->writeAttribute('version', '1.1');
}
/**
* Ends RelationStatsSvg Document
*
* @return void
* @see XMLWriter::endElement(),XMLWriter::endDocument()
*/
public function endSvgDoc()
{
$this->endElement();
$this->endDocument();
}
/**
* output RelationStatsSvg Document
*
* svg document prompted to the user for download
* RelationStatsSvg document saved in .svg extension and can be
* easily changeable by using any svg IDE
*
* @param string $fileName file name
*
* @return void
* @see XMLWriter::startElement(),XMLWriter::writeAttribute()
*/
public function showOutput($fileName)
{
//ob_get_clean();
$output = $this->flush();
PMA\libraries\Response::getInstance()
->disable();
PMA_downloadHeader(
$fileName,
'image/svg+xml',
strlen($output)
);
print $output;
}
/**
* Draws RelationStatsSvg elements
*
* SVG has some predefined shape elements like rectangle & text
* and other elements who have x,y co-ordinates are drawn.
* specify their width and height and can give styles too.
*
* @param string $name RelationStatsSvg element name
* @param int $x The x attr defines the left position of the element
* (e.g. x="0" places the element 0 pixels from the
* left of the browser window)
* @param integer $y The y attribute defines the top position of the
* element (e.g. y="0" places the element 0 pixels
* from the top of the browser window)
* @param int|string $width The width attribute defines the width the element
* @param int|string $height The height attribute defines the height the element
* @param string $text The text attribute defines the text the element
* @param string $styles The style attribute defines the style the element
* styles can be defined like CSS styles
*
* @return void
*
* @see XMLWriter::startElement(), XMLWriter::writeAttribute(),
* XMLWriter::text(), XMLWriter::endElement()
*/
public function printElement(
$name,
$x,
$y,
$width = '',
$height = '',
$text = '',
$styles = ''
) {
$this->startElement($name);
$this->writeAttribute('width', $width);
$this->writeAttribute('height', $height);
$this->writeAttribute('x', $x);
$this->writeAttribute('y', $y);
$this->writeAttribute('style', $styles);
if (isset($text)) {
$this->writeAttribute('font-family', $this->font);
$this->writeAttribute('font-size', $this->fontSize);
$this->text($text);
}
$this->endElement();
}
/**
* Draws RelationStatsSvg Line element
*
* RelationStatsSvg line element is drawn for connecting the tables.
* arrows are also drawn by specify its start and ending
* co-ordinates
*
* @param string $name RelationStatsSvg element name i.e line
* @param integer $x1 Defines the start of the line on the x-axis
* @param integer $y1 Defines the start of the line on the y-axis
* @param integer $x2 Defines the end of the line on the x-axis
* @param integer $y2 Defines the end of the line on the y-axis
* @param string $styles The style attribute defines the style the element
* styles can be defined like CSS styles
*
* @return void
*
* @see XMLWriter::startElement(), XMLWriter::writeAttribute(),
* XMLWriter::endElement()
*/
public function printElementLine($name, $x1, $y1, $x2, $y2, $styles)
{
$this->startElement($name);
$this->writeAttribute('x1', $x1);
$this->writeAttribute('y1', $y1);
$this->writeAttribute('x2', $x2);
$this->writeAttribute('y2', $y2);
$this->writeAttribute('style', $styles);
$this->endElement();
}
}

View File

@ -0,0 +1,267 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Contains PMA\libraries\plugins\schema\svg\RelationStatsSvg class
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins\schema\svg;
use PMA\libraries\plugins\schema\dia\RelationStatsDia;
use PMA\libraries\plugins\schema\eps\TableStatsEps;
use PMA\libraries\plugins\schema\ExportRelationSchema;
use PMA\libraries\plugins\schema\pdf\TableStatsPdf;
use PMA\libraries\plugins\schema\svg\Svg;
use PMA\libraries\plugins\schema\svg\TableStatsSvg;
use PMA\libraries\plugins\schema\dia\TableStatsDia;
/**
* RelationStatsSvg Relation Schema Class
*
* Purpose of this class is to generate the SVG XML Document because
* SVG defines the graphics in XML format which is used for representing
* the database diagrams as vector image. This class actually helps
* in preparing SVG XML format.
*
* SVG XML is generated by using XMLWriter php extension and this class
* inherits ExportRelationSchema class has common functionality added
* to this class
*
* @package PhpMyAdmin
* @name Svg_Relation_Schema
*/
class SvgRelationSchema extends ExportRelationSchema
{
/**
* @var \PMA\libraries\plugins\schema\dia\TableStatsDia[]|TableStatsEps[]|TableStatsPdf[]|TableStatsSvg[]
*/
private $_tables = array();
/** @var RelationStatsDia[] Relations */
private $_relations = array();
private $_xMax = 0;
private $_yMax = 0;
private $_xMin = 100000;
private $_yMin = 100000;
private $_tablewidth;
/**
* The "PMA\libraries\plugins\schema\svg\SvgRelationSchema" constructor
*
* Upon instantiation This starts writing the SVG XML document
* user will be prompted for download as .svg extension
*
* @param string $db database name
*
* @see PMA_SVG
*/
function __construct($db)
{
parent::__construct($db, new Svg());
$this->setShowColor(isset($_REQUEST['svg_show_color']));
$this->setShowKeys(isset($_REQUEST['svg_show_keys']));
$this->setTableDimension(isset($_REQUEST['svg_show_table_dimension']));
$this->setAllTablesSameWidth(isset($_REQUEST['svg_all_tables_same_width']));
$this->diagram->setTitle(
sprintf(
__('Schema of the %s database - Page %s'),
$this->db,
$this->pageNumber
)
);
$this->diagram->SetAuthor('phpMyAdmin ' . PMA_VERSION);
$this->diagram->setFont('Arial');
$this->diagram->setFontSize('16px');
$alltables = $this->getTablesFromRequest();
foreach ($alltables as $table) {
if (!isset($this->_tables[$table])) {
$this->_tables[$table] = new TableStatsSvg(
$this->diagram, $this->db,
$table, $this->diagram->getFont(),
$this->diagram->getFontSize(), $this->pageNumber,
$this->_tablewidth, $this->showKeys, $this->tableDimension,
$this->offline
);
}
if ($this->sameWide) {
$this->_tables[$table]->width = &$this->_tablewidth;
}
$this->_setMinMax($this->_tables[$table]);
}
$border = 15;
$this->diagram->startSvgDoc(
$this->_xMax + $border,
$this->_yMax + $border,
$this->_xMin - $border,
$this->_yMin - $border
);
$seen_a_relation = false;
foreach ($alltables as $one_table) {
$exist_rel = PMA_getForeigners($this->db, $one_table, '', 'both');
if (!$exist_rel) {
continue;
}
$seen_a_relation = true;
foreach ($exist_rel as $master_field => $rel) {
/* put the foreign table on the schema only if selected
* by the user
* (do not use array_search() because we would have to
* to do a === false and this is not PHP3 compatible)
*/
if ($master_field != 'foreign_keys_data') {
if (in_array($rel['foreign_table'], $alltables)) {
$this->_addRelation(
$one_table,
$this->diagram->getFont(),
$this->diagram->getFontSize(),
$master_field,
$rel['foreign_table'],
$rel['foreign_field'],
$this->tableDimension
);
}
continue;
}
foreach ($rel as $one_key) {
if (!in_array($one_key['ref_table_name'], $alltables)) {
continue;
}
foreach (
$one_key['index_list']
as $index => $one_field
) {
$this->_addRelation(
$one_table,
$this->diagram->getFont(),
$this->diagram->getFontSize(),
$one_field,
$one_key['ref_table_name'],
$one_key['ref_index_list'][$index],
$this->tableDimension
);
}
}
}
}
if ($seen_a_relation) {
$this->_drawRelations();
}
$this->_drawTables();
$this->diagram->endSvgDoc();
}
/**
* Output RelationStatsSvg Document for download
*
* @return void
*/
public function showOutput()
{
$this->diagram->showOutput($this->getFileName('.svg'));
}
/**
* Sets X and Y minimum and maximum for a table cell
*
* @param string $table The table name
*
* @return void
*/
private function _setMinMax($table)
{
$this->_xMax = max($this->_xMax, $table->x + $table->width);
$this->_yMax = max($this->_yMax, $table->y + $table->height);
$this->_xMin = min($this->_xMin, $table->x);
$this->_yMin = min($this->_yMin, $table->y);
}
/**
* Defines relation objects
*
* @param string $masterTable The master table name
* @param string $font The font face
* @param int $fontSize Font size
* @param string $masterField The relation field in the master table
* @param string $foreignTable The foreign table name
* @param string $foreignField The relation field in the foreign table
* @param boolean $tableDimension Whether to display table position or not
*
* @return void
*
* @see _setMinMax,Table_Stats_Svg::__construct(),
* PMA\libraries\plugins\schema\svg\RelationStatsSvg::__construct()
*/
private function _addRelation(
$masterTable,
$font,
$fontSize,
$masterField,
$foreignTable,
$foreignField,
$tableDimension
) {
if (!isset($this->_tables[$masterTable])) {
$this->_tables[$masterTable] = new TableStatsSvg(
$this->diagram, $this->db,
$masterTable, $font, $fontSize, $this->pageNumber,
$this->_tablewidth, false, $tableDimension
);
$this->_setMinMax($this->_tables[$masterTable]);
}
if (!isset($this->_tables[$foreignTable])) {
$this->_tables[$foreignTable] = new TableStatsSvg(
$this->diagram, $this->db,
$foreignTable, $font, $fontSize, $this->pageNumber,
$this->_tablewidth, false, $tableDimension
);
$this->_setMinMax($this->_tables[$foreignTable]);
}
$this->_relations[] = new RelationStatsSvg(
$this->diagram,
$this->_tables[$masterTable],
$masterField,
$this->_tables[$foreignTable],
$foreignField
);
}
/**
* Draws relation arrows and lines
* connects master table's master field to
* foreign table's foreign field
*
* @return void
*
* @see Relation_Stats_Svg::relationDraw()
*/
private function _drawRelations()
{
foreach ($this->_relations as $relation) {
$relation->relationDraw($this->showColor);
}
}
/**
* Draws tables
*
* @return void
*
* @see Table_Stats_Svg::Table_Stats_tableDraw()
*/
private function _drawTables()
{
foreach ($this->_tables as $table) {
$table->tableDraw($this->showColor);
}
}
}

View File

@ -0,0 +1,202 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Contains PMA\libraries\plugins\schema\svg\TableStatsSvg class
*
* @package PhpMyAdmin
*/
namespace PMA\libraries\plugins\schema\svg;
use PMA;
use PMA\libraries\plugins\schema\ExportRelationSchema;
use PMA\libraries\plugins\schema\TableStats;
/**
* Table preferences/statistics
*
* This class preserves the table co-ordinates,fields
* and helps in drawing/generating the Tables in SVG XML document.
*
* @package PhpMyAdmin
* @name Table_Stats_Svg
* @see PMA_SVG
*/
class TableStatsSvg extends TableStats
{
/**
* Defines properties
*/
public $height;
public $currentCell = 0;
/**
* The "PMA\libraries\plugins\schema\svg\TableStatsSvg" constructor
*
* @param object $diagram The current SVG image document
* @param string $db The database name
* @param string $tableName The table name
* @param string $font Font face
* @param integer $fontSize The font size
* @param integer $pageNumber Page number
* @param integer &$same_wide_width The max. width among tables
* @param boolean $showKeys Whether to display keys or not
* @param boolean $tableDimension Whether to display table position or not
* @param boolean $offline Whether the coordinates are sent
*
*
* @see PMA_SVG, Table_Stats_Svg::Table_Stats_setWidth,
* PMA\libraries\plugins\schema\svg\TableStatsSvg::Table_Stats_setHeight
*/
public function __construct(
$diagram,
$db,
$tableName,
$font,
$fontSize,
$pageNumber,
&$same_wide_width,
$showKeys = false,
$tableDimension = false,
$offline = false
) {
parent::__construct(
$diagram,
$db,
$pageNumber,
$tableName,
$showKeys,
$tableDimension,
$offline
);
// height and width
$this->_setHeightTable($fontSize);
// setWidth must me after setHeight, because title
// can include table height which changes table width
$this->_setWidthTable($font, $fontSize);
if ($same_wide_width < $this->width) {
$same_wide_width = $this->width;
}
}
/**
* Displays an error when the table cannot be found.
*
* @return void
*/
protected function showMissingTableError()
{
ExportRelationSchema::dieSchema(
$this->pageNumber,
"SVG",
sprintf(__('The %s table doesn\'t exist!'), $this->tableName)
);
}
/**
* Sets the width of the table
*
* @param string $font The font size
* @param integer $fontSize The font size
*
* @return void
* @access private
*
* @see PMA_SVG
*/
private function _setWidthTable($font, $fontSize)
{
foreach ($this->fields as $field) {
$this->width = max(
$this->width,
PMA\libraries\Font::getStringWidth($field, $font, $fontSize)
);
}
$this->width += PMA\libraries\Font::getStringWidth(' ', $font, $fontSize);
/*
* it is unknown what value must be added, because
* table title is affected by the table width value
*/
while ($this->width
< PMA\libraries\Font::getStringWidth($this->getTitle(), $font, $fontSize)
) {
$this->width += 7;
}
}
/**
* Sets the height of the table
*
* @param integer $fontSize font size
*
* @return void
*/
private function _setHeightTable($fontSize)
{
$this->heightCell = $fontSize + 4;
$this->height = (count($this->fields) + 1) * $this->heightCell;
}
/**
* draw the table
*
* @param boolean $showColor Whether to display color
*
* @access public
* @return void
*
* @see PMA_SVG,PMA_SVG::printElement
*/
public function tableDraw($showColor)
{
$this->diagram->printElement(
'rect',
$this->x,
$this->y,
$this->width,
$this->heightCell,
null,
'fill:#007;stroke:black;'
);
$this->diagram->printElement(
'text',
$this->x + 5,
$this->y + 14,
$this->width,
$this->heightCell,
$this->getTitle(),
'fill:#fff;'
);
foreach ($this->fields as $field) {
$this->currentCell += $this->heightCell;
$fillColor = 'none';
if ($showColor) {
if (in_array($field, $this->primary)) {
$fillColor = '#aea';
}
if ($field == $this->displayfield) {
$fillColor = 'none';
}
}
$this->diagram->printElement(
'rect',
$this->x,
$this->y + $this->currentCell,
$this->width,
$this->heightCell,
null,
'fill:' . $fillColor . ';stroke:black;'
);
$this->diagram->printElement(
'text',
$this->x + 5,
$this->y + 14 + $this->currentCell,
$this->width,
$this->heightCell,
$field,
'fill:black;'
);
}
}
}

View File

@ -0,0 +1,4 @@
TRANSFORMATION USAGE (Garvin Hicking, <me@supergarv.de>)
====================
See the documentation for complete instructions on how to use transformation plugins.

View File

@ -0,0 +1,47 @@
<?php
// vim: expandtab sw=4 ts=4 sts=4:
/**
* This file contains the basic structure for a specific MIME Type and Subtype
* transformations class.
* For instructions, read the documentation
*
* @package PhpMyAdmin-Transformations
* @subpackage [TransformationName]
*/
namespace PMA\libraries\plugins\transformations;
use PMA\libraries\plugins\transformations\abs\[TransformationName]TransformationsPlugin;
if (! defined('PHPMYADMIN')) {
exit;
}
/**
* Handles the [TransformationName] transformation for [MIMEType] - [MIMESubtype]
*
* @package PhpMyAdmin
*/
class [MIMEType][MIMESubtype][TransformationName]
extends [TransformationName]TransformationsPlugin
{
/**
* Gets the plugin`s MIME type
*
* @return string
*/
public static function getMIMEType()
{
return "[MIMEType]";
}
/**
* Gets the plugin`s MIME subtype
*
* @return string
*/
public static function getMIMESubtype()
{
return "[MIMESubtype]";
}
}
?>

View File

@ -0,0 +1,74 @@
<?php
// vim: expandtab sw=4 ts=4 sts=4:
/**
* This file contains the basic structure for an abstract class defining a
* transformation.
* For instructions, read the documentation
*
* @package PhpMyAdmin-Transformations
* @subpackage [TransformationName]
*/
namespace PMA\libraries\plugins\transformations\abs;
use PMA\libraries\plugins\IOTransformationsPlugin;
if (! defined('PHPMYADMIN')) {
exit;
}
/**
* Provides common methods for all of the [TransformationName] transformations plugins.
*
* @package PhpMyAdmin
*/
abstract class [TransformationName]TransformationsPlugin
extends IOTransformationsPlugin
{
/**
* Gets the transformation description of the specific plugin
*
* @return string
*/
public static function getInfo()
{
return __(
'Description of the transformation.'
);
}
/**
* Does the actual work of each specific transformations plugin.
*
* @param string $buffer text to be transformed
* @param array $options transformation options
* @param string $meta meta information
*
* @return void
*/
public function applyTransformation($buffer, $options = array(), $meta = '')
{
// possibly use a global transform and feed it with special options
// further operations on $buffer using the $options[] array.
// You can evaluate the propagated $meta Object. It's contained fields are described in https://www.php.net/mysql_fetch_field.
// This stored information can be used to get the field information about the transformed field.
// $meta->mimetype contains the original MimeType of the field (i.e. 'text/plain', 'image/jpeg' etc.)
return $buffer;
}
/* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */
/**
* Gets the TransformationName of the specific plugin
*
* @return string
*/
public static function getName()
{
return "[TransformationName]";
}
}
?>

View File

@ -0,0 +1,40 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Text Plain Link Transformations plugin for phpMyAdmin
*
* @package PhpMyAdmin-Transformations
* @subpackage Link
*/
namespace PMA\libraries\plugins\transformations;
use PMA\libraries\plugins\transformations\abs\TextLinkTransformationsPlugin;
/**
* Handles the link transformation for text plain
*
* @package PhpMyAdmin-Transformations
* @subpackage Link
*/
class Text_Plain_Link extends TextLinkTransformationsPlugin
{
/**
* Gets the plugin`s MIME type
*
* @return string
*/
public static function getMIMEType()
{
return "Text";
}
/**
* Gets the plugin`s MIME subtype
*
* @return string
*/
public static function getMIMESubtype()
{
return "Plain";
}
}

View File

@ -0,0 +1,40 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Text Plain Long To IPv4 Transformations plugin for phpMyAdmin
*
* @package PhpMyAdmin-Transformations
* @subpackage LongToIPv4
*/
namespace PMA\libraries\plugins\transformations;
use PMA\libraries\plugins\transformations\abs\LongToIPv4TransformationsPlugin;
/**
* Handles the long to ipv4 transformation for text plain
*
* @package PhpMyAdmin-Transformations
* @subpackage LongToIPv4
*/
class Text_Plain_Longtoipv4 extends LongToIPv4TransformationsPlugin
{
/**
* Gets the plugin`s MIME type
*
* @return string
*/
public static function getMIMEType()
{
return "Text";
}
/**
* Gets the plugin`s MIME subtype
*
* @return string
*/
public static function getMIMESubtype()
{
return "Plain";
}
}

View File

@ -0,0 +1,41 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Text Plain Prepend/Append Transformations plugin for phpMyAdmin
*
* @package PhpMyAdmin-Transformations
* @subpackage PreApPend
*/
namespace PMA\libraries\plugins\transformations;
use PMA\libraries\plugins\transformations\abs\PreApPendTransformationsPlugin;
/**
* Handles the prepend and/or append transformation for text plain.
* Has two options: the text to be prepended and appended (if any, default '')
*
* @package PhpMyAdmin-Transformations
* @subpackage PreApPend
*/
class Text_Plain_PreApPend extends PreApPendTransformationsPlugin
{
/**
* Gets the plugin`s MIME type
*
* @return string
*/
public static function getMIMEType()
{
return "Text";
}
/**
* Gets the plugin`s MIME subtype
*
* @return string
*/
public static function getMIMESubtype()
{
return "Plain";
}
}

View File

@ -0,0 +1,40 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Text Plain Substring Transformations plugin for phpMyAdmin
*
* @package PhpMyAdmin-Transformations
* @subpackage Substring
*/
namespace PMA\libraries\plugins\transformations;
use PMA\libraries\plugins\transformations\abs\SubstringTransformationsPlugin;
/**
* Handles the substring transformation for text plain
*
* @package PhpMyAdmin-Transformations
* @subpackage Substring
*/
class Text_Plain_Substring extends SubstringTransformationsPlugin
{
/**
* Gets the plugin`s MIME type
*
* @return string
*/
public static function getMIMEType()
{
return "Text";
}
/**
* Gets the plugin`s MIME subtype
*
* @return string
*/
public static function getMIMESubtype()
{
return "Plain";
}
}

View File

@ -0,0 +1,65 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Abstract class for the Bool2Text transformations plugins
*
* @package PhpMyAdmin-Transformations
* @subpackage Bool2Text
*/
namespace PMA\libraries\plugins\transformations\abs;
use PMA\libraries\plugins\TransformationsPlugin;
/**
* Provides common methods for all of the Bool2Text transformations plugins.
*
* @package PhpMyAdmin-Transformations
* @subpackage Bool2Text
*/
abstract class Bool2TextTransformationsPlugin extends TransformationsPlugin
{
/**
* Gets the transformation description of the specific plugin
*
* @return string
*/
public static function getInfo()
{
return __(
'Converts Boolean values to text (default \'T\' and \'F\').'
. ' First option is for TRUE, second for FALSE. Nonzero=true.'
);
}
/**
* Does the actual work of each specific transformations plugin.
*
* @param string $buffer text to be transformed
* @param array $options transformation options
* @param string $meta meta information
*
* @return string
*/
public function applyTransformation($buffer, $options = array(), $meta = '')
{
$options = $this->getOptions($options, array('T', 'F'));
if ($buffer == '0') {
return $options[1]; // return false label
}
return $options[0]; // or true one if nonzero
}
/* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */
/**
* Gets the transformation name of the specific plugin
*
* @return string
*/
public static function getName()
{
return "Bool2Text";
}
}

View File

@ -0,0 +1,72 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Abstract class for syntax highlighted editors using CodeMirror
*
* @package PhpMyAdmin-Transformations
*/
namespace PMA\libraries\plugins\transformations\abs;
use PMA\libraries\plugins\IOTransformationsPlugin;
/**
* Provides common methods for all the CodeMirror syntax highlighted editors
*
* @package PhpMyAdmin-Transformations
*/
abstract class CodeMirrorEditorTransformationPlugin extends IOTransformationsPlugin
{
/**
* Does the actual work of each specific transformations plugin.
*
* @param string $buffer text to be transformed
* @param array $options transformation options
* @param string $meta meta information
*
* @return string
*/
public function applyTransformation($buffer, $options = array(), $meta = '')
{
return $buffer;
}
/**
* Returns the html for input field to override default textarea.
* Note: Return empty string if default textarea is required.
*
* @param array $column column details
* @param int $row_id row number
* @param string $column_name_appendix the name attribute
* @param array $options transformation options
* @param string $value Current field value
* @param string $text_dir text direction
* @param int $tabindex tab index
* @param int $tabindex_for_value offset for the values tabindex
* @param int $idindex id index
*
* @return string the html for input field
*/
public function getInputHtml(
$column,
$row_id,
$column_name_appendix,
$options,
$value,
$text_dir,
$tabindex,
$tabindex_for_value,
$idindex
) {
$html = '';
if (!empty($value)) {
$html = '<input type="hidden" name="fields_prev' . $column_name_appendix
. '" value="' . htmlspecialchars($value) . '"/>';
}
$class = 'transform_' . strtolower(static::getName()) . '_editor';
$html .= '<textarea name="fields' . $column_name_appendix . '"'
. ' dir="' . $text_dir . '" class="' . $class . '">'
. htmlspecialchars($value) . '</textarea>';
return $html;
}
}

View File

@ -0,0 +1,168 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Abstract class for the date format transformations plugins
*
* @package PhpMyAdmin-Transformations
* @subpackage DateFormat
*/
namespace PMA\libraries\plugins\transformations\abs;
use PMA;
use PMA\libraries\plugins\TransformationsPlugin;
require_once 'libraries/js_escape.lib.php';
/**
* Provides common methods for all of the date format transformations plugins.
*
* @package PhpMyAdmin
*/
abstract class DateFormatTransformationsPlugin extends TransformationsPlugin
{
/**
* Gets the transformation description of the specific plugin
*
* @return string
*/
public static function getInfo()
{
return __(
'Displays a TIME, TIMESTAMP, DATETIME or numeric unix timestamp'
. ' column as formatted date. The first option is the offset (in'
. ' hours) which will be added to the timestamp (Default: 0). Use'
. ' second option to specify a different date/time format string.'
. ' Third option determines whether you want to see local date or'
. ' UTC one (use "local" or "utc" strings) for that. According to'
. ' that, date format has different value - for "local" see the'
. ' documentation for PHP\'s strftime() function and for "utc" it'
. ' is done using gmdate() function.'
);
}
/**
* Does the actual work of each specific transformations plugin.
*
* @param string $buffer text to be transformed
* @param array $options transformation options
* @param string $meta meta information
*
* @return string
*/
public function applyTransformation($buffer, $options = array(), $meta = '')
{
// possibly use a global transform and feed it with special options
// further operations on $buffer using the $options[] array.
if (empty($options[0])) {
$options[0] = 0;
}
if (empty($options[2])) {
$options[2] = 'local';
} else {
$options[2] = mb_strtolower($options[2]);
}
if (empty($options[1])) {
if ($options[2] == 'local') {
$options[1] = __('%B %d, %Y at %I:%M %p');
} else {
$options[1] = 'Y-m-d H:i:s';
}
}
$timestamp = -1;
// INT columns will be treated as UNIX timestamps
// and need to be detected before the verification for
// MySQL TIMESTAMP
if ($meta->type == 'int') {
$timestamp = $buffer;
// Detect TIMESTAMP(6 | 8 | 10 | 12 | 14)
// TIMESTAMP (2 | 4) not supported here.
// (Note: prior to MySQL 4.1, TIMESTAMP has a display size
// for example TIMESTAMP(8) means YYYYMMDD)
} else {
if (preg_match('/^(\d{2}){3,7}$/', $buffer)) {
if (mb_strlen($buffer) == 14 || mb_strlen($buffer) == 8) {
$offset = 4;
} else {
$offset = 2;
}
$aDate = array();
$aDate['year'] = (int)
mb_substr($buffer, 0, $offset);
$aDate['month'] = (int)
mb_substr($buffer, $offset, 2);
$aDate['day'] = (int)
mb_substr($buffer, $offset + 2, 2);
$aDate['hour'] = (int)
mb_substr($buffer, $offset + 4, 2);
$aDate['minute'] = (int)
mb_substr($buffer, $offset + 6, 2);
$aDate['second'] = (int)
mb_substr($buffer, $offset + 8, 2);
if (checkdate($aDate['month'], $aDate['day'], $aDate['year'])) {
$timestamp = mktime(
$aDate['hour'],
$aDate['minute'],
$aDate['second'],
$aDate['month'],
$aDate['day'],
$aDate['year']
);
}
// If all fails, assume one of the dozens of valid strtime() syntaxes
// (http://www.gnu.org/manual/tar-1.12/html_chapter/tar_7.html)
} else {
if (preg_match('/^[0-9]\d{1,9}$/', $buffer)) {
$timestamp = (int)$buffer;
} else {
$timestamp = strtotime($buffer);
}
}
}
// If all above failed, maybe it's a Unix timestamp already?
if ($timestamp < 0 && preg_match('/^[1-9]\d{1,9}$/', $buffer)) {
$timestamp = $buffer;
}
// Reformat a valid timestamp
if ($timestamp >= 0) {
$timestamp -= $options[0] * 60 * 60;
$source = $buffer;
if ($options[2] == 'local') {
$text = PMA\libraries\Util::localisedDate(
$timestamp,
$options[1]
);
} elseif ($options[2] == 'utc') {
$text = gmdate($options[1], $timestamp);
} else {
$text = 'INVALID DATE TYPE';
}
return '<dfn onclick="alert(\'' . PMA_jsFormat($source, false) . '\');" title="'
. htmlspecialchars($source) . '">' . htmlspecialchars($text) . '</dfn>';
} else {
return htmlspecialchars($buffer);
}
}
/* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */
/**
* Gets the transformation name of the specific plugin
*
* @return string
*/
public static function getName()
{
return "Date Format";
}
}

View File

@ -0,0 +1,90 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Abstract class for the download transformations plugins
*
* @package PhpMyAdmin-Transformations
* @subpackage Download
*/
namespace PMA\libraries\plugins\transformations\abs;
use PMA\libraries\plugins\TransformationsPlugin;
/**
* Provides common methods for all of the download transformations plugins.
*
* @package PhpMyAdmin
*/
abstract class DownloadTransformationsPlugin extends TransformationsPlugin
{
/**
* Gets the transformation description of the specific plugin
*
* @return string
*/
public static function getInfo()
{
return __(
'Displays a link to download the binary data of the column. You can'
. ' use the first option to specify the filename, or use the second'
. ' option as the name of a column which contains the filename. If'
. ' you use the second option, you need to set the first option to'
. ' the empty string.'
);
}
/**
* Does the actual work of each specific transformations plugin.
*
* @param string $buffer text to be transformed
* @param array $options transformation options
* @param string $meta meta information
*
* @return string
*/
public function applyTransformation($buffer, $options = array(), $meta = '')
{
global $row, $fields_meta;
if (isset($options[0]) && !empty($options[0])) {
$cn = $options[0]; // filename
} else {
if (isset($options[1]) && !empty($options[1])) {
foreach ($fields_meta as $key => $val) {
if ($val->name == $options[1]) {
$pos = $key;
break;
}
}
if (isset($pos)) {
$cn = $row[$pos];
}
}
if (empty($cn)) {
$cn = 'binary_file.dat';
}
}
return sprintf(
'<a href="transformation_wrapper.php%s&amp;ct=application'
. '/octet-stream&amp;cn=%s" title="%s" class="disableAjax">%s</a>',
$options['wrapper_link'],
htmlspecialchars(urlencode($cn)),
htmlspecialchars($cn),
htmlspecialchars($cn)
);
}
/* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */
/**
* Gets the transformation name of the specific plugin
*
* @return string
*/
public static function getName()
{
return "Download";
}
}

View File

@ -0,0 +1,150 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Abstract class for the external transformations plugins
*
* @package PhpMyAdmin-Transformations
* @subpackage External
*/
namespace PMA\libraries\plugins\transformations\abs;
use PMA\libraries\plugins\TransformationsPlugin;
/**
* Provides common methods for all of the external transformations plugins.
*
* @package PhpMyAdmin
*/
abstract class ExternalTransformationsPlugin extends TransformationsPlugin
{
/**
* Gets the transformation description of the specific plugin
*
* @return string
*/
public static function getInfo()
{
return __(
'LINUX ONLY: Launches an external application and feeds it the column'
. ' data via standard input. Returns the standard output of the'
. ' application. The default is Tidy, to pretty-print HTML code.'
. ' For security reasons, you have to manually edit the file'
. ' libraries/plugins/transformations/output/Text_Plain_External'
. '.php and list the tools you want to make available.'
. ' The first option is then the number of the program you want to'
. ' use and the second option is the parameters for the program.'
. ' The third option, if set to 1, will convert the output using'
. ' htmlspecialchars() (Default 1). The fourth option, if set to 1,'
. ' will prevent wrapping and ensure that the output appears all on'
. ' one line (Default 1).'
);
}
/**
* Enables no-wrapping
*
* @param array $options transformation options
*
* @return bool
*/
public function applyTransformationNoWrap($options = array())
{
if (!isset($options[3]) || $options[3] == '') {
$nowrap = true;
} elseif ($options[3] == '1' || $options[3] == 1) {
$nowrap = true;
} else {
$nowrap = false;
}
return $nowrap;
}
/**
* Does the actual work of each specific transformations plugin.
*
* @param string $buffer text to be transformed
* @param array $options transformation options
* @param string $meta meta information
*
* @return string
*/
public function applyTransformation($buffer, $options = array(), $meta = '')
{
// possibly use a global transform and feed it with special options
// further operations on $buffer using the $options[] array.
$allowed_programs = array();
//
// WARNING:
//
// It's up to administrator to allow anything here. Note that users may
// specify any parameters, so when programs allow output redirection or
// any other possibly dangerous operations, you should write wrapper
// script that will publish only functions you really want.
//
// Add here program definitions like (note that these are NOT safe
// programs):
//
//$allowed_programs[0] = '/usr/local/bin/tidy';
//$allowed_programs[1] = '/usr/local/bin/validate';
// no-op when no allowed programs
if (count($allowed_programs) == 0) {
return $buffer;
}
$options = $this->getOptions(
$options,
array(0, '-f /dev/null -i -wrap -q', 1, 1)
);
if (isset($allowed_programs[$options[0]])) {
$program = $allowed_programs[$options[0]];
} else {
$program = $allowed_programs[0];
}
// needs PHP >= 4.3.0
$newstring = '';
$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
);
$process = proc_open($program . ' ' . $options[1], $descriptorspec, $pipes);
if (is_resource($process)) {
fwrite($pipes[0], $buffer);
fclose($pipes[0]);
while (!feof($pipes[1])) {
$newstring .= fgets($pipes[1], 1024);
}
fclose($pipes[1]);
// we don't currently use the return value
proc_close($process);
}
if ($options[2] == 1 || $options[2] == '2') {
$retstring = htmlspecialchars($newstring);
} else {
$retstring = $newstring;
}
return $retstring;
}
/* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */
/**
* Gets the transformation name of the specific plugin
*
* @return string
*/
public static function getName()
{
return "External";
}
}

View File

@ -0,0 +1,62 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Abstract class for the formatted transformations plugins
*
* @package PhpMyAdmin-Transformations
* @subpackage Formatted
*/
namespace PMA\libraries\plugins\transformations\abs;
use PMA\libraries\plugins\TransformationsPlugin;
/**
* Provides common methods for all of the formatted transformations plugins.
*
* @package PhpMyAdmin
*/
abstract class FormattedTransformationsPlugin extends TransformationsPlugin
{
/**
* Gets the transformation description of the specific plugin
*
* @return string
*/
public static function getInfo()
{
return __(
'Displays the contents of the column as-is, without running it'
. ' through htmlspecialchars(). That is, the column is assumed'
. ' to contain valid HTML.'
);
}
/**
* Does the actual work of each specific transformations plugin.
*
* @param string $buffer text to be transformed
* @param array $options transformation options
* @param string $meta meta information
*
* @return string
*/
public function applyTransformation($buffer, $options = array(), $meta = '')
{
return '<iframe srcdoc="'
. strtr($buffer, '"', '\'')
. '" sandbox=""></iframe>';
}
/* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */
/**
* Gets the transformation name of the specific plugin
*
* @return string
*/
public static function getName()
{
return "Formatted";
}
}

View File

@ -0,0 +1,67 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Abstract class for the hex transformations plugins
*
* @package PhpMyAdmin-Transformations
* @subpackage Hex
*/
namespace PMA\libraries\plugins\transformations\abs;
use PMA\libraries\plugins\TransformationsPlugin;
/**
* Provides common methods for all of the hex transformations plugins.
*
* @package PhpMyAdmin
*/
abstract class HexTransformationsPlugin extends TransformationsPlugin
{
/**
* Gets the transformation description of the specific plugin
*
* @return string
*/
public static function getInfo()
{
return __(
'Displays hexadecimal representation of data. Optional first'
. ' parameter specifies how often space will be added (defaults'
. ' to 2 nibbles).'
);
}
/**
* Does the actual work of each specific transformations plugin.
*
* @param string $buffer text to be transformed
* @param array $options transformation options
* @param string $meta meta information
*
* @return string
*/
public function applyTransformation($buffer, $options = array(), $meta = '')
{
// possibly use a global transform and feed it with special options
$options = $this->getOptions($options, array('2'));
$options[0] = intval($options[0]);
if ($options[0] < 1) {
return bin2hex($buffer);
} else {
return chunk_split(bin2hex($buffer), $options[0], ' ');
}
}
/* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */
/**
* Gets the transformation name of the specific plugin
*
* @return string
*/
public static function getName()
{
return "Hex";
}
}

View File

@ -0,0 +1,67 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Abstract class for the link transformations plugins
*
* @package PhpMyAdmin-Transformations
* @subpackage Link
*/
namespace PMA\libraries\plugins\transformations\abs;
use PMA\libraries\plugins\TransformationsPlugin;
if (!defined('PHPMYADMIN')) {
exit;
}
/* For PMA_Transformation_globalHtmlReplace */
require_once 'libraries/transformations.lib.php';
/**
* Provides common methods for all of the link transformations plugins.
*
* @package PhpMyAdmin
*/
abstract class ImageLinkTransformationsPlugin extends TransformationsPlugin
{
/**
* Gets the transformation description of the specific plugin
*
* @return string
*/
public static function getInfo()
{
return __(
'Displays a link to download this image.'
);
}
/**
* Does the actual work of each specific transformations plugin.
*
* @param string $buffer text to be transformed
* @param array $options transformation options
* @param string $meta meta information
*
* @return string
*/
public function applyTransformation($buffer, $options = array(), $meta = '')
{
// must disable the page loader, see
// https://wiki.phpmyadmin.net/pma/Page_loader#Bypassing_the_page_loader
return '<a class="disableAjax" target="_blank" rel="noopener noreferrer" href="transformation_wrapper.php'
. $options['wrapper_link'] . '" alt="[' . htmlspecialchars($buffer) . ']">[BLOB]</a>';
}
/* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */
/**
* Gets the transformation name of the specific plugin
*
* @return string
*/
public static function getName()
{
return "ImageLink";
}
}

View File

@ -0,0 +1,118 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Abstract class for the image upload input transformations plugins
*
* @package PhpMyAdmin-Transformations
* @subpackage ImageUpload
*/
namespace PMA\libraries\plugins\transformations\abs;
use PMA\libraries\plugins\IOTransformationsPlugin;
/**
* Provides common methods for all of the image upload transformations plugins.
*
* @package PhpMyAdmin
*/
abstract class ImageUploadTransformationsPlugin extends IOTransformationsPlugin
{
/**
* Gets the transformation description of the specific plugin
*
* @return string
*/
public static function getInfo()
{
return __(
'Image upload functionality which also displays a thumbnail.'
. ' The options are the width and height of the thumbnail'
. ' in pixels. Defaults to 100 X 100.'
);
}
/**
* Does the actual work of each specific transformations plugin.
*
* @param string $buffer text to be transformed
* @param array $options transformation options
* @param string $meta meta information
*
* @return string
*/
public function applyTransformation($buffer, $options = array(), $meta = '')
{
return $buffer;
}
/**
* Returns the html for input field to override default textarea.
* Note: Return empty string if default textarea is required.
*
* @param array $column column details
* @param int $row_id row number
* @param string $column_name_appendix the name attribute
* @param array $options transformation options
* @param string $value Current field value
* @param string $text_dir text direction
* @param int $tabindex tab index
* @param int $tabindex_for_value offset for the values tabindex
* @param int $idindex id index
*
* @return string the html for input field
*/
public function getInputHtml(
$column,
$row_id,
$column_name_appendix,
$options,
$value,
$text_dir,
$tabindex,
$tabindex_for_value,
$idindex
) {
$html = '';
$src = '';
if (!empty($value)) {
$html = '<input type="hidden" name="fields_prev' . $column_name_appendix
. '" value="' . bin2hex($value) . '"/>';
$html .= '<input type="hidden" name="fields' . $column_name_appendix
. '" value="' . bin2hex($value) . '"/>';
$src = 'transformation_wrapper.php' . $options['wrapper_link'];
}
$html .= '<img src="' . $src . '" width="'
. (isset($options[0]) ? intval($options[0]) : '100') . '" height="'
. (isset($options[1]) ? intval($options[1]) : '100') . '" alt="'
. __('Image preview here') . '"/>';
$html .= '<br/><input type="file" name="fields_upload'
. $column_name_appendix . '" accept="image/*" class="image-upload"/>';
return $html;
}
/**
* Returns the array of scripts (filename) required for plugin
* initialization and handling
*
* @return array javascripts to be included
*/
public function getScripts()
{
return array(
'transformations/image_upload.js',
);
}
/* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */
/**
* Gets the transformation name of the specific plugin
*
* @return string
*/
public static function getName()
{
return "Image upload";
}
}

View File

@ -0,0 +1,79 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Abstract class for the inline transformations plugins
*
* @package PhpMyAdmin-Transformations
* @subpackage Inline
*/
namespace PMA\libraries\plugins\transformations\abs;
use PMA\libraries\plugins\TransformationsPlugin;
if (!defined('PHPMYADMIN')) {
exit;
}
/* For PMA_Transformation_globalHtmlReplace */
require_once 'libraries/transformations.lib.php';
/**
* Provides common methods for all of the inline transformations plugins.
*
* @package PhpMyAdmin
*/
abstract class InlineTransformationsPlugin extends TransformationsPlugin
{
/**
* Gets the transformation description of the specific plugin
*
* @return string
*/
public static function getInfo()
{
return __(
'Displays a clickable thumbnail. The options are the maximum width'
. ' and height in pixels. The original aspect ratio is preserved.'
);
}
/**
* Does the actual work of each specific transformations plugin.
*
* @param string $buffer text to be transformed
* @param array $options transformation options
* @param string $meta meta information
*
* @return string
*/
public function applyTransformation($buffer, $options = array(), $meta = '')
{
if (PMA_IS_GD2) {
return '<a href="transformation_wrapper.php'
. $options['wrapper_link']
. '" rel="noopener noreferrer" target="_blank"><img src="transformation_wrapper.php'
. $options['wrapper_link'] . '&amp;resize=jpeg&amp;newWidth='
. (isset($options[0]) ? intval($options[0]) : '100') . '&amp;newHeight='
. (isset($options[1]) ? intval($options[1]) : 100)
. '" alt="[' . htmlspecialchars($buffer) . ']" border="0" /></a>';
} else {
return '<img src="transformation_wrapper.php'
. $options['wrapper_link']
. '" alt="[' . htmlspecialchars($buffer) . ']" width="320" height="240" />';
}
}
/* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */
/**
* Gets the transformation name of the specific plugin
*
* @return string
*/
public static function getName()
{
return "Inline";
}
}

View File

@ -0,0 +1,63 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Abstract class for the long to IPv4 transformations plugins
*
* @package PhpMyAdmin-Transformations
* @subpackage LongToIPv4
*/
namespace PMA\libraries\plugins\transformations\abs;
use PMA\libraries\plugins\TransformationsPlugin;
/**
* Provides common methods for all of the long to IPv4 transformations plugins.
*
* @package PhpMyAdmin
*/
abstract class LongToIPv4TransformationsPlugin extends TransformationsPlugin
{
/**
* Gets the transformation description of the specific plugin
*
* @return string
*/
public static function getInfo()
{
return __(
'Converts an (IPv4) Internet network address stored as a BIGINT'
. ' into a string in Internet standard dotted format.'
);
}
/**
* Does the actual work of each specific transformations plugin.
*
* @param string $buffer text to be transformed
* @param array $options transformation options
* @param string $meta meta information
*
* @return string
*/
public function applyTransformation($buffer, $options = array(), $meta = '')
{
if ($buffer < 0 || $buffer > 4294967295) {
return htmlspecialchars($buffer);
}
return long2ip($buffer);
}
/* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */
/**
* Gets the transformation name of the specific plugin
*
* @return string
*/
public static function getName()
{
return "Long To IPv4";
}
}

View File

@ -0,0 +1,64 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Abstract class for the prepend/append transformations plugins
*
* @package PhpMyAdmin-Transformations
* @subpackage PreApPend
*/
namespace PMA\libraries\plugins\transformations\abs;
use PMA\libraries\plugins\TransformationsPlugin;
/**
* Provides common methods for all of the prepend/append transformations plugins.
*
* @package PhpMyAdmin-Transformations
* @subpackage PreApPend
*/
abstract class PreApPendTransformationsPlugin extends TransformationsPlugin
{
/**
* Gets the transformation description of the specific plugin
*
* @return string
*/
public static function getInfo()
{
return __(
'Prepends and/or Appends text to a string. First option is text'
. ' to be prepended, second is appended (enclosed in single'
. ' quotes, default empty string).'
);
}
/**
* Does the actual work of each specific transformations plugin.
*
* @param string $buffer text to be transformed
* @param array $options transformation options
* @param string $meta meta information
*
* @return string
*/
public function applyTransformation($buffer, $options = array(), $meta = '')
{
$options = $this->getOptions($options, array('', ''));
//just prepend and/or append the options to the original text
return htmlspecialchars($options[0]) . htmlspecialchars($buffer)
. htmlspecialchars($options[1]);
}
/* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */
/**
* Gets the transformation name of the specific plugin
*
* @return string
*/
public static function getName()
{
return "PreApPend";
}
}

View File

@ -0,0 +1,71 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Abstract class for the regex validation input transformations plugins
*
* @package PhpMyAdmin-Transformations
* @subpackage RegexValidation
*/
namespace PMA\libraries\plugins\transformations\abs;
use PMA\libraries\plugins\IOTransformationsPlugin;
/**
* Provides common methods for all of the regex validation
* input transformations plugins.
*
* @package PhpMyAdmin-Transformations
* @subpackage RegexValidation
*/
abstract class RegexValidationTransformationsPlugin extends IOTransformationsPlugin
{
/**
* Gets the transformation description of the specific plugin
*
* @return string
*/
public static function getInfo()
{
return __(
'Validates the string using regular expression '
. 'and performs insert only if string matches it. '
. 'The first option is the Regular Expression.'
);
}
/**
* Does the actual work of each specific transformations plugin.
*
* @param string $buffer text to be transformed
* @param array $options transformation options
* @param string $meta meta information
*
* @return string
*/
public function applyTransformation($buffer, $options = array(), $meta = '')
{
// reset properties of object
$this->reset();
if (!empty($options[0]) && !preg_match($options[0], $buffer)) {
$this->success = false;
$this->error = sprintf(
__('Validation failed for the input string %s.'),
htmlspecialchars($buffer)
);
}
return $buffer;
}
/* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */
/**
* Gets the transformation name of the specific plugin
*
* @return string
*/
public static function getName()
{
return "Regex Validation";
}
}

View File

@ -0,0 +1,62 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Abstract class for the SQL transformations plugins
*
* @package PhpMyAdmin-Transformations
* @subpackage SQL
*/
namespace PMA\libraries\plugins\transformations\abs;
use PMA;
use PMA\libraries\plugins\TransformationsPlugin;
/**
* Provides common methods for all of the SQL transformations plugins.
*
* @package PhpMyAdmin
*/
abstract class SQLTransformationsPlugin extends TransformationsPlugin
{
/**
* Gets the transformation description of the specific plugin
*
* @return string
*/
public static function getInfo()
{
return __(
'Formats text as SQL query with syntax highlighting.'
);
}
/**
* Does the actual work of each specific transformations plugin.
*
* @param string $buffer text to be transformed
* @param array $options transformation options
* @param string $meta meta information
*
* @return string
*/
public function applyTransformation($buffer, $options = array(), $meta = '')
{
// see PMA_highlightSQL()
$result = PMA\libraries\Util::formatSql($buffer);
return $result;
}
/* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */
/**
* Gets the transformation name of the specific plugin
*
* @return string
*/
public static function getName()
{
return "SQL";
}
}

Some files were not shown because too many files have changed in this diff Show More