diff options
Diffstat (limited to 'hugo/libraries/plugins')
81 files changed, 17916 insertions, 0 deletions
diff --git a/hugo/libraries/plugins/AuthenticationPlugin.class.php b/hugo/libraries/plugins/AuthenticationPlugin.class.php new file mode 100644 index 0000000..3ddf55e --- /dev/null +++ b/hugo/libraries/plugins/AuthenticationPlugin.class.php @@ -0,0 +1,51 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Abstract class for the authentication plugins + * + * @package PhpMyAdmin + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* This class extends the PluginObserver class */ +require_once 'PluginObserver.class.php'; + +/** + * Provides a common interface that will have to be implemented by all of the + * authentication plugins. + * + * @package PhpMyAdmin + */ +abstract class AuthenticationPlugin extends PluginObserver +{ + /** + * 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(); + + /** + * User is not allowed to login to MySQL -> authentication failed + * + * @return boolean + */ + abstract public function authFails(); +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/ExportPlugin.class.php b/hugo/libraries/plugins/ExportPlugin.class.php new file mode 100644 index 0000000..0af20d3 --- /dev/null +++ b/hugo/libraries/plugins/ExportPlugin.class.php @@ -0,0 +1,205 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Abstract class for the export plugins + * + * @package PhpMyAdmin + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* This class extends the PluginObserver class */ +require_once 'PluginObserver.class.php'; + +/** + * 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 extends PluginObserver +{ + /** + * Array containing the specific export plugin type properties + * + * @var array + */ + 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 + * + * @return bool Whether it succeeded + */ + abstract public function exportDBHeader ($db); + + /** + * 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 + * + * @return bool Whether it succeeded + */ + abstract public function exportDBCreate($db); + + /** + * 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 + * + * @return bool Whether it succeeded + */ + abstract public function exportData ($db, $table, $crlf, $error_url, $sql_query); + + + /** + * 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 + * + * @return bool Whether it succeeded + */ + public function exportRoutines($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 + * + * @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 + ) { + ; + } + + /** + * 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 + * + * @return string resulting definition + */ + public function getTableDefStandIn($db, $view, $crlf) + { + ; + } + + /** + * 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 array + */ + public function getProperties() + { + return $this->properties; + } + + /** + * Sets the export plugins properties and is implemented by each export + * plugin + * + * @return void + */ + abstract protected function setProperties(); +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/ImportPlugin.class.php b/hugo/libraries/plugins/ImportPlugin.class.php new file mode 100644 index 0000000..0890dcf --- /dev/null +++ b/hugo/libraries/plugins/ImportPlugin.class.php @@ -0,0 +1,59 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Abstract class for the import plugins + * + * @package PhpMyAdmin + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* This class extends the PluginObserver class */ +require_once 'PluginObserver.class.php'; + +/** + * Provides a common interface that will have to be implemented by all of the + * import plugins. + * + * @package PhpMyAdmin + */ +abstract class ImportPlugin extends PluginObserver +{ + /** + * Array containing the import plugin properties + * + * @var type array + */ + protected $properties; + + /** + * Handles the whole import logic + * + * @return void + */ + abstract public function doImport(); + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the import specific format plugin properties + * + * @return array + */ + public function getProperties() + { + return $this->properties; + } + + /** + * Sets the export plugins properties and is implemented by each import + * plugin + * + * @return void + */ + abstract protected function setProperties(); +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/PluginManager.class.php b/hugo/libraries/plugins/PluginManager.class.php new file mode 100644 index 0000000..28400b7 --- /dev/null +++ b/hugo/libraries/plugins/PluginManager.class.php @@ -0,0 +1,132 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * The PluginManager class is used alongside PluginObserver to implement + * the Observer Design Pattern. + * + * @package PhpMyAdmin + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/** + * This class implements the SplSubject interface + * + * @todo implement all methods + * @package PhpMyAdmin + * @link http://php.net/manual/en/class.splsubject.php + * + */ +class PluginManager implements SplSubject +{ + /** + * Contains a list with all the plugins that attach to it + * + * @var type SplObjectStorage + */ + private $_storage; + + /** + * Contains information about the current plugin state + * + * @var type string + */ + private $_status; + + /** + * Constructor + * Initializes $_storage with an empty SplObjectStorage + */ + public function __construct() + { + $this->_storage = new SplObjectStorage(); + } + + /** + * Attaches an SplObserver so that it can be notified of updates + * + * @param SplObserver $observer The SplObserver to attach + * + * @return void + */ + function attach (SplObserver $observer ) + { + $this->_storage->attach($observer); + } + + /** + * Detaches an observer from the subject to no longer notify it of updates + * + * @param SplObserver $observer The SplObserver to detach + * + * @return void + */ + function detach (SplObserver $observer) + { + $this->_storage->detach($observer); + } + + /** + * It is called after setStatus() was run by a certain plugin, and has + * the role of sending a notification to all of the plugins in $_storage, + * by calling the update() method for each of them. + * + * @todo implement + * @return void + */ + function notify () + { + } + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + /** + * Gets the list with all the plugins that attach to it + * + * @return type SplObjectStorage + */ + public function getStorage() + { + return $this->_storage; + } + + /** + * Setter for $_storage + * + * @param SplObjectStorage $_storage the list with all the plugins that + * attach to it + * + * @return void + */ + public function setStorage($_storage) + { + $this->_storage = $_storage; + } + + /** + * Gets the information about the current plugin state + * It is called by all the plugins in $_storage in their update() method + * + * @return type mixed + */ + public function getStatus() + { + return $this->_status; + } + + /** + * Setter for $_status + * If a plugin changes its status, this has to be remembered in order to + * notify the rest of the plugins that they should update + * + * @param mixed $_status contains information about the current plugin state + * + * @return void + */ + public function setStatus($_status) + { + $this->_status = $_status; + } +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/PluginObserver.class.php b/hugo/libraries/plugins/PluginObserver.class.php new file mode 100644 index 0000000..520d62a --- /dev/null +++ b/hugo/libraries/plugins/PluginObserver.class.php @@ -0,0 +1,90 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * The PluginObserver class is used alongside PluginManager to implement + * the Observer Design Pattern. + * + * @package PhpMyAdmin + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Each PluginObserver instance contains a PluginManager instance */ +require_once 'PluginManager.class.php'; + +/** + * This class implements the SplObserver interface + * + * @package PhpMyAdmin + * @link http://php.net/manual/en/class.splobserver.php + */ +abstract class PluginObserver implements SplObserver +{ + /** + * PluginManager instance that contains a list with all the observer + * plugins that attach to it + * + * @var type PluginManager + */ + private $_pluginManager; + + /** + * Constructor + * + * @param PluginManager $pluginManager The Plugin Manager instance + */ + public function __construct($pluginManager) + { + $this->_pluginManager = $pluginManager; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * TODO Declare this function abstract, removing its body, + * as soon as we drop support for PHP 5.2.x. + * See bug #3538655. + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + throw new Exception( + 'PluginObserver::update must be overridden in child classes.' + ); + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the PluginManager instance that contains the list with all the + * plugins that attached to it + * + * @return type PluginManager + */ + public function getPluginManager() + { + return $this->_pluginManager; + } + + /** + * Setter for $_pluginManager + * + * @param PluginManager $_pluginManager the private instance that it will + * attach to + * + * @return void + */ + public function setPluginManager($_pluginManager) + { + $this->_pluginManager = $_pluginManager; + } +} +?> diff --git a/hugo/libraries/plugins/TransformationsInterface.int.php b/hugo/libraries/plugins/TransformationsInterface.int.php new file mode 100644 index 0000000..1bcb8af --- /dev/null +++ b/hugo/libraries/plugins/TransformationsInterface.int.php @@ -0,0 +1,49 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Interface for the transformations plugins + * + * @package PhpMyAdmin + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/** + * 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(); +} + +?> diff --git a/hugo/libraries/plugins/TransformationsPlugin.class.php b/hugo/libraries/plugins/TransformationsPlugin.class.php new file mode 100644 index 0000000..959a8e1 --- /dev/null +++ b/hugo/libraries/plugins/TransformationsPlugin.class.php @@ -0,0 +1,49 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Abstract class for the transformations plugins + * + * @package PhpMyAdmin + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* It extends the PluginObserver abstract class */ +require_once 'PluginObserver.class.php'; +/* It also implements the transformations interface */ +require_once 'TransformationsInterface.int.php'; + +/** + * Extends PluginObserver and provides a common interface that will have to + * be implemented by all of the transformations plugins. + * + * @package PhpMyAdmin + */ +abstract class TransformationsPlugin extends PluginObserver + 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 void + */ + abstract public function applyTransformation($buffer, $options = array(), $meta = ''); +} +?> diff --git a/hugo/libraries/plugins/UploadInterface.int.php b/hugo/libraries/plugins/UploadInterface.int.php new file mode 100644 index 0000000..ab660d6 --- /dev/null +++ b/hugo/libraries/plugins/UploadInterface.int.php @@ -0,0 +1,36 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Interface for the import->upload plugins + * + * @package PhpMyAdmin + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/** + * 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); +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/auth/AuthenticationConfig.class.php b/hugo/libraries/plugins/auth/AuthenticationConfig.class.php new file mode 100644 index 0000000..07ad7cb --- /dev/null +++ b/hugo/libraries/plugins/auth/AuthenticationConfig.class.php @@ -0,0 +1,172 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Config Authentication plugin for phpMyAdmin + * + * @package PhpMyAdmin-Authentication + * @subpackage Config + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the authentication interface */ +require_once 'libraries/plugins/AuthenticationPlugin.class.php'; + +/** + * Handles the config authentication method + * + * @package PhpMyAdmin-Authentication + */ +class AuthenticationConfig extends AuthenticationPlugin +{ + /** + * Displays authentication form + * + * @return boolean always true + */ + public function auth() + { + return true; + } + + /** + * Gets advanced authentication settings + * + * @return boolean always true + */ + public function authCheck() + { + return true; + } + + /** + * Set the user and password after last checkings if required + * + * @return boolean always true + */ + public function authSetUser() + { + return true; + } + + /** + * User is not allowed to login to MySQL -> authentication failed + * + * @global string the MySQL error message PHP returns + * @global string the connection type (persistent or not) + * @global string the MySQL server port to use + * @global string the MySQL socket port to use + * @global array the current server settings + * @global string the font face to use in case of failure + * @global string the default font size to use in case of failure + * @global string the big font size to use in case of failure + * @global boolean tell the "PMA_mysqlDie()" function headers have been + * sent + * + * @return boolean always true (no return indeed) + */ + public function authFails() + { + $conn_error = PMA_DBI_getError(); + if (! $conn_error) { + $conn_error = __('Cannot connect: invalid settings.'); + } + + /* HTML header */ + $response = PMA_Response::getInstance(); + $response->getFooter()->setMinimal(); + $header = $response->getHeader(); + $header->setBodyId('loginform'); + $header->setTitle(__('Access denied')); + $header->disableMenu(); + 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_Util::mysqlDie( + $conn_error, '', true, '', false + ); + } + $GLOBALS['error_handler']->dispUserErrors(); + echo '</td> + </tr> + <tr> + <td>' . "\n"; + echo '<a href="' + . $GLOBALS['cfg']['DefaultTabServer'] + . PMA_generate_common_url(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"; + exit; + return true; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } +} diff --git a/hugo/libraries/plugins/auth/AuthenticationCookie.class.php b/hugo/libraries/plugins/auth/AuthenticationCookie.class.php new file mode 100644 index 0000000..72274d9 --- /dev/null +++ b/hugo/libraries/plugins/auth/AuthenticationCookie.class.php @@ -0,0 +1,696 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Cookie Authentication plugin for phpMyAdmin + * + * @package PhpMyAdmin-Authentication + * @subpackage Cookie + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the authentication interface */ +require_once 'libraries/plugins/AuthenticationPlugin.class.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')); +} + +/** + * Swekey authentication functions. + */ +require './libraries/plugins/auth/swekey/swekey.auth.lib.php'; + +/** + * 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. + */ +if (function_exists('mcrypt_encrypt')) { + if (empty($_COOKIE['pma_mcrypt_iv']) + || ! ($iv = base64_decode($_COOKIE['pma_mcrypt_iv'], true)) + ) { + srand((double) microtime() * 1000000); + $td = mcrypt_module_open(MCRYPT_BLOWFISH, '', MCRYPT_MODE_CBC, ''); + if ($td === false) { + PMA_fatalError(__('Failed to use Blowfish from mcrypt!')); + } + $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND); + $GLOBALS['PMA_Config']->setCookie( + 'pma_mcrypt_iv', + base64_encode($iv) + ); + } +} + +/** + * Handles the cookie authentication method + * + * @package PhpMyAdmin-Authentication + */ +class AuthenticationCookie extends AuthenticationPlugin +{ + /** + * Displays authentication form + * + * this function MUST exit/quit the application + * + * @global string the last connection error + * + * @return void + */ + public function auth() + { + global $conn_error; + + $response = PMA_Response::getInstance(); + if ($response->isAjax()) { + $response->isSuccess(false); + + $login_link = '<br /><br />[ ' . + sprintf( + '<a href="%s" class="ajax login-link">%s</a>', + $GLOBALS['cfg']['PmaAbsoluteUri'], + __('Log in') + ) + . ' ]'; + + if (! empty($conn_error)) { + + $conn_error .= $login_link; + + $response->addJSON( + 'message', + PMA_Message::error( + $conn_error + ) + ); + } else { + $response->addJSON( + 'message', + PMA_Message::error( + __('Your session has expired. Please log in again.') . + $login_link + ) + ); + } + exit; + } + + /* Perform logout to custom URL */ + if (! empty($_REQUEST['old_usr']) + && ! empty($GLOBALS['cfg']['Server']['LogoutURL']) + ) { + PMA_sendHeaderLocation($GLOBALS['cfg']['Server']['LogoutURL']); + 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"'; + } + + $cell_align = ($GLOBALS['text_dir'] == 'ltr') ? 'left' : 'right'; + + $response->getFooter()->setMinimal(); + $header = $response->getHeader(); + $header->setBodyId('loginform'); + $header->setTitle('phpMyAdmin'); + $header->disableMenu(); + $header->disableWarnings(); + + if (file_exists(CUSTOM_HEADER_FILE)) { + include CUSTOM_HEADER_FILE; + } + echo ' + <div class="container"> + <a href="'; + echo PMA_linkURL('http://www.phpmyadmin.net/'); + echo '" target="_blank" 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)) { + PMA_Message::rawError($conn_error)->display(); + } + + echo "<noscript>\n"; + PMA_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 PMA_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) + + 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_generate_common_hidden_inputs($_form_params, '', 0, 'server'); + echo '</fieldset> + </form>'; + + // BEGIN Swekey Integration + Swekey_login('input_username', 'input_go'); + // END Swekey Integration + + if ($GLOBALS['error_handler']->hasDisplayErrors()) { + echo '<div>'; + $GLOBALS['error_handler']->dispErrors(); + echo '</div>'; + } + echo '</div>'; + if (file_exists(CUSTOM_FOOTER_FILE)) { + include CUSTOM_FOOTER_FILE; + } + exit; + } + + /** + * 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 PMA_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 timout is reached + * + * @todo AllowArbitraryServer on does not imply that the user wants an + * arbitrary server, or? so we should also check if this is filled + * and not only if allowed + * + * @return boolean whether we get authentication settings or not + */ + public function authCheck() + { + // 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; + + // BEGIN Swekey Integration + if (! Swekey_auth_check()) { + return false; + } + // END Swekey Integration + + if (defined('PMA_CLEAR_COOKIES')) { + foreach ($GLOBALS['cfg']['Servers'] as $key => $val) { + $GLOBALS['PMA_Config']->removeCookie('pmaPass-' . $key); + $GLOBALS['PMA_Config']->removeCookie('pmaServer-' . $key); + $GLOBALS['PMA_Config']->removeCookie('pmaUser-' . $key); + } + return false; + } + + if (! empty($_REQUEST['old_usr'])) { + // The user wants to be logged out + // -> delete his choices that were stored in session + + // according to the PHP manual we should do this before the destroy: + //$_SESSION = array(); + + session_destroy(); + // -> delete password cookie(s) + if ($GLOBALS['cfg']['LoginCookieDeleteAll']) { + foreach ($GLOBALS['cfg']['Servers'] as $key => $val) { + $GLOBALS['PMA_Config']->removeCookie('pmaPass-' . $key); + if (isset($_COOKIE['pmaPass-' . $key])) { + unset($_COOKIE['pmaPass-' . $key]); + } + } + } else { + $GLOBALS['PMA_Config']->removeCookie( + 'pmaPass-' . $GLOBALS['server'] + ); + if (isset($_COOKIE['pmaPass-' . $GLOBALS['server']])) { + unset($_COOKIE['pmaPass-' . $GLOBALS['server']]); + } + } + } + + if (! empty($_REQUEST['pma_username'])) { + // The user just logged in + $GLOBALS['PHP_AUTH_USER'] = $_REQUEST['pma_username']; + $GLOBALS['PHP_AUTH_PW'] = empty($_REQUEST['pma_password']) + ? '' + : $_REQUEST['pma_password']; + if ($GLOBALS['cfg']['AllowArbitraryServer'] + && isset($_REQUEST['pma_servername']) + ) { + $GLOBALS['pma_auth_server'] = $_REQUEST['pma_servername']; + } + return true; + } + + // At the end, try to set the $GLOBALS['PHP_AUTH_USER'] + // and $GLOBALS['PHP_AUTH_PW'] variables from cookies + + // servername + if ($GLOBALS['cfg']['AllowArbitraryServer'] + && ! empty($_COOKIE['pmaServer-' . $GLOBALS['server']]) + ) { + $GLOBALS['pma_auth_server'] + = $_COOKIE['pmaServer-' . $GLOBALS['server']]; + } + + // username + if (empty($_COOKIE['pmaUser-' . $GLOBALS['server']])) { + return false; + } + + $GLOBALS['PHP_AUTH_USER'] = $this->blowfishDecrypt( + $_COOKIE['pmaUser-' . $GLOBALS['server']], + $this->_getBlowfishSecret() + ); + + // 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 + ) { + PMA_Util::cacheUnset('is_create_db_priv', true); + PMA_Util::cacheUnset('is_process_priv', true); + PMA_Util::cacheUnset('is_reload_priv', true); + PMA_Util::cacheUnset('db_to_create', true); + PMA_Util::cacheUnset('dbs_where_create_table_allowed', true); + $GLOBALS['no_activity'] = true; + $this->authFails(); + exit; + } + + // password + if (empty($_COOKIE['pmaPass-' . $GLOBALS['server']])) { + return false; + } + + $GLOBALS['PHP_AUTH_PW'] = $this->blowfishDecrypt( + $_COOKIE['pmaPass-' . $GLOBALS['server']], + $this->_getBlowfishSecret() + ); + + if ($GLOBALS['PHP_AUTH_PW'] == "\xff(blank)") { + $GLOBALS['PHP_AUTH_PW'] = ''; + } + + $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 ($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'] + && $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']); + + $_SESSION['last_access_time'] = time(); + + // Name and password cookies need to be refreshed each time + // Duration = one month for username + $GLOBALS['PMA_Config']->setCookie( + 'pmaUser-' . $GLOBALS['server'], + $this->blowfishEncrypt( + $cfg['Server']['user'], + $this->_getBlowfishSecret() + ) + ); + + // Duration = as configured + $GLOBALS['PMA_Config']->setCookie( + 'pmaPass-' . $GLOBALS['server'], + $this->blowfishEncrypt( + ! empty($cfg['Server']['password']) + ? $cfg['Server']['password'] : "\xff(blank)", + $this->_getBlowfishSecret() + ), + null, + $GLOBALS['cfg']['LoginCookieStore'] + ); + + // Set server cookies if required (once per session) and, in this case, + // force reload to ensure the client accepts cookies + if (! $GLOBALS['from_cookie']) { + if ($GLOBALS['cfg']['AllowArbitraryServer']) { + if (! empty($GLOBALS['pma_auth_server'])) { + // Duration = one month for servername + $GLOBALS['PMA_Config']->setCookie( + 'pmaServer-' . $GLOBALS['server'], + $cfg['Server']['host'] + ); + } else { + // Delete servername cookie + $GLOBALS['PMA_Config']->removeCookie( + 'pmaServer-' . $GLOBALS['server'] + ); + } + } + + // URL where to go: + $redirect_url = $cfg['PmaAbsoluteUri'] . 'index.php'; + + // any parameters to pass? + $url_params = array(); + if (strlen($GLOBALS['db'])) { + $url_params['db'] = $GLOBALS['db']; + } + if (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. + */ + PMA_Util::clearUserCache(); + + PMA_Response::getInstance()->disable(); + + PMA_sendHeaderLocation( + $redirect_url . PMA_generate_common_url($url_params, '&'), + true + ); + exit; + } // end if + + return true; + + } + + /** + * 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 doen by call to auth() + * + * @return void + */ + public function authFails() + { + global $conn_error; + + // Deletes password cookie and displays the login form + $GLOBALS['PMA_Config']->removeCookie('pmaPass-' . $GLOBALS['server']); + + if (! empty($GLOBALS['login_without_password_is_forbidden'])) { + $conn_error = __( + 'Login without a password is forbidden by configuration' + . ' (see AllowNoPassword)' + ); + } elseif (! empty($GLOBALS['allowDeny_forbidden'])) { + $conn_error = __('Access denied'); + } elseif (! empty($GLOBALS['no_activity'])) { + $conn_error = sprintf( + __('No activity within %s seconds; please log in again'), + $GLOBALS['cfg']['LoginCookieValidity'] + ); + } elseif (PMA_DBI_getError()) { + $conn_error = '#' . $GLOBALS['errno'] . ' ' + . __('Cannot log in to the MySQL server'); + } else { + $conn_error = __('Cannot log in to the MySQL server'); + } + + // needed for PHP-CGI (not need for FastCGI or mod-php) + header('Cache-Control: no-store, no-cache, must-revalidate'); + header('Pragma: no-cache'); + + $this->auth(); + } + + /** + * Returns blowfish secret or generates one if needed. + * + * @return string + */ + private function _getBlowfishSecret() + { + if (empty($GLOBALS['cfg']['blowfish_secret'])) { + if (empty($_SESSION['auto_blowfish_secret'])) { + // this returns 23 characters + $_SESSION['auto_blowfish_secret'] = uniqid('', true); + } + return $_SESSION['auto_blowfish_secret']; + } else { + // apply md5() to work around too long secrets (returns 32 characters) + return md5($GLOBALS['cfg']['blowfish_secret']); + } + } + + /** + * Encryption using blowfish algorithm (mcrypt) + * or phpseclib's AES if mcrypt not available + * + * @param string $data original data + * @param string $secret the secret + * + * @return string the encrypted result + */ + public function blowfishEncrypt($data, $secret) + { + global $iv; + if (! function_exists('mcrypt_encrypt')) { + /** + * This library uses mcrypt when available, so + * we could always call it instead of having an + * if/then/else logic, however the include_once + * call is costly + */ + include_once "./libraries/phpseclib/Crypt/AES.php"; + $cipher = new Crypt_AES(CRYPT_AES_MODE_ECB); + $cipher->setKey($secret); + return base64_encode($cipher->encrypt($data)); + } else { + return base64_encode( + mcrypt_encrypt( + MCRYPT_BLOWFISH, + $secret, + $data, + MCRYPT_MODE_CBC, + $iv + ) + ); + } + } + + /** + * Decryption using blowfish algorithm (mcrypt) + * or phpseclib's AES if mcrypt not available + * + * @param string $encdata encrypted data + * @param string $secret the secret + * + * @return string original data + */ + public function blowfishDecrypt($encdata, $secret) + { + global $iv; + if (! function_exists('mcrypt_encrypt')) { + include_once "./libraries/phpseclib/Crypt/AES.php"; + $cipher = new Crypt_AES(CRYPT_AES_MODE_ECB); + $cipher->setKey($secret); + return $cipher->decrypt(base64_decode($encdata)); + } else { + $data = base64_decode($encdata); + $decrypted = mcrypt_decrypt( + MCRYPT_BLOWFISH, + $secret, + $data, + MCRYPT_MODE_CBC, + $iv + ); + return trim($decrypted); + } + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } +} diff --git a/hugo/libraries/plugins/auth/AuthenticationHttp.class.php b/hugo/libraries/plugins/auth/AuthenticationHttp.class.php new file mode 100644 index 0000000..f81ab92 --- /dev/null +++ b/hugo/libraries/plugins/auth/AuthenticationHttp.class.php @@ -0,0 +1,249 @@ +<?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 + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the authentication interface */ +require_once 'libraries/plugins/AuthenticationPlugin.class.php'; + +/** + * Handles the HTTP authentication methods + * + * @package PhpMyAdmin-Authentication + */ +class AuthenticationHttp extends AuthenticationPlugin +{ + /** + * Displays authentication form + * + * @global string the font face to use in case of failure + * @global string the default font size to use in case of failure + * @global string the big font size to use in case of failure + * + * @return boolean always true (no return indeed) + */ + public function auth() + { + /* Perform logout to custom URL */ + if (! empty($_REQUEST['old_usr']) + && ! empty($GLOBALS['cfg']['Server']['LogoutURL']) + ) { + PMA_sendHeaderLocation($GLOBALS['cfg']['Server']['LogoutURL']); + exit; + } + + 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']; + } + // remove non US-ASCII to respect RFC2616 + $realm_message = preg_replace('/[^\x20-\x7e]/i', '', $realm_message); + header('WWW-Authenticate: Basic realm="' . $realm_message . '"'); + header('HTTP/1.0 401 Unauthorized'); + if (php_sapi_name() !== 'cgi-fcgi') { + header('status: 401 Unauthorized'); + } + + /* HTML header */ + $response = PMA_Response::getInstance(); + $response->getFooter()->setMinimal(); + $header = $response->getHeader(); + $header->setTitle(__('Access denied')); + $header->disableMenu(); + $header->setBodyId('loginform'); + + $response->addHTML('<h1>'); + $response->addHTML(sprintf(__('Welcome to %s'), ' phpMyAdmin')); + $response->addHTML('</h1>'); + $response->addHTML('<h3>'); + $response->addHTML( + PMA_Message::error( + __('Wrong username/password. Access denied.') + ) + ); + $response->addHTML('</h3>'); + + if (file_exists(CUSTOM_FOOTER_FILE)) { + include CUSTOM_FOOTER_FILE; + } + + exit; + } + + /** + * Gets advanced authentication settings + * + * @global string the username if register_globals is on + * @global string the password if register_globals is on + * @global array the array of server variables if register_globals is + * off + * @global array the array of environment variables if register_globals + * is off + * @global string the username for the ? server + * @global string the password for the ? server + * @global string the username for the WebSite Professional server + * @global string the password for the WebSite Professional server + * @global string the username of the user who logs out + * + * @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') + && false === strpos(PMA_getenv('HTTP_AUTHORIZATION'), '<') + ) { + // IIS, might be encoded, see below; also prevent XSS + $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); + } + + // 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) && $old_usr == $PHP_AUTH_USER) + ) { + $PHP_AUTH_USER = ''; + // -> delete user's choices that were stored in session + 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 the valid servers settings + * @global integer the id of the current server + * @global array the current server settings + * @global string the current username + * @global string 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 ($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'] + && $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']); + + return true; + } + + /** + * User is not allowed to login to MySQL -> authentication failed + * + * @return boolean always true (no return indeed) + */ + public function authFails() + { + $error = PMA_DBI_getError(); + if ($error && $GLOBALS['errno'] != 1045) { + PMA_fatalError($error); + } else { + $this->auth(); + return true; + } + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } +} diff --git a/hugo/libraries/plugins/auth/AuthenticationSignon.class.php b/hugo/libraries/plugins/auth/AuthenticationSignon.class.php new file mode 100644 index 0000000..ee1cf36 --- /dev/null +++ b/hugo/libraries/plugins/auth/AuthenticationSignon.class.php @@ -0,0 +1,284 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * SignOn Authentication plugin for phpMyAdmin + * + * @package PhpMyAdmin-Authentication + * @subpackage SignOn + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the authentication interface */ +require_once 'libraries/plugins/AuthenticationPlugin.class.php'; + +/** + * Handles the SignOn authentication method + * + * @package PhpMyAdmin-Authentication + */ +class AuthenticationSignon extends AuthenticationPlugin +{ + /** + * Displays authentication form + * + * @global string the font face to use in case of failure + * @global string the default font size to use in case of failure + * @global string the big font size to use in case of failure + * + * @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!'); + } elseif (! empty($_REQUEST['old_usr']) + && ! empty($GLOBALS['cfg']['Server']['LogoutURL']) + ) { + /* Perform logout to custom URL */ + PMA_sendHeaderLocation($GLOBALS['cfg']['Server']['LogoutURL']); + } else { + PMA_sendHeaderLocation($GLOBALS['cfg']['Server']['SignonURL']); + } + exit(); + } + + /** + * Gets advanced authentication settings + * + * @global string the username if register_globals is on + * @global string the password if register_globals is on + * @global array the array of server variables if register_globals is + * off + * @global array the array of environment variables if register_globals + * is off + * @global string the username for the ? server + * @global string the password for the ? server + * @global string the username for the WebSite Professional server + * @global string the password for the WebSite Professional server + * @global string the username of the user who logs out + * + * @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 sigon 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(); + + /* Are we requested to do logout? */ + $do_logout = !empty($_REQUEST['old_usr']); + + /* 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($cfg['Server']['user']); + + } elseif (isset($_COOKIE[$session_name])) { /* Does session exist? */ + /* End current session */ + $old_session = session_name(); + $old_id = session_id(); + session_write_close(); + + /* Load single signon session */ + session_name($session_name); + session_id($_COOKIE[$session_name]); + session_start(); + + /* Clear error message */ + unset($_SESSION['PMA_single_signon_error_message']); + + /* Grab credentials if they exist */ + if (isset($_SESSION['PMA_single_signon_user'])) { + if ($do_logout) { + $PHP_AUTH_USER = ''; + } else { + $PHP_AUTH_USER = $_SESSION['PMA_single_signon_user']; + } + } + if (isset($_SESSION['PMA_single_signon_password'])) { + if ($do_logout) { + $PHP_AUTH_PW = ''; + } else { + $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 */ + session_write_close(); + + /* Restart phpMyAdmin session */ + session_name($old_session); + if (!empty($old_id)) { + session_id($old_id); + } + 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_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 the valid servers settings + * @global integer the id of the current server + * @global array the current server settings + * @global string the current username + * @global string 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 */ + $old_session = session_name(); + $old_id = session_id(); + session_write_close(); + + /* Load single signon session */ + session_name($session_name); + session_id($_COOKIE[$session_name]); + session_start(); + + /* Set error message */ + if (! empty($GLOBALS['login_without_password_is_forbidden'])) { + $_SESSION['PMA_single_signon_error_message'] = __( + 'Login without a password is forbidden by configuration ' + . '(see AllowNoPassword)' + ); + } elseif (! empty($GLOBALS['allowDeny_forbidden'])) { + $_SESSION['PMA_single_signon_error_message'] = __('Access denied'); + } elseif (! empty($GLOBALS['no_activity'])) { + $_SESSION['PMA_single_signon_error_message'] = sprintf( + __('No activity within %s seconds; please log in again'), + $GLOBALS['cfg']['LoginCookieValidity'] + ); + } elseif (PMA_DBI_getError()) { + $_SESSION['PMA_single_signon_error_message'] = PMA_sanitize( + PMA_DBI_getError() + ); + } else { + $_SESSION['PMA_single_signon_error_message'] = __( + 'Cannot log in to the MySQL server' + ); + } + } + $this->auth(); + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } +}
\ No newline at end of file diff --git a/hugo/libraries/plugins/auth/swekey/authentication.inc.php b/hugo/libraries/plugins/auth/swekey/authentication.inc.php new file mode 100644 index 0000000..1977f88 --- /dev/null +++ b/hugo/libraries/plugins/auth/swekey/authentication.inc.php @@ -0,0 +1,172 @@ +<?php +/** + * @package Swekey + */ +?> + +<script> + + var g_SwekeyPlugin = null; + + // ------------------------------------------------------------------- + // Create the swekey plugin if it does not exists + function Swekey_Plugin() + { + try + { + if (g_SwekeyPlugin != null) + return g_SwekeyPlugin; + + if (window.ActiveXObject) + { + g_SwekeyPlugin = document.getElementById("swekey_activex"); + if (g_SwekeyPlugin == null) + { + // we must create the activex that way instead of new ActiveXObject("FbAuthAx.FbAuthCtl"); + // ortherwise SetClientSite is not called and we can not get the url + var div = document.createElement('div'); + div.innerHTML='<object id="swekey_activex" style="display:none" CLASSID="CLSID:8E02E3F9-57AA-4EE1-AA68-A42DD7B0FADE"></object>'; + + // Never append to the body because it may still loading and it breaks IE + document.body.insertBefore(div, document.body.firstChild); + g_SwekeyPlugin = document.getElementById("swekey_activex"); + } + return g_SwekeyPlugin; + } + + g_SwekeyPlugin = document.getElementById("swekey_plugin"); + if (g_SwekeyPlugin != null) + return g_SwekeyPlugin; + + for (i = 0; i < navigator.plugins.length; i ++) + { + try + { + if (navigator.plugins[i] == null) + { + navigator.plugins.refresh(); + } + else if (navigator.plugins[i][0] != null && navigator.plugins[i][0].type == "application/fbauth-plugin") + { + var x = document.createElement('embed'); + x.setAttribute('type', 'application/fbauth-plugin'); + x.setAttribute('id', 'swekey_plugin'); + x.setAttribute('width', '0'); + x.setAttribute('height', '0'); + x.style.dislay='none'; + + //document.body.appendChild(x); + document.body.insertBefore(x, document.body.firstChild); + g_SwekeyPlugin = document.getElementById("swekey_plugin"); + return g_SwekeyPlugin; + } + } + catch (e) + { + navigator.plugins.refresh(); + //alert ('Failed to create plugin: ' + e); + } + } + } + catch (e) + { + //alert("Swekey_Plugin " + e); + g_SwekeyPlugin = null; + } + return null; + } + + // ------------------------------------------------------------------- + // Returns true if the swekey plugin is installed + function Swekey_Installed() + { + return (Swekey_Plugin() != null); + } + + // ------------------------------------------------------------------- + // List the id of the Swekey connected to the PC + // Returns a string containing comma separated Swekey Ids + // A Swekey is a 32 char hexadecimal value. + function Swekey_ListKeyIds() + { + try + { + return Swekey_Plugin().list(); + } + catch (e) + { +// alert("Swekey_ListKeyIds " + e); + } + return ""; + } + + // ------------------------------------------------------------------- + // Ask the Connected Swekey to generate an OTP + // id: The id of the connected Swekey (returne by Swekey_ListKeyIds()) + // rt: A random token + // return: The calculated OTP encoded in a 64 chars hexadecimal value. + function Swekey_GetOtp(id, rt) + { + try + { + return Swekey_Plugin().getotp(id, rt); + } + catch (e) + { +// alert("Swekey_GetOtp " + e); + } + return ""; + } + + // ------------------------------------------------------------------- + // Ask the Connected Swekey to generate a OTP linked to the current https host + // id: The id of the connected Swekey (returne by Swekey_ListKeyIds()) + // rt: A random token + // return: The calculated OTP encoded in a 64 chars hexadecimal value. + // or "" if the current url does not start with https + function Swekey_GetLinkedOtp(id, rt) + { + try + { + return Swekey_Plugin().getlinkedotp(id, rt); + } + catch (e) + { +// alert("Swekey_GetSOtp " + e); + } + return ""; + } + + // ------------------------------------------------------------------- + // Calls Swekey_GetOtp or Swekey_GetLinkedOtp depending if we are in + // an https page or not. + // id: The id of the connected Swekey (returne by Swekey_ListKeyIds()) + // rt: A random token + // return: The calculated OTP encoded in a 64 chars hexadecimal value. + function Swekey_GetSmartOtp(id, rt) + { + var res = Swekey_GetLinkedOtp(id, rt); + if (res == "") + res = Swekey_GetOtp(id, rt); + + return res; + } + + // ------------------------------------------------------------------- + // Set a unplug handler (url) to the specified connected feebee + // id: The id of the connected Swekey (returne by Swekey_ListKeyIds()) + // key: The key that index that url, (aplhanumeric values only) + // url: The url that will be launched ("" deletes the url) + function Swekey_SetUnplugUrl(id, key, url) + { + try + { + return Swekey_Plugin().setunplugurl(id, key, url); + } + catch (e) + { +// alert("Swekey_SetUnplugUrl " + e); + } + } + +</script> diff --git a/hugo/libraries/plugins/auth/swekey/musbe-ca.crt b/hugo/libraries/plugins/auth/swekey/musbe-ca.crt new file mode 100644 index 0000000..2a31ad1 --- /dev/null +++ b/hugo/libraries/plugins/auth/swekey/musbe-ca.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIJAMjw7QcLWCd6MA0GCSqGSIb3DQEBBQUAMGsxCzAJBgNV +BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRQwEgYDVQQKEwtNdXNiZSwgSW5j +LjESMBAGA1UEAxMJbXVzYmUuY29tMR0wGwYJKoZIhvcNAQkBFg5pbmZvQG11c2Jl +LmNvbTAeFw0wODA5MDQxNDE2MTNaFw0zNzEyMjExNDE2MTNaMGsxCzAJBgNVBAYT +AlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRQwEgYDVQQKEwtNdXNiZSwgSW5jLjES +MBAGA1UEAxMJbXVzYmUuY29tMR0wGwYJKoZIhvcNAQkBFg5pbmZvQG11c2JlLmNv +bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOBhOljxVzQfK4gted2I +d3BemcjW4abAUOzn3KYWXpPO5xIfVeXNDGkDbyH+X+7fo94sX25/ewuKNFDSOcvo +tXHq7uQenTHB35r+a+LY81KceUHgW90a3XsqPAkwAjyYcgo3zmM2DtLvw+5Yod8T +wAHk9m3qavnQ1uk99jBTwL7RZ9jIZHh9pFCL93uJc2obtd8O96Iycbn2q0w/AWbb ++eUVWIHzvLtfPvROeL3lJzr/Uz5LjKapxJ3qyqASflfHpnj9pU8l6g2TQ6Hg5KT5 +tLFkRe7uGhOfRtOQ/+NjaWrEuNCFnpyN4Q5Fv+5qA1Ip1IpH0200sWbAf/k2u0Qp +Sx0CAwEAAaOB0DCBzTAdBgNVHQ4EFgQUczJrQ7hCvtsnzcqiDIZ/GSn/CiwwgZ0G +A1UdIwSBlTCBkoAUczJrQ7hCvtsnzcqiDIZ/GSn/Ciyhb6RtMGsxCzAJBgNVBAYT +AlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRQwEgYDVQQKEwtNdXNiZSwgSW5jLjES +MBAGA1UEAxMJbXVzYmUuY29tMR0wGwYJKoZIhvcNAQkBFg5pbmZvQG11c2JlLmNv +bYIJAMjw7QcLWCd6MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAGxk +8xzIljeBDQWWVRr0NEALVSv3i09V4jAKkyEOfmZ8lKMKJi0atwbtjrXTzLnNYj+Q +pyUbyY/8ItWvV7pnVxMiF9qcer7e9X4vw358GZuMVE/da1nWxz+CwzTm5oO30RzA +antM9bISFFr9lJq69bDWOnCUi1IG8DSL3TxtlABso7S4vqiZ+sB33l6k1K4a/Njb +QkU9UejKhKkVVZTsOrumfnOJ4MCmPfX8Y/AY2o670y5HnzpxerIYziCVzApPVrW7 +sKH0tuVGturMfQOKgstYe4/m9glBTeTLMkjD+6MJC2ONBD7GAiOO95gNl5M1fzJQ +FEe5CJ7DCYl0GdmLXXw= +-----END CERTIFICATE----- diff --git a/hugo/libraries/plugins/auth/swekey/swekey.auth.lib.php b/hugo/libraries/plugins/auth/swekey/swekey.auth.lib.php new file mode 100644 index 0000000..678cb1a --- /dev/null +++ b/hugo/libraries/plugins/auth/swekey/swekey.auth.lib.php @@ -0,0 +1,297 @@ +<?php +/** + * @package Swekey + */ + +if (! defined('PHPMYADMIN')) { + exit; +} + +/** + * Checks Swekey authentication. + */ +function Swekey_auth_check() +{ + global $cfg; + $confFile = $cfg['Server']['auth_swekey_config']; + + if (! isset($_SESSION['SWEKEY'])) { + $_SESSION['SWEKEY'] = array(); + } + + $_SESSION['SWEKEY']['ENABLED'] = (! empty($confFile) && file_exists($confFile)); + + // Load the swekey.conf file the first time + if ($_SESSION['SWEKEY']['ENABLED'] + && empty($_SESSION['SWEKEY']['CONF_LOADED']) + ) { + $_SESSION['SWEKEY']['CONF_LOADED'] = true; + $_SESSION['SWEKEY']['VALID_SWEKEYS'] = array(); + $valid_swekeys = explode("\n", @file_get_contents($confFile)); + foreach ($valid_swekeys as $line) { + if (preg_match("/^[0-9A-F]{32}:.+$/", $line) != false) { + $items = explode(":", $line); + if (count($items) == 2) { + $_SESSION['SWEKEY']['VALID_SWEKEYS'][$items[0]] = trim($items[1]); + } + } elseif (preg_match("/^[A-Z_]+=.*$/", $line) != false) { + $items = explode("=", $line); + $_SESSION['SWEKEY']['CONF_'.trim($items[0])] = trim($items[1]); + } + } + + // Set default values for settings + if (! isset($_SESSION['SWEKEY']['CONF_SERVER_CHECK'])) { + $_SESSION['SWEKEY']['CONF_SERVER_CHECK'] = ""; + } + if (! isset($_SESSION['SWEKEY']['CONF_SERVER_RNDTOKEN'])) { + $_SESSION['SWEKEY']['CONF_SERVER_RNDTOKEN'] = ""; + } + if (! isset($_SESSION['SWEKEY']['CONF_SERVER_STATUS'])) { + $_SESSION['SWEKEY']['CONF_SERVER_STATUS'] = ""; + } + if (! isset($_SESSION['SWEKEY']['CONF_CA_FILE'])) { + $_SESSION['SWEKEY']['CONF_CA_FILE'] = ""; + } + if (! isset($_SESSION['SWEKEY']['CONF_ENABLE_TOKEN_CACHE'])) { + $_SESSION['SWEKEY']['CONF_ENABLE_TOKEN_CACHE'] = true; + } + if (! isset($_SESSION['SWEKEY']['CONF_DEBUG'])) { + $_SESSION['SWEKEY']['CONF_DEBUG'] = false; + } + } + + // check if a web key has been authenticated + if ($_SESSION['SWEKEY']['ENABLED']) { + if (empty($_SESSION['SWEKEY']['AUTHENTICATED_SWEKEY'])) { + return false; + } + } + + return true; +} + + +/** + * Handle Swekey authentication error. + */ +function Swekey_auth_error() +{ + if (! isset($_SESSION['SWEKEY'])) { + return null; + } + + if (! $_SESSION['SWEKEY']['ENABLED']) { + return null; + } + + include_once './libraries/plugins/auth/swekey/authentication.inc.php'; + + ?> + <script> + function Swekey_GetValidKey() + { + var valids = "<?php + foreach ($_SESSION['SWEKEY']['VALID_SWEKEYS'] as $key => $value) { + echo $key.','; + } + ?>"; + var connected_keys = Swekey_ListKeyIds().split(","); + for (i in connected_keys) { + if (connected_keys[i] != null && connected_keys[i].length == 32) { + if (valids.indexOf(connected_keys[i]) >= 0) { + return connected_keys[i]; + } + } + } + + + if (connected_keys.length > 0) { + if (connected_keys[0].length == 32) { + return "unknown_key_" + connected_keys[0]; + } + } + + return "none"; + } + + var key = Swekey_GetValidKey(); + + function timedCheck() + { + if (key != Swekey_GetValidKey()) { + window.location.search = "?swekey_reset"; + } else { + setTimeout("timedCheck()",1000); + } + } + + setTimeout("timedCheck()",1000); + </script> + <?php + + if (! empty($_SESSION['SWEKEY']['AUTHENTICATED_SWEKEY'])) { + return null; + } + + if (count($_SESSION['SWEKEY']['VALID_SWEKEYS']) == 0) { + return sprintf(__('File %s does not contain any key id'), $GLOBALS['cfg']['Server']['auth_swekey_config']); + } + + include_once "libraries/plugins/auth/swekey/swekey.php"; + + Swekey_SetCheckServer($_SESSION['SWEKEY']['CONF_SERVER_CHECK']); + Swekey_SetRndTokenServer($_SESSION['SWEKEY']['CONF_SERVER_RNDTOKEN']); + Swekey_SetStatusServer($_SESSION['SWEKEY']['CONF_SERVER_STATUS']); + Swekey_EnableTokenCache($_SESSION['SWEKEY']['CONF_ENABLE_TOKEN_CACHE']); + + $caFile = $_SESSION['SWEKEY']['CONF_CA_FILE']; + if (empty($caFile)) { + $caFile = __FILE__; + $pos = strrpos($caFile, '/'); + if ($pos === false) { + $pos = strrpos($caFile, '\\'); // windows + } + $caFile = substr($caFile, 0, $pos + 1).'musbe-ca.crt'; +// echo "\n<!-- $caFile -->\n"; +// if (file_exists($caFile)) +// echo "<!-- exists -->\n"; + } + + if (file_exists($caFile)) { + Swekey_SetCAFile($caFile); + } elseif (! empty($caFile) && (substr($_SESSION['SWEKEY']['CONF_SERVER_CHECK'], 0, 8) == "https://")) { + return "Internal Error: CA File $caFile not found"; + } + + $result = null; + $swekey_id = $_GET['swekey_id']; + $swekey_otp = $_GET['swekey_otp']; + + if (isset($swekey_id)) { + unset($_SESSION['SWEKEY']['AUTHENTICATED_SWEKEY']); + if (! isset($_SESSION['SWEKEY']['RND_TOKEN'])) { + unset($swekey_id); + } else { + if (strlen($swekey_id) == 32) { + $res = Swekey_CheckOtp($swekey_id, $_SESSION['SWEKEY']['RND_TOKEN'], $swekey_otp); + unset($_SESSION['SWEKEY']['RND_TOKEN']); + if (! $res) { + $result = __('Hardware authentication failed') . ' (' . Swekey_GetLastError() . ')'; + } else { + $_SESSION['SWEKEY']['AUTHENTICATED_SWEKEY'] = $swekey_id; + $_SESSION['SWEKEY']['FORCE_USER'] = $_SESSION['SWEKEY']['VALID_SWEKEYS'][$swekey_id]; + return null; + } + } else { + $result = __('No valid authentication key plugged'); + if ($_SESSION['SWEKEY']['CONF_DEBUG']) { + $result .= "<br/>" . htmlspecialchars($swekey_id); + } + unset($_SESSION['SWEKEY']['CONF_LOADED']); // reload the conf file + } + } + } else { + unset($_SESSION['SWEKEY']); + } + + $_SESSION['SWEKEY']['RND_TOKEN'] = Swekey_GetFastRndToken(); + if (strlen($_SESSION['SWEKEY']['RND_TOKEN']) != 64) { + $result = __('Hardware authentication failed') . ' (' . Swekey_GetLastError() . ')'; + unset($_SESSION['SWEKEY']['CONF_LOADED']); // reload the conf file + } + + if (! isset($swekey_id)) { + ?> + <script> + if (key.length != 32) { + window.location.search="?swekey_id=" + key + "&token=<?php echo $_SESSION[' PMA_token ']; ?>"; + } else { + var url = "" + window.location; + if (url.indexOf("?") > 0) { + url = url.substr(0, url.indexOf("?")); + } + Swekey_SetUnplugUrl(key, "pma_login", url + "?session_to_unset=<?php echo session_id();?>&token=<?php echo $_SESSION[' PMA_token ']; ?>"); + var otp = Swekey_GetOtp(key, <?php echo '"'.$_SESSION['SWEKEY']['RND_TOKEN'].'"';?>); + window.location.search="?swekey_id=" + key + "&swekey_otp=" + otp + "&token=<?php echo $_SESSION[' PMA_token ']; ?>"; + } + </script> + <?php + return __('Authenticating…'); + } + + return $result; +} + + +/** + * Perform login using Swekey. + */ +function Swekey_login($input_name, $input_go) +{ + $swekeyErr = Swekey_auth_error(); + if ($swekeyErr != null) { + PMA_Message::error($swekeyErr)->display(); + if ($GLOBALS['error_handler']->hasDisplayErrors()) { + echo '<div>'; + $GLOBALS['error_handler']->dispErrors(); + echo '</div>'; + } + } + + if (isset($_SESSION['SWEKEY']) && $_SESSION['SWEKEY']['ENABLED']) { + echo '<script type="text/javascript">'; + if (empty($_SESSION['SWEKEY']['FORCE_USER'])) { + echo 'var user = null;'; + } else { + echo 'var user = "'.$_SESSION['SWEKEY']['FORCE_USER'].'";'; + } + + ?> + function open_swekey_site() + { + window.open("<?php echo PMA_linkURL('http://phpmyadmin.net/auth_key'); ?>"); + } + + var input_username = document.getElementById("<?php echo $input_name; ?>"); + var input_go = document.getElementById("<?php echo $input_go; ?>"); + var swekey_status = document.createElement('img'); + swekey_status.setAttribute('onclick', 'open_swekey_site()'); + swekey_status.setAttribute('style', 'width:8px; height:16px; border:0px; vspace:0px; hspace:0px; frameborder:no'); + if (user == null) { + swekey_status.setAttribute('src', 'http://artwork.swekey.com/unplugged-8x16.png'); + //swekey_status.setAttribute('title', 'No swekey plugged'); + input_go.disabled = true; + } else { + swekey_status.setAttribute('src', 'http://artwork.swekey.com/plugged-8x16.png'); + //swekey_status.setAttribute('title', 'swekey plugged'); + input_username.value = user; + } + input_username.readOnly = true; + + if (input_username.nextSibling == null) { + input_username.parentNode.appendChild(swekey_status); + } else { + input_username.parentNode.insertBefore(swekey_status, input_username.nextSibling); + } + + <?php + echo '</script>'; + } +} + +if (!empty($_GET['session_to_unset'])) { + session_write_close(); + session_id($_GET['session_to_unset']); + session_start(); + $_SESSION = array(); + session_write_close(); + session_destroy(); + exit; +} + +if (isset($_GET['swekey_reset'])) { + unset($_SESSION['SWEKEY']); +} + +?> diff --git a/hugo/libraries/plugins/auth/swekey/swekey.php b/hugo/libraries/plugins/auth/swekey/swekey.php new file mode 100644 index 0000000..d495d45 --- /dev/null +++ b/hugo/libraries/plugins/auth/swekey/swekey.php @@ -0,0 +1,522 @@ +<?php +/** + * Library that provides common functions that are used to help integrating Swekey Authentication in a PHP web site + * Version 1.0 + * + * History: + * 1.2 Use curl (widely installed) to query the server + * Fixed a possible tempfile race attack + * Random token cache can now be disabled + * 1.1 Added Swekey_HttpGet function that support faulty servers + * Support for custom servers + * 1.0 First release + * + * @package Swekey + */ + + +/** + * Errors codes + */ +define("SWEKEY_ERR_INVALID_DEV_STATUS", 901); // The satus of the device is not SWEKEY_STATUS_OK +define("SWEKEY_ERR_INTERNAL", 902); // Should never occurd +define("SWEKEY_ERR_OUTDATED_RND_TOKEN", 910); // You random token is too old +define("SWEKEY_ERR_INVALID_OTP", 911); // The otp was not correct + +/** + * Those errors are considered as an attack and your site will be blacklisted during one minute + * if you receive one of those errors + */ +define("SWEKEY_ERR_BADLY_ENCODED_REQUEST", 920); +define("SWEKEY_ERR_INVALID_RND_TOKEN", 921); +define("SWEKEY_ERR_DEV_NOT_FOUND", 922); + +/** + * Default values for configuration. + */ +define('SWEKEY_DEFAULT_CHECK_SERVER', 'https://auth-check.musbe.net'); +define('SWEKEY_DEFAULT_RND_SERVER', 'https://auth-rnd-gen.musbe.net'); +define('SWEKEY_DEFAULT_STATUS_SERVER', 'https://auth-status.musbe.net'); + +/** + * The last error of an operation is alway put in this global var + */ + +global $gSwekeyLastError; +$gSwekeyLastError = 0; + +global $gSwekeyLastResult; +$gSwekeyLastResult = "<not set>"; + +/** + * Servers addresses + * Use the Swekey_SetXxxServer($server) functions to set them + */ + +global $gSwekeyCheckServer; +if (! isset($gSwekeyCheckServer)) { + $gSwekeyCheckServer = SWEKEY_DEFAULT_CHECK_SERVER; +} + +global $gSwekeyRndTokenServer; +if (! isset($gSwekeyRndTokenServer)) { + $gSwekeyRndTokenServer = SWEKEY_DEFAULT_RND_SERVER; +} + +global $gSwekeyStatusServer; +if (! isset($gSwekeyStatusServer)) { + $gSwekeyStatusServer = SWEKEY_DEFAULT_STATUS_SERVER; +} + +global $gSwekeyCA; + +global $gSwekeyTokenCacheEnabled; +if (! isset($gSwekeyTokenCacheEnabled)) { + $gSwekeyTokenCacheEnabled = true; +} + +/** + * Change the address of the Check server. + * If $server is empty the default value 'http://auth-check.musbe.net' will be used + * + * @param server The protocol and hostname to use + * + * @access public + */ +function Swekey_SetCheckServer($server) +{ + global $gSwekeyCheckServer; + if (empty($server)) { + $gSwekeyCheckServer = SWEKEY_DEFAULT_CHECK_SERVER; + } else { + $gSwekeyCheckServer = $server; + } +} + +/** + * Change the address of the Random Token Generator server. + * If $server is empty the default value 'http://auth-rnd-gen.musbe.net' will be used + * + * @param server The protocol and hostname to use + * + * @access public + */ +function Swekey_SetRndTokenServer($server) +{ + global $gSwekeyRndTokenServer; + if (empty($server)) { + $gSwekeyRndTokenServer = SWEKEY_DEFAULT_RND_SERVER; + } else { + $gSwekeyRndTokenServer = $server; + } +} + +/** + * Change the address of the Satus server. + * If $server is empty the default value 'http://auth-status.musbe.net' will be used + * + * @param server The protocol and hostname to use + * + * @access public + */ +function Swekey_SetStatusServer($server) +{ + global $gSwekeyStatusServer; + if (empty($server)) { + $gSwekeyStatusServer = SWEKEY_DEFAULT_STATUS_SERVER; + } else { + $gSwekeyStatusServer = $server; + } +} + +/** + * Change the certificat file in case of the the severs use https instead of http + * + * @param cafile The path of the crt file to use + * + * @access public + */ +function Swekey_SetCAFile($cafile) +{ + global $gSwekeyCA; + $gSwekeyCA = $cafile; +} + +/** + * Enable or disable the random token caching + * Because everybody has full access to the cache file, it can be a DOS vulnerability + * So disable it if you are running in a non secure enviromnement + * + * @param $enable + * + * @access public + */ +function Swekey_EnableTokenCache($enable) +{ + global $gSwekeyTokenCacheEnabled; + $gSwekeyTokenCacheEnabled = ! empty($enable); +} + + +/** + * Return the last error. + * + * @return The Last Error + * @access public + */ +function Swekey_GetLastError() +{ + global $gSwekeyLastError; + return $gSwekeyLastError; +} + +/** + * Return the last result. + * + * @return The Last Error + * @access public + */ +function Swekey_GetLastResult() +{ + global $gSwekeyLastResult; + return $gSwekeyLastResult; +} + +/** + * Send a synchronous request to the server. + * This function manages timeout then will not block if one of the server is down + * + * @param url The url to get + * @param response_code The response code + * + * @return The body of the response or "" in case of error + * @access private + */ +function Swekey_HttpGet($url, &$response_code) +{ + global $gSwekeyLastError; + $gSwekeyLastError = 0; + global $gSwekeyLastResult; + $gSwekeyLastResult = "<not set>"; + + // use curl if available + if (function_exists('curl_init')) { + $sess = curl_init($url); + if (substr($url, 0, 8) == "https://") { + global $gSwekeyCA; + + if (! empty($gSwekeyCA)) { + if (file_exists($gSwekeyCA)) { + if (! curl_setopt($sess, CURLOPT_CAINFO, $gSwekeyCA)) { + error_log("SWEKEY_ERROR:Could not set CA file : ".curl_error($sess)); + } else { + $caFileOk = true; + } + } else { + error_log("SWEKEY_ERROR:Could not find CA file $gSwekeyCA getting $url"); + } + } + + curl_setopt($sess, CURLOPT_SSL_VERIFYHOST, '2'); + curl_setopt($sess, CURLOPT_SSL_VERIFYPEER, '2'); + curl_setopt($sess, CURLOPT_CONNECTTIMEOUT, '20'); + curl_setopt($sess, CURLOPT_TIMEOUT, '20'); + } else { + curl_setopt($sess, CURLOPT_CONNECTTIMEOUT, '3'); + curl_setopt($sess, CURLOPT_TIMEOUT, '5'); + } + + curl_setopt($sess, CURLOPT_RETURNTRANSFER, '1'); + $res=curl_exec($sess); + $response_code = curl_getinfo($sess, CURLINFO_HTTP_CODE); + $curlerr = curl_error($sess); + curl_close($sess); + + if ($response_code == 200) { + $gSwekeyLastResult = $res; + return $res; + } + + if (! empty($response_code)) { + $gSwekeyLastError = $response_code; + error_log("SWEKEY_ERROR:Error $gSwekeyLastError ($curlerr) getting $url"); + return ""; + } + + $response_code = 408; // Request Timeout + $gSwekeyLastError = $response_code; + error_log("SWEKEY_ERROR:Error $curlerr getting $url"); + return ""; + } + + // use pecl_http if available + if (class_exists('HttpRequest')) { + // retry if one of the server is down + for ($num=1; $num <= 3; $num++ ) { + $r = new HttpRequest($url); + $options = array('timeout' => '3'); + + if (substr($url, 0, 6) == "https:") { + $sslOptions = array(); + $sslOptions['verifypeer'] = true; + $sslOptions['verifyhost'] = true; + + $capath = __FILE__; + $name = strrchr($capath, '/'); + // windows + if (empty($name)) { + $name = strrchr($capath, '\\'); + } + $capath = substr($capath, 0, strlen($capath) - strlen($name) + 1).'musbe-ca.crt'; + + if (! empty($gSwekeyCA)) { + $sslOptions['cainfo'] = $gSwekeyCA; + } + + $options['ssl'] = $sslOptions; + } + + $r->setOptions($options); + + // try + { + $reply = $r->send(); + $res = $reply->getBody(); + $info = $r->getResponseInfo(); + $response_code = $info['response_code']; + if ($response_code != 200) { + $gSwekeyLastError = $response_code; + error_log("SWEKEY_ERROR:Error ".$gSwekeyLastError." getting ".$url); + return ""; + } + + + $gSwekeyLastResult = $res; + return $res; + } + // catch (HttpException $e) + // { + // error_log("SWEKEY_WARNING:HttpException ".$e." getting ".$url); + // } + } + + $response_code = 408; // Request Timeout + $gSwekeyLastError = $response_code; + error_log("SWEKEY_ERROR:Error ".$gSwekeyLastError." getting ".$url); + return ""; + } + + global $http_response_header; + $res = @file_get_contents($url); + $response_code = substr($http_response_header[0], 9, 3); //HTTP/1.0 + if ($response_code == 200) { + $gSwekeyLastResult = $res; + return $res; + } + + $gSwekeyLastError = $response_code; + error_log("SWEKEY_ERROR:Error ".$response_code." getting ".$url); + return ""; +} + +/** + * Get a Random Token from a Token Server + * The RT is a 64 vhars hexadecimal value + * You should better use Swekey_GetFastRndToken() for performance + * @access public + */ +function Swekey_GetRndToken() +{ + global $gSwekeyRndTokenServer; + return Swekey_HttpGet($gSwekeyRndTokenServer.'/FULL-RND-TOKEN', $response_code); +} + +/** + * Get a Half Random Token from a Token Server + * The RT is a 64 vhars hexadecimal value + * Use this value if you want to make your own Swekey_GetFastRndToken() + * @access public + */ +function Swekey_GetHalfRndToken() +{ + global $gSwekeyRndTokenServer; + return Swekey_HttpGet($gSwekeyRndTokenServer.'/HALF-RND-TOKEN', $response_code); +} + +/** + * Get a Half Random Token + * The RT is a 64 vhars hexadecimal value + * This function get a new random token and reuse it. + * Token are refetched from the server only once every 30 seconds. + * You should always use this function to get half random token. + * @access public + */ +function Swekey_GetFastHalfRndToken() +{ + global $gSwekeyTokenCacheEnabled; + + $res = ""; + $cachefile = ""; + + // We check if we have a valid RT is the session + if (isset($_SESSION['rnd-token-date'])) { + if (time() - $_SESSION['rnd-token-date'] < 30) { + $res = $_SESSION['rnd-token']; + } + } + + // If not we try to get it from a temp file (PHP >= 5.2.1 only) + if (strlen($res) != 32 && $gSwekeyTokenCacheEnabled) { + if (function_exists('sys_get_temp_dir')) { + $tempdir = sys_get_temp_dir(); + $cachefile = $tempdir."/swekey-rnd-token-".get_current_user(); + $modif = filemtime($cachefile); + if ($modif != false) { + if (time() - $modif < 30) { + $res = @file_get_contents($cachefile); + if (strlen($res) != 32) { + $res = ""; + } else { + $_SESSION['rnd-token'] = $res; + $_SESSION['rnd-token-date'] = $modif; + } + } + } + } + } + + // If we don't have a valid RT here we have to get it from the server + if (strlen($res) != 32) { + $res = substr(Swekey_GetHalfRndToken(), 0, 32); + $_SESSION['rnd-token'] = $res; + $_SESSION['rnd-token-date'] = time(); + if (! empty($cachefile)) { + // we unlink the file so no possible tempfile race attack + unlink($cachefile); + $file = fopen($cachefile, "x"); + if ($file != false) { + @fwrite($file, $res); + @fclose($file); + } + } + } + + return $res."00000000000000000000000000000000"; +} + +/** + * Get a Random Token + * The RT is a 64 vhars hexadecimal value + * This function generates a unique random token for each call but call the + * server only once every 30 seconds. + * You should always use this function to get random token. + * @access public + */ +function Swekey_GetFastRndToken() +{ + $res = Swekey_GetFastHalfRndToken(); + if (strlen($res) == 64) { + return substr($res, 0, 32).strtoupper(md5("Musbe Authentication Key" . mt_rand() . date(DATE_ATOM))); + } + return ""; +} + + +/** + * Checks that an OTP generated by a Swekey is valid + * + * @param id The id of the swekey + * @param rt The random token used to generate the otp + * @param otp The otp generated by the swekey + * + * @return true or false + * @access public + */ +function Swekey_CheckOtp($id, $rt, $otp) +{ + global $gSwekeyCheckServer; + $res = Swekey_HttpGet($gSwekeyCheckServer.'/CHECK-OTP/'.$id.'/'.$rt.'/'.$otp, $response_code); + return $response_code == 200 && $res == "OK"; +} + +/** + * Values that are associated with a key. + * The following values can be returned by the Swekey_GetStatus() function + */ +define("SWEKEY_STATUS_OK", 0); +define("SWEKEY_STATUS_NOT_FOUND", 1); // The key does not exist in the db +define("SWEKEY_STATUS_INACTIVE", 2); // The key has never been activated +define("SWEKEY_STATUS_LOST", 3); // The user has lost his key +define("SWEKEY_STATUS_STOLEN", 4); // The key was stolen +define("SWEKEY_STATUS_FEE_DUE", 5); // The annual fee was not paid +define("SWEKEY_STATUS_OBSOLETE", 6); // The hardware is no longer supported +define("SWEKEY_STATUS_UNKOWN", 201); // We could not connect to the authentication server + +/** + * Values that are associated with a key. + * The Javascript Api can also return the following values + */ +define("SWEKEY_STATUS_REPLACED", 100); // This key has been replaced by a backup key +define("SWEKEY_STATUS_BACKUP_KEY", 101); // This key is a backup key that is not activated yet +define("SWEKEY_STATUS_NOTPLUGGED", 200); // This key is not plugged in the computer + + +/** + * Return the text corresponding to the integer status of a key + * + * @param status The status + * + * @return The text corresponding to the status + * @access public + */ +function Swekey_GetStatusStr($status) +{ + switch($status) + { + case SWEKEY_STATUS_OK : + return 'OK'; + case SWEKEY_STATUS_NOT_FOUND : + return 'Key does not exist in the db'; + case SWEKEY_STATUS_INACTIVE : + return 'Key not activated'; + case SWEKEY_STATUS_LOST : + return 'Key was lost'; + case SWEKEY_STATUS_STOLEN : + return 'Key was stolen'; + case SWEKEY_STATUS_FEE_DUE : + return 'The annual fee was not paid'; + case SWEKEY_STATUS_OBSOLETE : + return 'Key no longer supported'; + case SWEKEY_STATUS_REPLACED : + return 'This key has been replaced by a backup key'; + case SWEKEY_STATUS_BACKUP_KEY : + return 'This key is a backup key that is not activated yet'; + case SWEKEY_STATUS_NOTPLUGGED : + return 'This key is not plugged in the computer'; + case SWEKEY_STATUS_UNKOWN : + return 'Unknow Status, could not connect to the authentication server'; + } + return 'unknown status '.$status; +} + +/** + * If your web site requires a key to login you should check that the key + * is still valid (has not been lost or stolen) before requiring it. + * A key can be authenticated only if its status is SWEKEY_STATUS_OK + * + * @param id The id of the swekey + * + * @return The status of the swekey + * @access public + */ +function Swekey_GetStatus($id) +{ + global $gSwekeyStatusServer; + $res = Swekey_HttpGet($gSwekeyStatusServer.'/GET-STATUS/'.$id, $response_code); + if ($response_code == 200) { + return intval($res); + } + return SWEKEY_STATUS_UNKOWN; +} + +?> diff --git a/hugo/libraries/plugins/export/ExportCodegen.class.php b/hugo/libraries/plugins/export/ExportCodegen.class.php new file mode 100644 index 0000000..d0a2216 --- /dev/null +++ b/hugo/libraries/plugins/export/ExportCodegen.class.php @@ -0,0 +1,423 @@ +<?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 + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the export interface */ +require_once 'libraries/plugins/ExportPlugin.class.php'; +/* Get the table property class */ +require_once 'libraries/plugins/export/TableProperty.class.php'; + +/** + * 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() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/HiddenPropertyItem.class.php"; + include_once "$props/options/items/SelectPropertyItem.class.php"; + + $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(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create primary items and add them to the group + $leaf = new HiddenPropertyItem(); + $leaf->setName("structure_or_data"); + $generalOptions->addProperty($leaf); + $leaf = new SelectPropertyItem(); + $leaf->setName("format"); + $leaf->setText(__('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; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * 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 + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + 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 + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + 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 + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + $CG_FORMATS = $this->_getCgFormats(); + $CG_HANDLERS = $this->_getCgHandlers(); + + $format = $GLOBALS['codegen_format']; + if (isset($CG_FORMATS[$format])) { + return PMA_exportOutputHandler( + $this->$CG_HANDLERS[$format]($db, $table, $crlf) + ); + } + 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 + * + * @return string containing C# code lines, separated by "\n" + */ + private function _handleNHibernateCSBody($db, $table, $crlf) + { + $lines = array(); + + $result = PMA_DBI_query( + sprintf( + 'DESC %s.%s', PMA_Util::backquote($db), + PMA_Util::backquote($table) + ) + ); + if ($result) { + $tableProperties = array(); + while ($row = PMA_DBI_fetch_row($result)) { + $tableProperties[] = new TableProperty($row); + } + PMA_DBI_free_result($result); + $lines[] = 'using System;'; + $lines[] = 'using System.Collections;'; + $lines[] = 'using System.Collections.Generic;'; + $lines[] = 'using System.Text;'; + $lines[] = 'namespace ' . ExportCodegen::cgMakeIdentifier($db); + $lines[] = '{'; + $lines[] = ' #region ' . ExportCodegen::cgMakeIdentifier($table); + $lines[] = ' public class ' . ExportCodegen::cgMakeIdentifier($table); + $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) . '() { }'; + $temp = array(); + foreach ($tableProperties as $tableProperty) { + if (! $tableProperty->isPK()) { + $temp[] = $tableProperty->formatCs( + '#dotNetPrimitiveType# #name#' + ); + } + } + $lines[] = ' public ' + . ExportCodegen::cgMakeIdentifier($table) + . '(' + . 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("\n", $lines); + } + + /** + * XML Handler + * + * @param string $db database name + * @param string $table table name + * @param string $crlf line separator + * + * @return string containing XML code lines, separated by "\n" + */ + private function _handleNHibernateXMLBody($db, $table, $crlf) + { + $lines = array(); + $lines[] = '<?xml version="1.0" encoding="utf-8" ?' . '>'; + $lines[] = '<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" ' + . 'namespace="' . ExportCodegen::cgMakeIdentifier($db) . '" ' + . 'assembly="' . ExportCodegen::cgMakeIdentifier($db) . '">'; + $lines[] = ' <class ' + . 'name="' . ExportCodegen::cgMakeIdentifier($table) . '" ' + . 'table="' . ExportCodegen::cgMakeIdentifier($table) . '">'; + $result = PMA_DBI_query( + sprintf( + "DESC %s.%s", PMA_Util::backquote($db), + PMA_Util::backquote($table) + ) + ); + if ($result) { + while ($row = PMA_DBI_fetch_row($result)) { + $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>' + ); + } + } + PMA_DBI_free_result($result); + } + $lines[] = ' </class>'; + $lines[] = '</hibernate-mapping>'; + return implode("\n", $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; + } +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/export/ExportCsv.class.php b/hugo/libraries/plugins/export/ExportCsv.class.php new file mode 100644 index 0000000..98558e9 --- /dev/null +++ b/hugo/libraries/plugins/export/ExportCsv.class.php @@ -0,0 +1,345 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * CSV export code + * + * @package PhpMyAdmin-Export + * @subpackage CSV + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the export interface */ +require_once 'libraries/plugins/ExportPlugin.class.php'; + +/** + * Handles the export for the CSV format + * + * @package PhpMyAdmin-Export + * @subpackage CSV + */ +class ExportCsv extends ExportPlugin +{ + /** + * The string used to end lines + * + * @var string + */ + private $_csvTerminated; + + /** + * The string used to separate columns + * + * @var string + */ + private $_csvSeparator; + + /** + * The string used to enclose columns + * + * @var string + */ + private $_csvEnclosed; + + /** + * The string used to escape columns + * + * @var string + */ + private $_csvEscaped; + + /** + * Constructor + */ + public function __construct() + { + $this->setProperties(); + } + + /** + * Sets the export CSV properties + * + * @return void + */ + protected function setProperties() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/TextPropertyItem.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + include_once "$props/options/items/HiddenPropertyItem.class.php"; + + $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(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create leaf items and add them to the group + $leaf = new TextPropertyItem(); + $leaf->setName("separator"); + $leaf->setText(__('Columns separated with:')); + $generalOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("enclosed"); + $leaf->setText(__('Columns enclosed with:')); + $generalOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("escaped"); + $leaf->setText(__('Columns escaped with:')); + $generalOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("terminated"); + $leaf->setText(__('Lines terminated with:')); + $generalOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName('null'); + $leaf->setText(__('Replace NULL with:')); + $generalOptions->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName('removeCRLF'); + $leaf->setText( + __('Remove carriage return/line feed characters within columns') + ); + $generalOptions->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName('columns'); + $leaf->setText(__('Put columns names in the first row')); + $generalOptions->addProperty($leaf); + $leaf = new HiddenPropertyItem(); + $leaf->setName('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; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * 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) || 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 + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + 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 + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + 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 + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + global $what, $csv_terminated, $csv_separator, $csv_enclosed, $csv_escaped; + + // Gets the data from the database + $result = PMA_DBI_query($sql_query, null, PMA_DBI_QUERY_UNBUFFERED); + $fields_cnt = PMA_DBI_num_fields($result); + + // If required, get fields name at the first line + if (isset($GLOBALS['csv_columns'])) { + $schema_insert = ''; + for ($i = 0; $i < $fields_cnt; $i++) { + if ($csv_enclosed == '') { + $schema_insert .= stripslashes(PMA_DBI_field_name($result, $i)); + } else { + $schema_insert .= $csv_enclosed + . str_replace( + $csv_enclosed, + $csv_escaped . $csv_enclosed, + stripslashes(PMA_DBI_field_name($result, $i)) + ) + . $csv_enclosed; + } + $schema_insert .= $csv_separator; + } // end for + $schema_insert = trim(substr($schema_insert, 0, -1)); + if (! PMA_exportOutputHandler($schema_insert . $csv_terminated)) { + return false; + } + } // end if + + // Format the data + while ($row = PMA_DBI_fetch_row($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 + PMA_DBI_free_result($result); + + return true; + } +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/export/ExportExcel.class.php b/hugo/libraries/plugins/export/ExportExcel.class.php new file mode 100644 index 0000000..1bb1060 --- /dev/null +++ b/hugo/libraries/plugins/export/ExportExcel.class.php @@ -0,0 +1,105 @@ +<?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 + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Extend the export CSV class */ +require_once 'libraries/plugins/export/ExportCsv.class.php'; + +/** + * 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() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/TextPropertyItem.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + include_once "$props/options/items/SelectPropertyItem.class.php"; + include_once "$props/options/items/HiddenPropertyItem.class.php"; + + $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(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create primary items and add them to the group + $leaf = new TextPropertyItem(); + $leaf->setName('null'); + $leaf->setText(__('Replace NULL with:')); + $generalOptions->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName('removeCRLF'); + $leaf->setText( + __('Remove carriage return/line feed characters within columns') + ); + $generalOptions->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName('columns'); + $leaf->setText(__('Put columns names in the first row')); + $generalOptions->addProperty($leaf); + $leaf = new SelectPropertyItem(); + $leaf->setName('edition'); + $leaf->setValues( + array( + 'win' => 'Windows', + 'mac_excel2003' => 'Excel 2003 / Macintosh', + 'mac_excel2008' => 'Excel 2008 / Macintosh' + ) + ); + $leaf->setText(__('Excel edition:')); + $generalOptions->addProperty($leaf); + $leaf = new HiddenPropertyItem(); + $leaf->setName('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; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/export/ExportHtmlword.class.php b/hugo/libraries/plugins/export/ExportHtmlword.class.php new file mode 100644 index 0000000..cdd5ec6 --- /dev/null +++ b/hugo/libraries/plugins/export/ExportHtmlword.class.php @@ -0,0 +1,645 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * HTML-Word export code + * + * @package PhpMyAdmin-Export + * @subpackage HTML-Word + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the export interface */ +require_once 'libraries/plugins/ExportPlugin.class.php'; + +/** + * 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() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/RadioPropertyItem.class.php"; + include_once "$props/options/items/TextPropertyItem.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + + $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(); + $exportSpecificOptions->setName("Format Specific Options"); + + // what to dump (structure/data/both) + $dumpWhat = new OptionsPropertyMainGroup(); + $dumpWhat->setName("dump_what"); + $dumpWhat->setText(__('Dump table')); + // create primary items and add them to the group + $leaf = new RadioPropertyItem(); + $leaf->setName("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(); + $dataOptions->setName("dump_what"); + $dataOptions->setText(__('Data dump options')); + $dataOptions->setForce('structure'); + // create primary items and add them to the group + $leaf = new TextPropertyItem(); + $leaf->setName("null"); + $leaf->setText(__('Replace NULL with:')); + $dataOptions->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName("columns"); + $leaf->setText(__('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; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Outputs export header + * + * @return bool Whether it succeeded + */ + public function exportHeader () + { + global $charset_of_file; + + 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_of_file) ? $charset_of_file : '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 + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + return PMA_exportOutputHandler( + '<h1>' . __('Database') . ' ' . htmlspecialchars($db) . '</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 + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + 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 + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + global $what; + + if (! PMA_exportOutputHandler( + '<h2>' + . __('Dumping data for table') . ' ' . htmlspecialchars($table) + . '</h2>' + )) { + return false; + } + if (! PMA_exportOutputHandler( + '<table class="width100" cellspacing="1">' + )) { + return false; + } + + // Gets the data from the database + $result = PMA_DBI_query($sql_query, null, PMA_DBI_QUERY_UNBUFFERED); + $fields_cnt = PMA_DBI_num_fields($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++) { + $schema_insert .= '<td class="print"><strong>' + . htmlspecialchars( + stripslashes(PMA_DBI_field_name($result, $i)) + ) + . '</strong></td>'; + } // end for + $schema_insert .= '</tr>'; + if (! PMA_exportOutputHandler($schema_insert)) { + return false; + } + } // end if + + // Format the data + while ($row = PMA_DBI_fetch_row($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 + PMA_DBI_free_result($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 + * + * @return string resulting definition + */ + public function getTableDefStandIn($db, $view, $crlf) + { + $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 = PMA_DBI_get_table_indexes($db, $view); + foreach ($keys as $key) { + if ($key['Non_unique'] == 0) { + $unique_keys[] = $key['Column_name']; + } + } + + $columns = PMA_DBI_get_columns($db, $view); + foreach ($columns as $column) { + $schema_insert .= $this->formatOneColumnDefinition( + $column, + $unique_keys + ); + $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 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 + * 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 + * + * @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 + ) { + // set $cfgRelation here, because there is a chance that it's modified + // since the class initialization + global $cfgRelation; + + $schema_insert = ''; + + /** + * Gets fields properties + */ + PMA_DBI_select_db($db); + + // Check if we can use Relations + if ($do_relation && ! empty($cfgRelation['relation'])) { + // Find which tables are related with the current one and write it in + // an array + $res_rel = PMA_getForeigners($db, $table); + + if ($res_rel && count($res_rel) > 0) { + $have_rel = true; + } else { + $have_rel = false; + } + } else { + $have_rel = false; + } // end if + + /** + * Displays the table structure + */ + $schema_insert .= '<table class="width100" cellspacing="1">'; + + $columns_cnt = 4; + if ($do_relation && $have_rel) { + $columns_cnt++; + } + if ($do_comments && $cfgRelation['commwork']) { + $columns_cnt++; + } + if ($do_mime && $cfgRelation['mimework']) { + $columns_cnt++; + } + + $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 = PMA_DBI_get_columns($db, $table); + /** + * Get the unique keys in the table + */ + $unique_keys = array(); + $keys = PMA_DBI_get_table_indexes($db, $table); + foreach ($keys as $key) { + if ($key['Non_unique'] == 0) { + $unique_keys[] = $key['Column_name']; + } + } + foreach ($columns as $column) { + $schema_insert .= $this->formatOneColumnDefinition( + $column, + $unique_keys + ); + $field_name = $column['Field']; + + if ($do_relation && $have_rel) { + $schema_insert .= '<td class="print">' + . (isset($res_rel[$field_name]) + ? htmlspecialchars( + $res_rel[$field_name]['foreign_table'] + . ' (' . $res_rel[$field_name]['foreign_field'] + . ')' + ) + : '') . '</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 = PMA_DBI_get_triggers($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 + * + * @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 + ) { + $dump = ''; + + switch($export_mode) { + case 'create_table': + $dump .= '<h2>' + . __('Table structure for table') . ' ' . htmlspecialchars($table) + . '</h2>'; + $dump .= $this->getTableDef( + $db, $table, $crlf, $error_url, $do_relation, $do_comments, $do_mime, + $dates + ); + break; + case 'triggers': + $dump = ''; + $triggers = PMA_DBI_get_triggers($db, $table); + if ($triggers) { + $dump .= '<h2>' + . __('Triggers') . ' ' . htmlspecialchars($table) + . '</h2>'; + $dump .= $this->getTriggers($db, $table); + } + break; + case 'create_view': + $dump .= '<h2>' + . __('Structure for view') . ' ' . htmlspecialchars($table) + . '</h2>'; + $dump .= $this->getTableDef( + $db, $table, $crlf, $error_url, $do_relation, $do_comments, $do_mime, + $dates, true, true + ); + break; + case 'stand_in': + $dump .= '<h2>' + . __('Stand-in structure for view') . ' ' . htmlspecialchars($table) + . '</h2>'; + // export a stand-in definition to resolve view dependencies + $dump .= $this->getTableDefStandIn($db, $table, $crlf); + } // 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 + * + * @return string Formatted column definition + */ + protected function formatOneColumnDefinition( + $column, $unique_keys + ) { + $definition = '<tr class="print-category">'; + + $extracted_columnspec + = PMA_Util::extractColumnSpec($column['Type']); + + $type = htmlspecialchars($extracted_columnspec['print_type']); + if (empty($type)) { + $type = ' '; + } + + if (! isset($column['Default'])) { + if ($column['Null'] != 'NO') { + $column['Default'] = 'NULL'; + } + } + + $fmt_pre = ''; + $fmt_post = ''; + if (in_array($column['Field'], $unique_keys)) { + $fmt_pre = '<strong>' . $fmt_pre; + $fmt_post = $fmt_post . '</strong>'; + } + if ($column['Key'] == 'PRI') { + $fmt_pre = '<em>' . $fmt_pre; + $fmt_post = $fmt_post . '</em>'; + } + $definition .= '<td class="print">' . $fmt_pre + . htmlspecialchars($column['Field']) . $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; + } +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/export/ExportJson.class.php b/hugo/libraries/plugins/export/ExportJson.class.php new file mode 100644 index 0000000..299e248 --- /dev/null +++ b/hugo/libraries/plugins/export/ExportJson.class.php @@ -0,0 +1,221 @@ +<?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 + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the export interface */ +require_once 'libraries/plugins/ExportPlugin.class.php'; + +/** + * 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() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/HiddenPropertyItem.class.php"; + + $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(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create primary items and add them to the group + $leaf = new HiddenPropertyItem(); + $leaf->setName("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; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Outputs export header + * + * @return bool Whether it succeeded + */ + public function exportHeader () + { + PMA_exportOutputHandler( + '/**' . $GLOBALS['crlf'] + . ' Export to JSON plugin for PHPMyAdmin' . $GLOBALS['crlf'] + . ' @version 0.1' . $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 + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + PMA_exportOutputHandler('// Database \'' . $db . '\'' . $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 + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + 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 + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + $result = PMA_DBI_query($sql_query, null, PMA_DBI_QUERY_UNBUFFERED); + $columns_cnt = PMA_DBI_num_fields($result); + + // Get field information + $fields_meta = PMA_DBI_get_fields_meta($result); + + for ($i = 0; $i < $columns_cnt; $i++) { + $columns[$i] = stripslashes(PMA_DBI_field_name($result, $i)); + } + unset($i); + + $buffer = ''; + $record_cnt = 0; + while ($record = PMA_DBI_fetch_row($result)) { + + $record_cnt++; + + // Output table name as comment if this is the first record of the table + if ($record_cnt == 1) { + $buffer .= '// ' . $db . '.' . $table . $crlf . $crlf; + $buffer .= '[{'; + } else { + $buffer .= ', {'; + } + + for ($i = 0; $i < $columns_cnt; $i++) { + $isLastLine = ($i + 1 >= $columns_cnt); + $column = $columns[$i]; + if (is_null($record[$i])) { + $buffer .= '"' . addslashes($column) + . '": null' + . (! $isLastLine ? ',' : ''); + } elseif ($fields_meta[$i]->numeric) { + $buffer .= '"' . addslashes($column) + . '": ' + . $record[$i] + . (! $isLastLine ? ',' : ''); + } else { + $buffer .= '"' . addslashes($column) + . '": "' + . addslashes($record[$i]) + . '"' + . (! $isLastLine ? ',' : ''); + } + } + + $buffer .= '}'; + } + + if ($record_cnt) { + $buffer .= ']'; + } + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + + PMA_DBI_free_result($result); + return true; + } +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/export/ExportLatex.class.php b/hugo/libraries/plugins/export/ExportLatex.class.php new file mode 100644 index 0000000..0f5c953 --- /dev/null +++ b/hugo/libraries/plugins/export/ExportLatex.class.php @@ -0,0 +1,655 @@ +<?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 + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the export interface */ +require_once 'libraries/plugins/ExportPlugin.class.php'; + +/** + * 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; + } + + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + include_once "$props/options/items/RadioPropertyItem.class.php"; + include_once "$props/options/items/TextPropertyItem.class.php"; + + $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(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create primary items and add them to the group + $leaf = new BoolPropertyItem(); + $leaf->setName("caption"); + $leaf->setText(__('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(); + $dumpWhat->setName("dump_what"); + $dumpWhat->setText(__('Dump table')); + // create primary items and add them to the group + $leaf = new RadioPropertyItem(); + $leaf->setName("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(); + $structureOptions->setName("structure"); + $structureOptions->setText(__('Object creation options')); + $structureOptions->setForce('data'); + // create primary items and add them to the group + $leaf = new TextPropertyItem(); + $leaf->setName("structure_caption"); + $leaf->setText(__('Table caption')); + $leaf->setDoc('faq6-27'); + $structureOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("structure_continued_caption"); + $leaf->setText(__('Table caption (continued)')); + $leaf->setDoc('faq6-27'); + $structureOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("structure_label"); + $leaf->setText(__('Label key')); + $leaf->setDoc('faq6-27'); + $structureOptions->addProperty($leaf); + if (! empty($GLOBALS['cfgRelation']['relation'])) { + $leaf = new BoolPropertyItem(); + $leaf->setName("relation"); + $leaf->setText(__('Display foreign key relationships')); + $structureOptions->addProperty($leaf); + } + $leaf = new BoolPropertyItem(); + $leaf->setName("comments"); + $leaf->setText(__('Display comments')); + $structureOptions->addProperty($leaf); + if (! empty($GLOBALS['cfgRelation']['mimework'])) { + $leaf = new BoolPropertyItem(); + $leaf->setName("mime"); + $leaf->setText(__('Display MIME types')); + $structureOptions->addProperty($leaf); + } + // add the main group to the root group + $exportSpecificOptions->addProperty($structureOptions); + } + + // data options main group + $dataOptions = new OptionsPropertyMainGroup(); + $dataOptions->setName("data"); + $dataOptions->setText(__('Data dump options')); + $dataOptions->setForce('structure'); + // create primary items and add them to the group + $leaf = new BoolPropertyItem(); + $leaf->setName("columns"); + $leaf->setText(__('Put columns names in the first row')); + $dataOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("data_caption"); + $leaf->setText(__('Table caption')); + $leaf->setDoc('faq6-27'); + $dataOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("data_continued_caption"); + $leaf->setText(__('Table caption (continued)')); + $leaf->setDoc('faq6-27'); + $dataOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("data_label"); + $leaf->setText(__('Label key')); + $leaf->setDoc('faq6-27'); + $dataOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName('null'); + $leaf->setText(__('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; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Outputs export header + * + * @return bool Whether it succeeded + */ + public function exportHeader () + { + global $crlf; + global $cfg; + + $head = '% phpMyAdmin LaTeX Dump' . $crlf + . '% version ' . PMA_VERSION . $crlf + . '% http://www.phpmyadmin.net' . $crlf + . '%' . $crlf + . '% ' . __('Host') . ': ' . $cfg['Server']['host']; + if (! empty($cfg['Server']['port'])) { + $head .= ':' . $cfg['Server']['port']; + } + $head .= $crlf + . '% ' . __('Generation Time') . ': ' + . PMA_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 + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + global $crlf; + $head = '% ' . $crlf + . '% ' . __('Database') . ': ' . '\'' . $db . '\'' . $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 + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + 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 + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + $result = PMA_DBI_try_query($sql_query, null, PMA_DBI_QUERY_UNBUFFERED); + + $columns_cnt = PMA_DBI_num_fields($result); + for ($i = 0; $i < $columns_cnt; $i++) { + $columns[$i] = PMA_DBI_field_name($result, $i); + } + unset($i); + + $buffer = $crlf . '%' . $crlf . '% ' . __('Data') . ': ' . $table + . $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{' + . PMA_Util::expandUserString( + $GLOBALS['latex_data_caption'], + array( + 'texEscape', + get_class($this), + 'libraries/plugins/export/' . get_class($this) . ".class.php" + ), + array('table' => $table, 'database' => $db) + ) + . '} \\label{' + . PMA_Util::expandUserString( + $GLOBALS['latex_data_label'], + null, + array('table' => $table, 'database' => $db) + ) + . '} \\\\'; + } + 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[$i])) . '}} & '; + } + + $buffer = substr($buffer, 0, -2) . '\\\\ \\hline \hline '; + if (! PMA_exportOutputHandler($buffer . ' \\endfirsthead ' . $crlf)) { + return false; + } + if (isset($GLOBALS['latex_caption'])) { + if (! PMA_exportOutputHandler( + '\\caption{' + . PMA_Util::expandUserString( + $GLOBALS['latex_data_continued_caption'], + array( + 'texEscape', + get_class($this), + 'libraries/plugins/export/' + . get_class($this) . ".class.php" + ), + array('table' => $table, 'database' => $db) + ) + . '} \\\\ ' + )) { + return false; + } + } + if (! PMA_exportOutputHandler($buffer . '\\endhead \\endfoot' . $crlf)) { + return false; + } + } else { + if (! PMA_exportOutputHandler('\\\\ \hline')) { + return false; + } + } + + // print the whole table + while ($record = PMA_DBI_fetch_assoc($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; + } + + PMA_DBI_free_result($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 + * + * @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 + ) { + global $cfgRelation; + + /* We do not export triggers */ + if ($export_mode == 'triggers') { + return true; + } + + /** + * Get the unique keys in the table + */ + $unique_keys = array(); + $keys = PMA_DBI_get_table_indexes($db, $table); + foreach ($keys as $key) { + if ($key['Non_unique'] == 0) { + $unique_keys[] = $key['Column_name']; + } + } + + /** + * Gets fields properties + */ + PMA_DBI_select_db($db); + + // Check if we can use Relations + if ($do_relation && ! empty($cfgRelation['relation'])) { + // Find which tables are related with the current one and write it in + // an array + $res_rel = PMA_getForeigners($db, $table); + + if ($res_rel && count($res_rel) > 0) { + $have_rel = true; + } else { + $have_rel = false; + } + } else { + $have_rel = false; + } // end if + + /** + * Displays the table structure + */ + $buffer = $crlf . '%' . $crlf . '% ' . __('Structure') . ': ' . $table + . $crlf . '%' . $crlf . ' \\begin{longtable}{'; + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + + $columns_cnt = 4; + $alignment = '|l|c|c|c|'; + if ($do_relation && $have_rel) { + $columns_cnt++; + $alignment .= 'l|'; + } + if ($do_comments) { + $columns_cnt++; + $alignment .= 'l|'; + } + if ($do_mime && $cfgRelation['mimework']) { + $columns_cnt++; + $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{' + . PMA_Util::expandUserString( + $GLOBALS['latex_structure_caption'], + array( + 'texEscape', + get_class($this), + 'libraries/plugins/export/' . get_class($this) . ".class.php" + ), + array('table' => $table, 'database' => $db) + ) + . '} \\label{' + . PMA_Util::expandUserString( + $GLOBALS['latex_structure_label'], + null, + array('table' => $table, 'database' => $db) + ) + . '} \\\\' . $crlf; + } + $buffer .= $header . ' \\\\ \\hline \\hline' . $crlf + . '\\endfirsthead' . $crlf; + // Table caption on next pages + if (isset($GLOBALS['latex_caption'])) { + $buffer .= ' \\caption{' + . PMA_Util::expandUserString( + $GLOBALS['latex_structure_continued_caption'], + array( + 'texEscape', + get_class($this), + 'libraries/plugins/export/' . get_class($this) . ".class.php" + ), + array('table' => $table, 'database' => $db) + ) + . '} \\\\ ' . $crlf; + } + $buffer .= $header . ' \\\\ \\hline \\hline \\endhead \\endfoot ' . $crlf; + + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + + $fields = PMA_DBI_get_columns($db, $table); + foreach ($fields as $row) { + $extracted_columnspec + = PMA_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 = $row['Field']; + + $local_buffer = $field_name . "\000" . $type . "\000" + . (($row['Null'] == '' || $row['Null'] == 'NO') + ? __('No') : __('Yes')) + . "\000" . (isset($row['Default']) ? $row['Default'] : ''); + + if ($do_relation && $have_rel) { + $local_buffer .= "\000"; + if (isset($res_rel[$field_name])) { + $local_buffer .= $res_rel[$field_name]['foreign_table'] . ' (' + . $res_rel[$field_name]['foreign_field'] . ')'; + } + } + 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=strpos($local_buffer, "\000"); + $local_buffer = '\\textit{' + . substr($local_buffer, 0, $pos) + . '}' . substr($local_buffer, $pos); + } + if (in_array($field_name, $unique_keys)) { + $pos=strpos($local_buffer, "\000"); + $local_buffer = '\\textbf{' + . substr($local_buffer, 0, $pos) + . '}' . 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; + } +} +?> diff --git a/hugo/libraries/plugins/export/ExportMediawiki.class.php b/hugo/libraries/plugins/export/ExportMediawiki.class.php new file mode 100644 index 0000000..89afe71 --- /dev/null +++ b/hugo/libraries/plugins/export/ExportMediawiki.class.php @@ -0,0 +1,364 @@ +<?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 + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the export interface */ +require_once 'libraries/plugins/ExportPlugin.class.php'; + +/** + * 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() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/groups/OptionsPropertySubgroup.class.php"; + include_once "$props/options/items/MessageOnlyPropertyItem.class.php"; + include_once "$props/options/items/RadioPropertyItem.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + + $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(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + $generalOptions->setText(__('Dump table')); + + // what to dump (structure/data/both) + $subgroup = new OptionsPropertySubgroup(); + $subgroup->setName("dump_table"); + $subgroup->setText("Dump table"); + $leaf = new RadioPropertyItem(); + $leaf->setName('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(); + $leaf->setName("caption"); + $leaf->setText(__('Export table names')); + $generalOptions->addProperty($leaf); + + // export table headers + $leaf = new BoolPropertyItem(); + $leaf->setName("headers"); + $leaf->setText(__('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; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * 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 + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + 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 + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + 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 + * + * @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 + ) { + switch($export_mode) { + case 'create_table': + $columns = PMA_DBI_get_columns($db, $table); + $columns = array_values($columns); + $row_cnt = count($columns); + + // Print structure comment + $output = $this->_exportComment( + "Table structure for " + . PMA_Util::backquote($table) + ); + + // Begin the table construction + $output .= "{| class=\"wikitable\" style=\"text-align:center;\"" + . $this->_exportCRLF(); + + // Add the table name + if ($GLOBALS['mediawiki_caption']) { + $output .= "|+'''" . $table . "'''" . $this->_exportCRLF(); + } + + // Add the table headers + if ($GLOBALS['mediawiki_headers']) { + $output .= "|- style=\"background:#ffdead;\"" . $this->_exportCRLF(); + $output .= "! style=\"background:#ffffff\" | " + . $this->_exportCRLF(); + for ($i = 0; $i < $row_cnt; ++$i) { + $output .= " | " . $columns[$i]['Field']. $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 + * + * @return bool Whether it succeeded + */ + public function exportData( + $db, + $table, + $crlf, + $error_url, + $sql_query + ) { + // Print data comment + $output = $this->_exportComment( + "Table data for ". PMA_Util::backquote($table) + ); + + // 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 ($GLOBALS['mediawiki_caption']) { + $output .= "|+'''" . $table . "'''" . $this->_exportCRLF(); + } + + // Add the table headers + if ($GLOBALS['mediawiki_headers']) { + // Get column names + $column_names = PMA_DBI_get_column_names($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) { + $output .= " ! " . $column . "" . $this->_exportCRLF(); + } + } + } + + // Get the table data from the database + $result = PMA_DBI_query($sql_query, null, PMA_DBI_QUERY_UNBUFFERED); + $fields_cnt = PMA_DBI_num_fields($result); + + while ($row = PMA_DBI_fetch_row($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 .= $text . $this->_exportCRLF(); + $comment .= '-->' . str_repeat($this->_exportCRLF(), 2); + + return $comment; + } + + /** + * Outputs CRLF + * + * @return string CRLF + */ + private function _exportCRLF() + { + // The CRLF expected by the mediawiki format is "\n" + return "\n"; + } +} +?> diff --git a/hugo/libraries/plugins/export/ExportOds.class.php b/hugo/libraries/plugins/export/ExportOds.class.php new file mode 100644 index 0000000..b1e9f91 --- /dev/null +++ b/hugo/libraries/plugins/export/ExportOds.class.php @@ -0,0 +1,334 @@ +<?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 + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the export interface */ +require_once 'libraries/plugins/ExportPlugin.class.php'; + +$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() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/TextPropertyItem.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + include_once "$props/options/items/HiddenPropertyItem.class.php"; + + $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(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create primary items and add them to the group + $leaf = new TextPropertyItem(); + $leaf->setName("null"); + $leaf->setText(__('Replace NULL with:')); + $generalOptions->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName("columns"); + $leaf->setText(__('Put columns names in the first row')); + $generalOptions->addProperty($leaf); + $leaf = new HiddenPropertyItem(); + $leaf->setName("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; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * 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 + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + 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 + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + 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 + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + global $what; + + // Gets the data from the database + $result = PMA_DBI_query($sql_query, null, PMA_DBI_QUERY_UNBUFFERED); + $fields_cnt = PMA_DBI_num_fields($result); + $fields_meta = PMA_DBI_get_fields_meta($result); + $field_flags = array(); + for ($j = 0; $j < $fields_cnt; $j++) { + $field_flags[$j] = PMA_DBI_field_flags($result, $j); + } + + $GLOBALS['ods_buffer'] .= + '<table:table table:name="' . htmlspecialchars($table) . '">'; + + // 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++) { + $GLOBALS['ods_buffer'] .= + '<table:table-cell office:value-type="string">' + . '<text:p>' + . htmlspecialchars( + stripslashes(PMA_DBI_field_name($result, $i)) + ) + . '</text:p>' + . '</table:table-cell>'; + } // end for + $GLOBALS['ods_buffer'] .= '</table:table-row>'; + } // end if + + // Format the data + while ($row = PMA_DBI_fetch_row($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 + PMA_DBI_free_result($result); + + $GLOBALS['ods_buffer'] .= '</table:table>'; + + return true; + } +} +?> diff --git a/hugo/libraries/plugins/export/ExportOdt.class.php b/hugo/libraries/plugins/export/ExportOdt.class.php new file mode 100644 index 0000000..bb608f0 --- /dev/null +++ b/hugo/libraries/plugins/export/ExportOdt.class.php @@ -0,0 +1,734 @@ +<?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 + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the export interface */ +require_once 'libraries/plugins/ExportPlugin.class.php'; + +$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; + } + + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/TextPropertyItem.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + include_once "$props/options/items/HiddenPropertyItem.class.php"; + include_once "$props/options/items/RadioPropertyItem.class.php"; + + $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(); + $exportSpecificOptions->setName("Format Specific Options"); + + // what to dump (structure/data/both) main group + $dumpWhat = new OptionsPropertyMainGroup(); + $dumpWhat->setName("general_opts"); + $dumpWhat->setText(__('Dump table')); + // create primary items and add them to the group + $leaf = new RadioPropertyItem(); + $leaf->setName("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(); + $structureOptions->setName("structure"); + $structureOptions->setText(__('Object creation options')); + $structureOptions->setForce('data'); + // create primary items and add them to the group + if (! empty($GLOBALS['cfgRelation']['relation'])) { + $leaf = new BoolPropertyItem(); + $leaf->setName("relation"); + $leaf->setText(__('Display foreign key relationships')); + $structureOptions->addProperty($leaf); + } + $leaf = new BoolPropertyItem(); + $leaf->setName("comments"); + $leaf->setText(__('Display comments')); + $structureOptions->addProperty($leaf); + if (! empty($GLOBALS['cfgRelation']['mimework'])) { + $leaf = new BoolPropertyItem(); + $leaf->setName("mime"); + $leaf->setText(__('Display MIME types')); + $structureOptions->addProperty($leaf); + } + // add the main group to the root group + $exportSpecificOptions->addProperty($structureOptions); + } + + // data options main group + $dataOptions = new OptionsPropertyMainGroup(); + $dataOptions->setName("data"); + $dataOptions->setText(__('Data dump options')); + $dataOptions->setForce('structure'); + // create primary items and add them to the group + $leaf = new BoolPropertyItem(); + $leaf->setName("columns"); + $leaf->setText(__('Put columns names in the first row')); + $dataOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName('null'); + $leaf->setText(__('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; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * 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 + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + $GLOBALS['odt_buffer'] .= + '<text:h text:outline-level="1" text:style-name="Heading_1"' + . ' text:is-list-header="true">' + . __('Database') . ' ' . htmlspecialchars($db) + . '</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 + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + 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 + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + global $what; + + // Gets the data from the database + $result = PMA_DBI_query($sql_query, null, PMA_DBI_QUERY_UNBUFFERED); + $fields_cnt = PMA_DBI_num_fields($result); + $fields_meta = PMA_DBI_get_fields_meta($result); + $field_flags = array(); + for ($j = 0; $j < $fields_cnt; $j++) { + $field_flags[$j] = PMA_DBI_field_flags($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) + . '</text:h>' + . '<table:table' + . ' table:name="' . htmlspecialchars($table) . '_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++) { + $GLOBALS['odt_buffer'] .= + '<table:table-cell office:value-type="string">' + . '<text:p>' + . htmlspecialchars( + stripslashes(PMA_DBI_field_name($result, $i)) + ) + . '</text:p>' + . '</table:table-cell>'; + } // end for + $GLOBALS['odt_buffer'] .= '</table:table-row>'; + } // end if + + // Format the data + while ($row = PMA_DBI_fetch_row($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 + PMA_DBI_free_result($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 + * + * @return bool true + */ + public function getTableDefStandIn($db, $view, $crlf) + { + /** + * Gets fields properties + */ + PMA_DBI_select_db($db); + + /** + * Displays the table structure + */ + $GLOBALS['odt_buffer'] .= + '<table:table table:name="' + . htmlspecialchars($view) . '_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 = PMA_DBI_get_columns($db, $view); + foreach ($columns as $column) { + $GLOBALS['odt_buffer'] .= $this->formatOneColumnDefinition($column); + $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 + * + * @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 + ) { + global $cfgRelation; + + /** + * Gets fields properties + */ + PMA_DBI_select_db($db); + + // Check if we can use Relations + if ($do_relation && ! empty($cfgRelation['relation'])) { + // Find which tables are related with the current one and write it in + // an array + $res_rel = PMA_getForeigners($db, $table); + + if ($res_rel && count($res_rel) > 0) { + $have_rel = true; + } else { + $have_rel = false; + } + } else { + $have_rel = false; + } // end if + + /** + * Displays the table structure + */ + $GLOBALS['odt_buffer'] .= '<table:table table:name="' + . htmlspecialchars($table) . '_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 = PMA_DBI_get_columns($db, $table); + foreach ($columns as $column) { + $field_name = $column['Field']; + $GLOBALS['odt_buffer'] .= $this->formatOneColumnDefinition($column); + + if ($do_relation && $have_rel) { + if (isset($res_rel[$field_name])) { + $GLOBALS['odt_buffer'] .= + '<table:table-cell office:value-type="string">' + . '<text:p>' + . htmlspecialchars( + $res_rel[$field_name]['foreign_table'] + . ' (' . $res_rel[$field_name]['foreign_field'] . ')' + ) + . '</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 + * + * @return bool true + */ + protected function getTriggers($db, $table) + { + $GLOBALS['odt_buffer'] .= '<table:table' + . ' table:name="' . htmlspecialchars($table) . '_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 = PMA_DBI_get_triggers($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 + * + * @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 + ) { + 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) + . '</text:h>'; + $this->getTableDef( + $db, $table, $crlf, $error_url, $do_relation, $do_comments, + $do_mime, $dates + ); + break; + case 'triggers': + $triggers = PMA_DBI_get_triggers($db, $table); + if ($triggers) { + $GLOBALS['odt_buffer'] .= + '<text:h text:outline-level="2" text:style-name="Heading_2"' + . ' text:is-list-header="true">' + . __('Triggers') . ' ' + . htmlspecialchars($table) + . '</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) + . '</text:h>'; + $this->getTableDef( + $db, $table, $crlf, $error_url, $do_relation, $do_comments, + $do_mime, $dates, true, true + ); + 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) + . '</text:h>'; + // export a stand-in definition to resolve view dependencies + $this->getTableDefStandIn($db, $table, $crlf); + } // end switch + + return true; + } // end of the '$this->exportStructure' function + + /** + * Formats the definition for one column + * + * @param array $column info about this column + * + * @return string Formatted column definition + */ + protected function formatOneColumnDefinition($column) + { + $field_name = $column['Field']; + $definition = '<table:table-row>'; + $definition .= '<table:table-cell office:value-type="string">' + . '<text:p>' . htmlspecialchars($field_name) . '</text:p>' + . '</table:table-cell>'; + + $extracted_columnspec + = PMA_Util::extractColumnSpec($column['Type']); + $type = htmlspecialchars($extracted_columnspec['print_type']); + if (empty($type)) { + $type = ' '; + } + + $definition .= '<table:table-cell office:value-type="string">' + . '<text:p>' . htmlspecialchars($type) . '</text:p>' + . '</table:table-cell>'; + if (! isset($column['Default'])) { + if ($column['Null'] != 'NO') { + $column['Default'] = 'NULL'; + } else { + $column['Default'] = ''; + } + } else { + $column['Default'] = $column['Default']; + } + $definition .= '<table:table-cell office:value-type="string">' + . '<text:p>' + . (($column['Null'] == '' || $column['Null'] == 'NO') + ? __('No') + : __('Yes')) + . '</text:p>' + . '</table:table-cell>'; + $definition .= '<table:table-cell office:value-type="string">' + . '<text:p>' . htmlspecialchars($column['Default']) . '</text:p>' + . '</table:table-cell>'; + return $definition; + } +} +?> diff --git a/hugo/libraries/plugins/export/ExportPdf.class.php b/hugo/libraries/plugins/export/ExportPdf.class.php new file mode 100644 index 0000000..ffabb96 --- /dev/null +++ b/hugo/libraries/plugins/export/ExportPdf.class.php @@ -0,0 +1,268 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Produce a PDF report (export) from a query + * + * @package PhpMyAdmin-Export + * @subpackage PDF + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the export interface */ +require_once 'libraries/plugins/ExportPlugin.class.php'; +/* Get the PMA_ExportPdf class */ +require_once 'libraries/plugins/export/PMA_ExportPdf.class.php'; + +/** + * Handles the export for the PDF class + * + * @package PhpMyAdmin-Export + * @subpackage PDF + */ +class ExportPdf extends ExportPlugin +{ + /** + * 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() + { + $this->_setPdfReportTitle(""); + $this->_setPdf(new PMA_ExportPdf('L', 'pt', 'A3')); + } + + /** + * Sets the export PDF properties + * + * @return void + */ + protected function setProperties() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/MessageOnlyPropertyItem.class.php"; + include_once "$props/options/items/TextPropertyItem.class.php"; + include_once "$props/options/items/HiddenPropertyItem.class.php"; + + $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(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create primary items and add them to the group + $leaf = new MessageOnlyPropertyItem(); + $leaf->setName("explanation"); + $leaf->setText( + __('(Generates a report containing the data of a single table)') + ); + $generalOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("report_title"); + $leaf->setText(__('Report title:')); + $generalOptions->addProperty($leaf); + $leaf = new HiddenPropertyItem(); + $leaf->setName("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; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * 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 + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + 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 + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + 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 + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + $pdf = $this->_getPdf(); + + $attr = array('currentDb' => $db, 'currentTable' => $table); + $pdf->setAttributes($attr); + $pdf->mysqlReport($sql_query); + + return true; + } // end of the 'PMA_exportData()' function + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the PMA_ExportPdf instance + * + * @return PMA_ExportPdf + */ + private function _getPdf() + { + return $this->_pdf; + } + + /** + * Instantiates the PMA_ExportPdf class + * + * @param string $pdf PMA_ExportPdf 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; + } +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/export/ExportPhparray.class.php b/hugo/libraries/plugins/export/ExportPhparray.class.php new file mode 100644 index 0000000..2d3b73c --- /dev/null +++ b/hugo/libraries/plugins/export/ExportPhparray.class.php @@ -0,0 +1,227 @@ +<?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 + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the export interface */ +require_once 'libraries/plugins/ExportPlugin.class.php'; + +/** + * 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() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/HiddenPropertyItem.class.php"; + + $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(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create primary items and add them to the group + $leaf = new HiddenPropertyItem(); + $leaf->setName("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; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * 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 0.2b' . $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 + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + PMA_exportOutputHandler( + '//' . $GLOBALS['crlf'] + . '// Database ' . PMA_Util::backquote($db) + . $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 + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + 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 + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + $result = PMA_DBI_query($sql_query, null, PMA_DBI_QUERY_UNBUFFERED); + + $columns_cnt = PMA_DBI_num_fields($result); + for ($i = 0; $i < $columns_cnt; $i++) { + $columns[$i] = stripslashes(PMA_DBI_field_name($result, $i)); + } + unset($i); + + // fix variable names (based on + // http://www.php.net/manual/language.variables.basics.php) + if (! preg_match( + '/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', + $table + )) { + // fix invalid characters in variable names by replacing them with + // underscores + $tablefixed = preg_replace('/[^a-zA-Z0-9_\x7f-\xff]/', '_', $table); + + // variable name must not start with a number or dash... + if (preg_match('/^[a-zA-Z_\x7f-\xff]/', $tablefixed) == false) { + $tablefixed = '_' . $tablefixed; + } + } else { + $tablefixed = $table; + } + + $buffer = ''; + $record_cnt = 0; + // Output table name as comment + $buffer .= $crlf . '// ' + . PMA_Util::backquote($db) . '.' + . PMA_Util::backquote($table) . $crlf; + $buffer .= '$' . $tablefixed . ' = array('; + + while ($record = PMA_DBI_fetch_row($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; + } + + PMA_DBI_free_result($result); + return true; + } +} +?> diff --git a/hugo/libraries/plugins/export/ExportSql.class.php b/hugo/libraries/plugins/export/ExportSql.class.php new file mode 100644 index 0000000..fade66e --- /dev/null +++ b/hugo/libraries/plugins/export/ExportSql.class.php @@ -0,0 +1,1888 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Set of functions used to build SQL dumps of tables + * + * @package PhpMyAdmin-Export + * @subpackage SQL + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the export interface */ +require_once 'libraries/plugins/ExportPlugin.class.php'; + +/** + * Handles the export for the SQL class + * + * @package PhpMyAdmin-Export + * @subpackage SQL + */ +class ExportSql extends ExportPlugin +{ + /** + * Constructor + */ + public function __construct() + { + $this->setProperties(); + + // Avoids undefined variables, use NULL so isset() returns false + if (! isset($GLOBALS['sql_backquotes'])) { + $GLOBALS['sql_backquotes'] = null; + } + } + + /** + * Sets the export SQL properties + * + * @return void + */ + protected function setProperties() + { + global $plugin_param; + + $hide_sql = false; + $hide_structure = false; + if ($plugin_param['export_type'] == 'table' + && ! $plugin_param['single_table'] + ) { + $hide_structure = true; + $hide_sql = true; + } + + if (! $hide_sql) { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/groups/OptionsPropertySubgroup.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + include_once "$props/options/items/MessageOnlyPropertyItem.class.php"; + include_once "$props/options/items/RadioPropertyItem.class.php"; + include_once "$props/options/items/SelectPropertyItem.class.php"; + include_once "$props/options/items/TextPropertyItem.class.php"; + + $exportPluginProperties = new ExportPluginProperties(); + $exportPluginProperties->setText('SQL'); + $exportPluginProperties->setExtension('sql'); + $exportPluginProperties->setMimeType('text/x-sql'); + $exportPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $exportPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + + // comments + $subgroup = new OptionsPropertySubgroup(); + $subgroup->setName("include_comments"); + $leaf = new BoolPropertyItem(); + $leaf->setName('include_comments'); + $leaf->setText( + __( + 'Display comments <i>(includes info such as export' + . ' timestamp, PHP version, and server version)</i>' + ) + ); + $subgroup->setSubgroupHeader($leaf); + + $leaf = new TextPropertyItem(); + $leaf->setName('header_comment'); + $leaf->setText( + __('Additional custom header comment (\n splits lines):') + ); + $subgroup->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName('dates'); + $leaf->setText( + __( + 'Include a timestamp of when databases were created, last' + . ' updated, and last checked' + ) + ); + $subgroup->addProperty($leaf); + if (! empty($GLOBALS['cfgRelation']['relation'])) { + $leaf = new BoolPropertyItem(); + $leaf->setName('relation'); + $leaf->setText(__('Display foreign key relationships')); + $subgroup->addProperty($leaf); + } + if (! empty($GLOBALS['cfgRelation']['mimework'])) { + $leaf = new BoolPropertyItem(); + $leaf->setName('mime'); + $leaf->setText(__('Display MIME types')); + $subgroup->addProperty($leaf); + } + $generalOptions->addProperty($subgroup); + + // enclose in a transaction + $leaf = new BoolPropertyItem(); + $leaf->setName("use_transaction"); + $leaf->setText(__('Enclose export in a transaction')); + $leaf->setDoc( + array( + 'programs', + 'mysqldump', + 'option_mysqldump_single-transaction' + ) + ); + $generalOptions->addProperty($leaf); + + // disable foreign key checks + $leaf = new BoolPropertyItem(); + $leaf->setName("disable_fk"); + $leaf->setText(__('Disable foreign key checks')); + $leaf->setDoc( + array( + 'manual_MySQL_Database_Administration', + 'server-system-variables', + 'sysvar_foreign_key_checks' + ) + ); + $generalOptions->addProperty($leaf); + + // compatibility maximization + $compats = PMA_DBI_getCompatibilities(); + if (count($compats) > 0) { + $values = array(); + foreach ($compats as $val) { + $values[$val] = $val; + } + + $leaf = new SelectPropertyItem(); + $leaf->setName("compatibility"); + $leaf->setText( + __( + 'Database system or older MySQL server to maximize output' + . ' compatibility with:' + ) + ); + $leaf->setValues($values); + $leaf->setDoc( + array( + 'manual_MySQL_Database_Administration', + 'Server_SQL_mode' + ) + ); + $generalOptions->addProperty($leaf); + + unset($values); + } + + // server export options + if ($plugin_param['export_type'] == 'server') { + $leaf = new BoolPropertyItem(); + $leaf->setName("drop_database"); + $leaf->setText( + sprintf(__('Add %s statement'), '<code>DROP DATABASE</code>') + ); + $generalOptions->addProperty($leaf); + } + + // what to dump (structure/data/both) + $subgroup = new OptionsPropertySubgroup(); + $subgroup->setName("dump_table"); + $subgroup->setText("Dump table"); + $leaf = new RadioPropertyItem(); + $leaf->setName('structure_or_data'); + $leaf->setValues( + array( + 'structure' => __('structure'), + 'data' => __('data'), + 'structure_and_data' => __('structure and data') + ) + ); + $subgroup->setSubgroupHeader($leaf); + $generalOptions->addProperty($subgroup); + + // add the main group to the root group + $exportSpecificOptions->addProperty($generalOptions); + + + // structure options main group + if (! $hide_structure) { + $structureOptions = new OptionsPropertyMainGroup(); + $structureOptions->setName("structure"); + $structureOptions->setText(__('Object creation options')); + $structureOptions->setForce('data'); + + // begin SQL Statements + $subgroup = new OptionsPropertySubgroup(); + $leaf = new MessageOnlyPropertyItem(); + $leaf->setName('add_statements'); + $leaf->setText(__('Add statements:')); + $subgroup->setSubgroupHeader($leaf); + + if ($plugin_param['export_type'] != 'table') { + $leaf = new BoolPropertyItem(); + $leaf->setName('create_database'); + $create_clause = '<code>CREATE DATABASE / USE</code>'; + $leaf->setText(sprintf(__('Add %s statement'), $create_clause)); + $subgroup->addProperty($leaf); + } + + if ($plugin_param['export_type'] == 'table') { + if (PMA_Table::isView($GLOBALS['db'], $GLOBALS['table'])) { + $drop_clause = '<code>DROP VIEW</code>'; + } else { + $drop_clause = '<code>DROP TABLE</code>'; + } + } else { + if (PMA_DRIZZLE) { + $drop_clause = '<code>DROP TABLE</code>'; + } else { + $drop_clause = '<code>DROP TABLE / VIEW / PROCEDURE' + . ' / FUNCTION</code>'; + if (PMA_MYSQL_INT_VERSION > 50100) { + $drop_clause .= '<code> / EVENT</code>'; + } + } + } + $leaf = new BoolPropertyItem(); + $leaf->setName('drop_table'); + $leaf->setText(sprintf(__('Add %s statement'), $drop_clause)); + $subgroup->addProperty($leaf); + // Drizzle doesn't support procedures and functions + if (! PMA_DRIZZLE) { + $leaf = new BoolPropertyItem(); + $leaf->setName('procedure_function'); + $leaf->setText( + sprintf( + __('Add %s statement'), + '<code>CREATE PROCEDURE / FUNCTION' + . (PMA_MYSQL_INT_VERSION > 50100 + ? ' / EVENT</code>' : '</code>') + ) + ); + $subgroup->addProperty($leaf); + } + + // begin CREATE TABLE statements + $subgroup_create_table = new OptionsPropertySubgroup(); + $leaf = new BoolPropertyItem(); + $leaf->setName('create_table_statements'); + $leaf->setText(__('<code>CREATE TABLE</code> options:')); + $subgroup_create_table->setSubgroupHeader($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName('if_not_exists'); + $leaf->setText('<code>IF NOT EXISTS</code>'); + $subgroup_create_table->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName('auto_increment'); + $leaf->setText('<code>AUTO_INCREMENT</code>'); + $subgroup_create_table->addProperty($leaf); + $subgroup->addProperty($subgroup_create_table); + $structureOptions->addProperty($subgroup); + + $leaf = new BoolPropertyItem(); + $leaf->setName("backquotes"); + $leaf->setText( + __( + 'Enclose table and column names with backquotes ' + . '<i>(Protects column and table names formed with' + . ' special characters or keywords)</i>' + ) + ); + + $structureOptions->addProperty($leaf); + + // add the main group to the root group + $exportSpecificOptions->addProperty($structureOptions); + } + + + // begin Data options + $dataOptions = new OptionsPropertyMainGroup(); + $dataOptions->setName("data"); + $dataOptions->setText(__('Data creation options')); + $dataOptions->setForce('structure'); + $leaf = new BoolPropertyItem(); + $leaf->setName("truncate"); + $leaf->setText(__('Truncate table before insert')); + $dataOptions->addProperty($leaf); + + // begin SQL Statements + $subgroup = new OptionsPropertySubgroup(); + $leaf = new MessageOnlyPropertyItem(); + $leaf->setText(__('Instead of <code>INSERT</code> statements, use:')); + $subgroup->setSubgroupHeader($leaf); + // Not supported in Drizzle + if (! PMA_DRIZZLE) { + $leaf = new BoolPropertyItem(); + $leaf->setName("delayed"); + $leaf->setText(__('<code>INSERT DELAYED</code> statements')); + $leaf->setDoc( + array( + 'manual_MySQL_Database_Administration', + 'insert_delayed' + ) + ); + $subgroup->addProperty($leaf); + } + $leaf = new BoolPropertyItem(); + $leaf->setName("ignore"); + $leaf->setText(__('<code>INSERT IGNORE</code> statements')); + $leaf->setDoc( + array( + 'manual_MySQL_Database_Administration', + 'insert' + ) + ); + $subgroup->addProperty($leaf); + $dataOptions->addProperty($subgroup); + + // Function to use when dumping dat + $leaf = new SelectPropertyItem(); + $leaf->setName("type"); + $leaf->setText(__('Function to use when dumping data:')); + $leaf->setValues( + array( + 'INSERT' => 'INSERT', + 'UPDATE' => 'UPDATE', + 'REPLACE' => 'REPLACE' + ) + ); + $dataOptions->addProperty($leaf); + + /* Syntax to use when inserting data */ + $subgroup = new OptionsPropertySubgroup(); + $leaf = new MessageOnlyPropertyItem(); + $leaf->setText(__('Syntax to use when inserting data:')); + $subgroup->setSubgroupHeader($leaf); + $leaf = new RadioPropertyItem(); + $leaf->setName("insert_syntax"); + $leaf->setText(__('<code>INSERT IGNORE</code> statements')); + $leaf->setValues( + array( + 'complete' => __( + 'include column names in every <code>INSERT</code> statement' + . ' <br /> Example: <code>INSERT INTO' + . ' tbl_name (col_A,col_B,col_C) VALUES (1,2,3)</code>' + ), + 'extended' => __( + 'insert multiple rows in every <code>INSERT</code> statement' + . '<br /> Example: <code>INSERT INTO' + . ' tbl_name VALUES (1,2,3), (4,5,6), (7,8,9)</code>' + ), + 'both' => __( + 'both of the above<br /> Example:' + . ' <code>INSERT INTO tbl_name (col_A,col_B) VALUES (1,2,3),' + . ' (4,5,6), (7,8,9)</code>' + ), + 'none' => __( + 'neither of the above<br /> Example:' + . ' <code>INSERT INTO tbl_name VALUES (1,2,3)</code>' + ) + ) + ); + $subgroup->addProperty($leaf); + $dataOptions->addProperty($subgroup); + + // Max length of query + $leaf = new TextPropertyItem(); + $leaf->setName("max_query_size"); + $leaf->setText(__('Maximal length of created query')); + $dataOptions->addProperty($leaf); + + // Dump binary columns in hexadecimal + $leaf = new BoolPropertyItem(); + $leaf->setName("hex_for_blob"); + $leaf->setText( + __( + 'Dump binary columns in hexadecimal notation' + . ' <i>(for example, "abc" becomes 0x616263)</i>' + ) + ); + $dataOptions->addProperty($leaf); + + // Drizzle works only with UTC timezone + if (! PMA_DRIZZLE) { + // Dump time in UTC + $leaf = new BoolPropertyItem(); + $leaf->setName("utc_time"); + $leaf->setText( + __( + 'Dump TIMESTAMP columns in UTC <i>(enables TIMESTAMP columns' + . ' to be dumped and reloaded between servers in different' + . ' time zones)</i>' + ) + ); + $dataOptions->addProperty($leaf); + } + + // add the main group to the root group + $exportSpecificOptions->addProperty($dataOptions); + + // set the options for the export plugin property item + $exportPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $exportPluginProperties; + } + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Exports routines (procedures and functions) + * + * @param string $db Database + * + * @return bool Whether it succeeded + */ + public function exportRoutines($db) + { + global $crlf; + + $text = ''; + $delimiter = '$$'; + + $procedure_names = PMA_DBI_get_procedures_or_functions($db, 'PROCEDURE'); + $function_names = PMA_DBI_get_procedures_or_functions($db, 'FUNCTION'); + + if ($procedure_names || $function_names) { + $text .= $crlf + . 'DELIMITER ' . $delimiter . $crlf; + } + + if ($procedure_names) { + $text .= + $this->_exportComment() + . $this->_exportComment(__('Procedures')) + . $this->_exportComment(); + + foreach ($procedure_names as $procedure_name) { + if (! empty($GLOBALS['sql_drop_table'])) { + $text .= 'DROP PROCEDURE IF EXISTS ' + . PMA_Util::backquote($procedure_name) + . $delimiter . $crlf; + } + $text .= PMA_DBI_get_definition($db, 'PROCEDURE', $procedure_name) + . $delimiter . $crlf . $crlf; + } + } + + if ($function_names) { + $text .= + $this->_exportComment() + . $this->_exportComment(__('Functions')) + . $this->_exportComment(); + + foreach ($function_names as $function_name) { + if (! empty($GLOBALS['sql_drop_table'])) { + $text .= 'DROP FUNCTION IF EXISTS ' + . PMA_Util::backquote($function_name) + . $delimiter . $crlf; + } + $text .= PMA_DBI_get_definition($db, 'FUNCTION', $function_name) + . $delimiter . $crlf . $crlf; + } + } + + if ($procedure_names || $function_names) { + $text .= 'DELIMITER ;' . $crlf; + } + + if (! empty($text)) { + return PMA_exportOutputHandler($text); + } else { + return false; + } + } + + /** + * Possibly outputs comment + * + * @param string $text Text of comment + * + * @return string The formatted comment + */ + private function _exportComment($text = '') + { + if (isset($GLOBALS['sql_include_comments']) + && $GLOBALS['sql_include_comments'] + ) { + // see http://dev.mysql.com/doc/refman/5.0/en/ansi-diff-comments.html + return '--' . (empty($text) ? '' : ' ') . $text . $GLOBALS['crlf']; + } else { + return ''; + } + } + + /** + * Possibly outputs CRLF + * + * @return string $crlf or nothing + */ + private function _possibleCRLF() + { + if (isset($GLOBALS['sql_include_comments']) + && $GLOBALS['sql_include_comments'] + ) { + return $GLOBALS['crlf']; + } else { + return ''; + } + } + + /** + * Outputs export footer + * + * @return bool Whether it succeeded + */ + public function exportFooter() + { + global $crlf, $mysql_charset_map; + + $foot = ''; + + if (isset($GLOBALS['sql_disable_fk'])) { + $foot .= 'SET FOREIGN_KEY_CHECKS=1;' . $crlf; + } + + if (isset($GLOBALS['sql_use_transaction'])) { + $foot .= 'COMMIT;' . $crlf; + } + + // restore connection settings + $charset_of_file = isset($GLOBALS['charset_of_file']) + ? $GLOBALS['charset_of_file'] : ''; + if (! empty($GLOBALS['asfile']) + && isset($mysql_charset_map[$charset_of_file]) + && ! PMA_DRIZZLE + ) { + $foot .= $crlf + . '/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;' + . $crlf + . '/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;' + . $crlf + . '/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;' + . $crlf; + } + + /* Restore timezone */ + if (isset($GLOBALS['sql_utc_time']) && $GLOBALS['sql_utc_time']) { + PMA_DBI_query('SET time_zone = "' . $GLOBALS['old_tz'] . '"'); + } + + return PMA_exportOutputHandler($foot); + } + + /** + * Outputs export header. It is the first method to be called, so all + * the required variables are initialized here. + * + * @return bool Whether it succeeded + */ + public function exportHeader() + { + global $crlf, $cfg; + global $mysql_charset_map; + + if (isset($GLOBALS['sql_compatibility'])) { + $tmp_compat = $GLOBALS['sql_compatibility']; + if ($tmp_compat == 'NONE') { + $tmp_compat = ''; + } + PMA_DBI_try_query('SET SQL_MODE="' . $tmp_compat . '"'); + unset($tmp_compat); + } + $head = $this->_exportComment('phpMyAdmin SQL Dump') + . $this->_exportComment('version ' . PMA_VERSION) + . $this->_exportComment('http://www.phpmyadmin.net') + . $this->_exportComment(); + $host_string = __('Host') . ': ' . $cfg['Server']['host']; + if (! empty($cfg['Server']['port'])) { + $host_string .= ':' . $cfg['Server']['port']; + } + $head .= $this->_exportComment($host_string); + $head .= + $this->_exportComment( + __('Generation Time') . ': ' + . PMA_Util::localisedDate() + ) + . $this->_exportComment( + __('Server version') . ': ' . PMA_MYSQL_STR_VERSION + ) + . $this->_exportComment(__('PHP Version') . ': ' . phpversion()) + . $this->_possibleCRLF(); + + if (isset($GLOBALS['sql_header_comment']) + && ! empty($GLOBALS['sql_header_comment']) + ) { + // '\n' is not a newline (like "\n" would be), it's the characters + // backslash and n, as explained on the export interface + $lines = explode('\n', $GLOBALS['sql_header_comment']); + $head .= $this->_exportComment(); + foreach ($lines as $one_line) { + $head .= $this->_exportComment($one_line); + } + $head .= $this->_exportComment(); + } + + if (isset($GLOBALS['sql_disable_fk'])) { + $head .= 'SET FOREIGN_KEY_CHECKS=0;' . $crlf; + } + + // We want exported AUTO_INCREMENT columns to have still same value, + // do this only for recent MySQL exports + if ((! isset($GLOBALS['sql_compatibility']) + || $GLOBALS['sql_compatibility'] == 'NONE') + && ! PMA_DRIZZLE + ) { + $head .= 'SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";' . $crlf; + } + + if (isset($GLOBALS['sql_use_transaction'])) { + $head .= 'SET AUTOCOMMIT = 0;' . $crlf + . 'START TRANSACTION;' . $crlf; + } + + /* Change timezone if we should export timestamps in UTC */ + if (isset($GLOBALS['sql_utc_time']) && $GLOBALS['sql_utc_time']) { + $head .= 'SET time_zone = "+00:00";' . $crlf; + $GLOBALS['old_tz'] = PMA_DBI_fetch_value('SELECT @@session.time_zone'); + PMA_DBI_query('SET time_zone = "+00:00"'); + } + + $head .= $this->_possibleCRLF(); + + if (! empty($GLOBALS['asfile']) && ! PMA_DRIZZLE) { + // we are saving as file, therefore we provide charset information + // so that a utility like the mysql client can interpret + // the file correctly + if (isset($GLOBALS['charset_of_file']) + && isset($mysql_charset_map[$GLOBALS['charset_of_file']]) + ) { + // we got a charset from the export dialog + $set_names = $mysql_charset_map[$GLOBALS['charset_of_file']]; + } else { + // by default we use the connection charset + $set_names = $mysql_charset_map['utf-8']; + } + $head .= $crlf + . '/*!40101 SET @OLD_CHARACTER_SET_CLIENT=' + . '@@CHARACTER_SET_CLIENT */;' . $crlf + . '/*!40101 SET @OLD_CHARACTER_SET_RESULTS=' + . '@@CHARACTER_SET_RESULTS */;' . $crlf + . '/*!40101 SET @OLD_COLLATION_CONNECTION=' + . '@@COLLATION_CONNECTION */;'. $crlf + . '/*!40101 SET NAMES ' . $set_names . ' */;' . $crlf . $crlf; + } + + return PMA_exportOutputHandler($head); + } + + /** + * Outputs CREATE DATABASE statement + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + global $crlf; + + if (isset($GLOBALS['sql_compatibility'])) { + $compat = $GLOBALS['sql_compatibility']; + } else { + $compat = 'NONE'; + } + if (isset($GLOBALS['sql_drop_database'])) { + if (! PMA_exportOutputHandler( + 'DROP DATABASE ' + . (isset($GLOBALS['sql_backquotes']) + ? PMA_Util::backquoteCompat($db, $compat) : $db) + . ';' . $crlf + )) { + return false; + } + } + if (isset($GLOBALS['sql_create_database'])) { + $create_query = 'CREATE DATABASE IF NOT EXISTS ' + . (isset($GLOBALS['sql_backquotes']) + ? PMA_Util::backquoteCompat($db, $compat) : $db); + $collation = PMA_getDbCollation($db); + if (PMA_DRIZZLE) { + $create_query .= ' COLLATE ' . $collation; + } else { + if (strpos($collation, '_')) { + $create_query .= ' DEFAULT CHARACTER SET ' + . substr($collation, 0, strpos($collation, '_')) + . ' COLLATE ' . $collation; + } else { + $create_query .= ' DEFAULT CHARACTER SET ' . $collation; + } + } + $create_query .= ';' . $crlf; + if (! PMA_exportOutputHandler($create_query)) { + return false; + } + if (isset($GLOBALS['sql_backquotes']) + && ((isset($GLOBALS['sql_compatibility']) + && $GLOBALS['sql_compatibility'] == 'NONE') + || PMA_DRIZZLE) + ) { + $result = PMA_exportOutputHandler( + 'USE ' . PMA_Util::backquoteCompat($db, $compat) + . ';' . $crlf + ); + } else { + $result = PMA_exportOutputHandler('USE ' . $db . ';' . $crlf); + } + return $result; + } else { + return true; + } + } + + /** + * Outputs database header + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBHeader($db) + { + if (isset($GLOBALS['sql_compatibility'])) { + $compat = $GLOBALS['sql_compatibility']; + } else { + $compat = 'NONE'; + } + $head = $this->_exportComment() + . $this->_exportComment( + __('Database') . ': ' + . (isset($GLOBALS['sql_backquotes']) + ? PMA_Util::backquoteCompat($db, $compat) + : '\'' . $db . '\'') + ) + . $this->_exportComment(); + return PMA_exportOutputHandler($head); + } + + /** + * Outputs database footer + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBFooter($db) + { + global $crlf; + + $result = true; + if (isset($GLOBALS['sql_constraints'])) { + $result = PMA_exportOutputHandler($GLOBALS['sql_constraints']); + unset($GLOBALS['sql_constraints']); + } + + if (($GLOBALS['sql_structure_or_data'] == 'structure' + || $GLOBALS['sql_structure_or_data'] == 'structure_and_data') + && isset($GLOBALS['sql_procedure_function']) + ) { + $text = ''; + $delimiter = '$$'; + + if (PMA_MYSQL_INT_VERSION > 50100) { + $event_names = PMA_DBI_fetch_result( + 'SELECT EVENT_NAME FROM information_schema.EVENTS WHERE' + . ' EVENT_SCHEMA= \'' + . PMA_Util::sqlAddSlashes($db, true) + . '\';' + ); + } else { + $event_names = array(); + } + + if ($event_names) { + $text .= $crlf + . 'DELIMITER ' . $delimiter . $crlf; + + $text .= + $this->_exportComment() + . $this->_exportComment(__('Events')) + . $this->_exportComment(); + + foreach ($event_names as $event_name) { + if (! empty($GLOBALS['sql_drop_table'])) { + $text .= 'DROP EVENT ' + . PMA_Util::backquote($event_name) + . $delimiter . $crlf; + } + $text .= PMA_DBI_get_definition($db, 'EVENT', $event_name) + . $delimiter . $crlf . $crlf; + } + + $text .= 'DELIMITER ;' . $crlf; + } + + if (! empty($text)) { + $result = PMA_exportOutputHandler($text); + } + } + return $result; + } + + /** + * 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 + * + * @return string resulting definition + */ + public function getTableDefStandIn($db, $view, $crlf) + { + $create_query = ''; + if (! empty($GLOBALS['sql_drop_table'])) { + $create_query .= 'DROP VIEW IF EXISTS ' + . PMA_Util::backquote($view) + . ';' . $crlf; + } + + $create_query .= 'CREATE TABLE '; + + if (isset($GLOBALS['sql_if_not_exists']) + && $GLOBALS['sql_if_not_exists'] + ) { + $create_query .= 'IF NOT EXISTS '; + } + $create_query .= PMA_Util::backquote($view) . ' (' . $crlf; + $tmp = array(); + $columns = PMA_DBI_get_columns_full($db, $view); + foreach ($columns as $column_name => $definition) { + $tmp[] = PMA_Util::backquote($column_name) . ' ' . + $definition['Type'] . $crlf; + } + $create_query .= implode(',', $tmp) . ');'; + return($create_query); + } + + /** + * Returns $table's CREATE definition + * + * @param string $db the database name + * @param string $table the table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param bool $show_dates whether to include creation/update/check + * dates + * @param bool $add_semicolon whether to add semicolon and end-of-line at + * the end + * @param bool $view whether we're handling a view + * + * @return string resulting schema + */ + public function getTableDef( + $db, + $table, + $crlf, + $error_url, + $show_dates = false, + $add_semicolon = true, + $view = false + ) { + global $sql_drop_table, $sql_backquotes, $sql_constraints, + $sql_constraints_query, $sql_drop_foreign_keys; + + $schema_create = ''; + $auto_increment = ''; + $new_crlf = $crlf; + + if (isset($GLOBALS['sql_compatibility'])) { + $compat = $GLOBALS['sql_compatibility']; + } else { + $compat = 'NONE'; + } + + // need to use PMA_DBI_QUERY_STORE with PMA_DBI_num_rows() in mysqli + $result = PMA_DBI_query( + 'SHOW TABLE STATUS FROM ' . PMA_Util::backquote($db) + . ' LIKE \'' . PMA_Util::sqlAddSlashes($table, true) . '\'', + null, + PMA_DBI_QUERY_STORE + ); + if ($result != false) { + if (PMA_DBI_num_rows($result) > 0) { + $tmpres = PMA_DBI_fetch_assoc($result); + if (PMA_DRIZZLE && $show_dates) { + // Drizzle doesn't give Create_time and Update_time in + // SHOW TABLE STATUS, add it + $sql ="SELECT + TABLE_CREATION_TIME AS Create_time, + TABLE_UPDATE_TIME AS Update_time + FROM data_dictionary.TABLES + WHERE TABLE_SCHEMA = '" + . PMA_Util::sqlAddSlashes($db) . "' + AND TABLE_NAME = '" + . PMA_Util::sqlAddSlashes($table) . "'"; + $tmpres = array_merge(PMA_DBI_fetch_single_row($sql), $tmpres); + } + // Here we optionally add the AUTO_INCREMENT next value, + // but starting with MySQL 5.0.24, the clause is already included + // in SHOW CREATE TABLE so we'll remove it below + // It's required for Drizzle because SHOW CREATE TABLE uses + // the value from table's creation time + if (isset($GLOBALS['sql_auto_increment']) + && ! empty($tmpres['Auto_increment']) + ) { + $auto_increment .= ' AUTO_INCREMENT=' + . $tmpres['Auto_increment'] . ' '; + } + + if ($show_dates + && isset($tmpres['Create_time']) + && ! empty($tmpres['Create_time']) + ) { + $schema_create .= $this->_exportComment( + __('Creation') . ': ' + . PMA_Util::localisedDate( + strtotime($tmpres['Create_time']) + ) + ); + $new_crlf = $this->_exportComment() . $crlf; + } + + if ($show_dates + && isset($tmpres['Update_time']) + && ! empty($tmpres['Update_time']) + ) { + $schema_create .= $this->_exportComment( + __('Last update') . ': ' + . PMA_Util::localisedDate( + strtotime($tmpres['Update_time']) + ) + ); + $new_crlf = $this->_exportComment() . $crlf; + } + + if ($show_dates + && isset($tmpres['Check_time']) + && ! empty($tmpres['Check_time']) + ) { + $schema_create .= $this->_exportComment( + __('Last check') . ': ' + . PMA_Util::localisedDate( + strtotime($tmpres['Check_time']) + ) + ); + $new_crlf = $this->_exportComment() . $crlf; + } + } + PMA_DBI_free_result($result); + } + + $schema_create .= $new_crlf; + + // no need to generate a DROP VIEW here, it was done earlier + if (! empty($sql_drop_table) && ! PMA_Table::isView($db, $table)) { + $schema_create .= 'DROP TABLE IF EXISTS ' + . PMA_Util::backquote($table, $sql_backquotes) . ';' + . $crlf; + } + + // Complete table dump, + // Whether to quote table and column names or not + // Drizzle always quotes names + if (! PMA_DRIZZLE) { + if ($sql_backquotes) { + PMA_DBI_query('SET SQL_QUOTE_SHOW_CREATE = 1'); + } else { + PMA_DBI_query('SET SQL_QUOTE_SHOW_CREATE = 0'); + } + } + + // I don't see the reason why this unbuffered query could cause problems, + // because SHOW CREATE TABLE returns only one row, and we free the + // results below. Nonetheless, we got 2 user reports about this + // (see bug 1562533) so I removed the unbuffered mode. + // $result = PMA_DBI_query('SHOW CREATE TABLE ' . backquote($db) + // . '.' . backquote($table), null, PMA_DBI_QUERY_UNBUFFERED); + // + // Note: SHOW CREATE TABLE, at least in MySQL 5.1.23, does not + // produce a displayable result for the default value of a BIT + // column, nor does the mysqldump command. See MySQL bug 35796 + $result = PMA_DBI_try_query( + 'SHOW CREATE TABLE ' . PMA_Util::backquote($db) . '.' + . PMA_Util::backquote($table) + ); + // an error can happen, for example the table is crashed + $tmp_error = PMA_DBI_getError(); + if ($tmp_error) { + return $this->_exportComment(__('in use') . '(' . $tmp_error . ')'); + } + + if ($result != false && ($row = PMA_DBI_fetch_row($result))) { + $create_query = $row[1]; + unset($row); + + // Convert end of line chars to one that we want (note that MySQL + // doesn't return query it will accept in all cases) + if (strpos($create_query, "(\r\n ")) { + $create_query = str_replace("\r\n", $crlf, $create_query); + } elseif (strpos($create_query, "(\n ")) { + $create_query = str_replace("\n", $crlf, $create_query); + } elseif (strpos($create_query, "(\r ")) { + $create_query = str_replace("\r", $crlf, $create_query); + } + + /* + * Drop database name from VIEW creation. + * + * This is a bit tricky, but we need to issue SHOW CREATE TABLE with + * database name, but we don't want name to show up in CREATE VIEW + * statement. + */ + if ($view) { + $create_query = preg_replace( + '/' . PMA_Util::backquote($db) . '\./', + '', + $create_query + ); + } + + // Should we use IF NOT EXISTS? + // It always must be OFF for MSSQL compatibility mode + if (isset($GLOBALS['sql_if_not_exists']) && $compat != 'MSSQL') { + $create_query = preg_replace( + '/^CREATE TABLE/', + 'CREATE TABLE IF NOT EXISTS', + $create_query + ); + } + + // In MSSQL + // 1. DATE field doesn't exists, we will use DATETIME instead + // 2. UNSIGNED attribute doesn't exist + // 3. No length on INT, TINYINT, SMALLINT, BIGINT and no precision on + // FLOAT fields + // 4. No KEY and INDEX inside CREATE TABLE + // 5. DOUBLE field doesn't exists, we will use FLOAT instead + if ($compat == 'MSSQL') { + // first we need to replace all lines ended with '" DATE ...,\n' + // last preg_replace preserve us from situation with date text + // inside DEFAULT field value + $create_query = preg_replace( + "/\" date DEFAULT NULL(,)?\n/", + '" datetime DEFAULT NULL$1' . "\n", + $create_query + ); + $create_query = preg_replace( + "/\" date NOT NULL(,)?\n/", + '" datetime NOT NULL$1' . "\n", + $create_query + ); + $create_query = preg_replace( + '/" date NOT NULL DEFAULT \'([^\'])/', + '" datetime NOT NULL DEFAULT \'$1', + $create_query + ); + + // next we need to replace all lines ended with ') UNSIGNED ...,' + // last preg_replace preserve us from situation with unsigned text + // inside DEFAULT field value + $create_query = preg_replace( + "/\) unsigned NOT NULL(,)?\n/", + ') NOT NULL$1' . "\n", + $create_query + ); + $create_query = preg_replace( + "/\) unsigned DEFAULT NULL(,)?\n/", + ') DEFAULT NULL$1' . "\n", + $create_query + ); + $create_query = preg_replace( + '/\) unsigned NOT NULL DEFAULT \'([^\'])/', + ') NOT NULL DEFAULT \'$1', + $create_query + ); + + // we need to replace all lines ended with + // '" INT|TINYINT([0-9]{1,}) ...,' last preg_replace preserve us + // from situation with int([0-9]{1,}) text inside DEFAULT field + // value + $create_query = preg_replace( + '/" (int|tinyint|smallint|bigint)\([0-9]+\) DEFAULT NULL(,)?\n/', + '" $1 DEFAULT NULL$2' . "\n", + $create_query + ); + $create_query = preg_replace( + '/" (int|tinyint|smallint|bigint)\([0-9]+\) NOT NULL(,)?\n/', + '" $1 NOT NULL$2' . "\n", + $create_query + ); + $create_query = preg_replace( + '/" (int|tinyint|smallint|bigint)\([0-9]+\) NOT NULL DEFAULT \'([^\'])/', + '" $1 NOT NULL DEFAULT \'$2', + $create_query + ); + + // we need to replace all lines ended with + // '" FLOAT|DOUBLE([0-9,]{1,}) ...,' + // last preg_replace preserve us from situation with + // float([0-9,]{1,}) text inside DEFAULT field value + $create_query = preg_replace( + '/" (float|double)(\([0-9]+,[0-9,]+\))? DEFAULT NULL(,)?\n/', + '" float DEFAULT NULL$3' . "\n", + $create_query + ); + $create_query = preg_replace( + '/" (float|double)(\([0-9,]+,[0-9,]+\))? NOT NULL(,)?\n/', + '" float NOT NULL$3' . "\n", + $create_query + ); + $create_query = preg_replace( + '/" (float|double)(\([0-9,]+,[0-9,]+\))? NOT NULL DEFAULT \'([^\'])/', + '" float NOT NULL DEFAULT \'$3', + $create_query + ); + + // @todo remove indexes from CREATE TABLE + } + + // Drizzle (checked on 2011.03.13) returns ROW_FORMAT surrounded + // with quotes, which is not accepted by parser + if (PMA_DRIZZLE) { + $create_query = preg_replace( + '/ROW_FORMAT=\'(\S+)\'/', + 'ROW_FORMAT=$1', + $create_query + ); + } + + // are there any constraints to cut out? + if (preg_match('@CONSTRAINT|FOREIGN[\s]+KEY@', $create_query)) { + + // Split the query into lines, so we can easily handle it. + // We know lines are separated by $crlf (done few lines above). + $sql_lines = explode($crlf, $create_query); + $sql_count = count($sql_lines); + + // lets find first line with constraints + for ($i = 0; $i < $sql_count; $i++) { + if (preg_match( + '@^[\s]*(CONSTRAINT|FOREIGN[\s]+KEY)@', + $sql_lines[$i] + )) { + break; + } + } + + // If we really found a constraint + if ($i != $sql_count) { + + // remove, from the end of create statement + $sql_lines[$i - 1] = preg_replace( + '@,$@', + '', + $sql_lines[$i - 1] + ); + + // prepare variable for constraints + if (! isset($sql_constraints)) { + if (isset($GLOBALS['no_constraints_comments'])) { + $sql_constraints = ''; + } else { + $sql_constraints = $crlf + . $this->_exportComment() + . $this->_exportComment( + __('Constraints for dumped tables') + ) + . $this->_exportComment(); + } + } + + // comments for current table + if (! isset($GLOBALS['no_constraints_comments'])) { + $sql_constraints .= $crlf + . $this->_exportComment() + . $this->_exportComment( + __('Constraints for table') + . ' ' + . PMA_Util::backquoteCompat($table, $compat) + ) + . $this->_exportComment(); + } + + // let's do the work + $sql_constraints_query .= 'ALTER TABLE ' + . PMA_Util::backquoteCompat($table, $compat) + . $crlf; + $sql_constraints .= 'ALTER TABLE ' + . PMA_Util::backquoteCompat($table, $compat) + . $crlf; + $sql_drop_foreign_keys .= 'ALTER TABLE ' + . PMA_Util::backquoteCompat($db, $compat) . '.' + . PMA_Util::backquoteCompat($table, $compat) + . $crlf; + + $first = true; + for ($j = $i; $j < $sql_count; $j++) { + if (preg_match( + '@CONSTRAINT|FOREIGN[\s]+KEY@', + $sql_lines[$j] + )) { + if (! $first) { + $sql_constraints .= $crlf; + } + if (strpos($sql_lines[$j], 'CONSTRAINT') === false) { + $tmp_str = preg_replace( + '/(FOREIGN[\s]+KEY)/', + 'ADD \1', + $sql_lines[$j] + ); + $sql_constraints_query .= $tmp_str; + $sql_constraints .= $tmp_str; + } else { + $tmp_str = preg_replace( + '/(CONSTRAINT)/', + 'ADD \1', + $sql_lines[$j] + ); + $sql_constraints_query .= $tmp_str; + $sql_constraints .= $tmp_str; + preg_match( + '/(CONSTRAINT)([\s])([\S]*)([\s])/', + $sql_lines[$j], + $matches + ); + if (! $first) { + $sql_drop_foreign_keys .= ', '; + } + $sql_drop_foreign_keys .= 'DROP FOREIGN KEY ' + . $matches[3]; + } + $first = false; + } else { + break; + } + } + $sql_constraints .= ';' . $crlf; + $sql_constraints_query .= ';'; + + $create_query = implode( + $crlf, + array_slice($sql_lines, 0, $i) + ) + . $crlf + . implode( + $crlf, + array_slice($sql_lines, $j, $sql_count - 1) + ); + unset($sql_lines); + } + } + $schema_create .= $create_query; + } + + // remove a possible "AUTO_INCREMENT = value" clause + // that could be there starting with MySQL 5.0.24 + // in Drizzle it's useless as it contains the value given at table + // creation time + $schema_create = preg_replace( + '/AUTO_INCREMENT\s*=\s*([0-9])+/', + '', + $schema_create + ); + + $schema_create .= ($compat != 'MSSQL') ? $auto_increment : ''; + + PMA_DBI_free_result($result); + return $schema_create . ($add_semicolon ? ';' . $crlf : ''); + } // end of the 'getTableDef()' function + + /** + * Returns $table's comments, relations etc. + * + * @param string $db database name + * @param string $table table name + * @param string $crlf end of line sequence + * @param bool $do_relation whether to include relation comments + * @param bool $do_mime whether to include mime comments + * + * @return string resulting comments + */ + private function _getTableComments( + $db, + $table, + $crlf, + $do_relation = false, + $do_mime = false + ) { + global $cfgRelation, $sql_backquotes; + + $schema_create = ''; + + // Check if we can use Relations + if ($do_relation && ! empty($cfgRelation['relation'])) { + // Find which tables are related with the current one and write it in + // an array + $res_rel = PMA_getForeigners($db, $table); + + if ($res_rel && count($res_rel) > 0) { + $have_rel = true; + } else { + $have_rel = false; + } + } else { + $have_rel = false; + } // end if + + if ($do_mime && $cfgRelation['mimework']) { + if (! ($mime_map = PMA_getMIME($db, $table, true))) { + unset($mime_map); + } + } + + if (isset($mime_map) && count($mime_map) > 0) { + $schema_create .= $this->_possibleCRLF() + . $this->_exportComment() + . $this->_exportComment( + __('MIME TYPES FOR TABLE'). ' ' + . PMA_Util::backquote($table, $sql_backquotes) . ':' + ); + @reset($mime_map); + foreach ($mime_map AS $mime_field => $mime) { + $schema_create .= + $this->_exportComment( + ' ' + . PMA_Util::backquote($mime_field, $sql_backquotes) + ) + . $this->_exportComment( + ' ' + . PMA_Util::backquote( + $mime['mimetype'], + $sql_backquotes + ) + ); + } + $schema_create .= $this->_exportComment(); + } + + if ($have_rel) { + $schema_create .= $this->_possibleCRLF() + . $this->_exportComment() + . $this->_exportComment( + __('RELATIONS FOR TABLE') . ' ' + . PMA_Util::backquote($table, $sql_backquotes) + . ':' + ); + foreach ($res_rel AS $rel_field => $rel) { + $schema_create .= + $this->_exportComment( + ' ' + . PMA_Util::backquote($rel_field, $sql_backquotes) + ) + . $this->_exportComment( + ' ' + . PMA_Util::backquote( + $rel['foreign_table'], + $sql_backquotes + ) + . ' -> ' + . PMA_Util::backquote( + $rel['foreign_field'], + $sql_backquotes + ) + ); + } + $schema_create .= $this->_exportComment(); + } + + return $schema_create; + + } // end of the '_getTableComments()' function + + /** + * Outputs table's structure + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $export_mode 'create_table','triggers','create_view', + * 'stand_in' + * @param string $export_type 'server', 'database', 'table' + * @param bool $relation whether to include relation comments + * @param bool $comments whether to include the pmadb-style column + * comments as comments in the structure; this is + * deprecated but the parameter is left here + * because export.php calls exportStructure() + * also for other export types which use this + * parameter + * @param bool $mime whether to include mime comments + * @param bool $dates whether to include creation/update/check dates + * + * @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 + ) { + if (isset($GLOBALS['sql_compatibility'])) { + $compat = $GLOBALS['sql_compatibility']; + } else { + $compat = 'NONE'; + } + + $formatted_table_name = (isset($GLOBALS['sql_backquotes'])) + ? PMA_Util::backquoteCompat($table, $compat) + : '\'' . $table . '\''; + $dump = $this->_possibleCRLF() + . $this->_exportComment(str_repeat('-', 56)) + . $this->_possibleCRLF() + . $this->_exportComment(); + + switch($export_mode) { + case 'create_table': + $dump .= $this->_exportComment( + __('Table structure for table') . ' '. $formatted_table_name + ); + $dump .= $this->_exportComment(); + $dump .= $this->getTableDef($db, $table, $crlf, $error_url, $dates); + $dump .= $this->_getTableComments($db, $table, $crlf, $relation, $mime); + break; + case 'triggers': + $dump = ''; + $triggers = PMA_DBI_get_triggers($db, $table); + if ($triggers) { + $dump .= $this->_possibleCRLF() + . $this->_exportComment() + . $this->_exportComment( + __('Triggers') . ' ' . $formatted_table_name + ) + . $this->_exportComment(); + $delimiter = '//'; + foreach ($triggers as $trigger) { + $dump .= $trigger['drop'] . ';' . $crlf; + $dump .= 'DELIMITER ' . $delimiter . $crlf; + $dump .= $trigger['create']; + $dump .= 'DELIMITER ;' . $crlf; + } + } + break; + case 'create_view': + $dump .= + $this->_exportComment( + __('Structure for view') + . ' ' + . $formatted_table_name + ) + . $this->_exportComment(); + // delete the stand-in table previously created (if any) + if ($export_type != 'table') { + $dump .= 'DROP TABLE IF EXISTS ' + . PMA_Util::backquote($table) . ';' . $crlf; + } + $dump .= $this->getTableDef( + $db, $table, $crlf, $error_url, $dates, true, true + ); + break; + case 'stand_in': + $dump .= + $this->_exportComment( + __('Stand-in structure for view') . ' ' . $formatted_table_name + ) + . $this->_exportComment(); + // export a stand-in definition to resolve view dependencies + $dump .= $this->getTableDefStandIn($db, $table, $crlf); + } // end switch + + // this one is built by getTableDef() to use in table copy/move + // but not in the case of export + unset($GLOBALS['sql_constraints_query']); + + return PMA_exportOutputHandler($dump); + } + + /** + * Outputs the content of a table in SQL format + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $sql_query SQL query for obtaining data + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + global $current_row, $sql_backquotes; + + if (isset($GLOBALS['sql_compatibility'])) { + $compat = $GLOBALS['sql_compatibility']; + } else { + $compat = 'NONE'; + } + + $formatted_table_name = (isset($GLOBALS['sql_backquotes'])) + ? PMA_Util::backquoteCompat($table, $compat) + : '\'' . $table . '\''; + + // Do not export data for a VIEW + // (For a VIEW, this is called only when exporting a single VIEW) + if (PMA_Table::isView($db, $table)) { + $head = $this->_possibleCRLF() + . $this->_exportComment() + . $this->_exportComment('VIEW ' . ' ' . $formatted_table_name) + . $this->_exportComment(__('Data') . ': ' . __('None')) + . $this->_exportComment() + . $this->_possibleCRLF(); + + if (! PMA_exportOutputHandler($head)) { + return false; + } + return true; + } + + // analyze the query to get the true column names, not the aliases + // (this fixes an undefined index, also if Complete inserts + // are used, we did not get the true column name in case of aliases) + $analyzed_sql = PMA_SQP_analyze(PMA_SQP_parse($sql_query)); + + $result = PMA_DBI_try_query($sql_query, null, PMA_DBI_QUERY_UNBUFFERED); + // a possible error: the table has crashed + $tmp_error = PMA_DBI_getError(); + if ($tmp_error) { + return PMA_exportOutputHandler( + $this->_exportComment( + __('Error reading data:') . ' (' . $tmp_error . ')' + ) + ); + } + + if ($result != false) { + $fields_cnt = PMA_DBI_num_fields($result); + + // Get field information + $fields_meta = PMA_DBI_get_fields_meta($result); + $field_flags = array(); + for ($j = 0; $j < $fields_cnt; $j++) { + $field_flags[$j] = PMA_DBI_field_flags($result, $j); + } + + for ($j = 0; $j < $fields_cnt; $j++) { + if (isset($analyzed_sql[0]['select_expr'][$j]['column'])) { + $field_set[$j] = PMA_Util::backquoteCompat( + $analyzed_sql[0]['select_expr'][$j]['column'], + $compat, + $sql_backquotes + ); + } else { + $field_set[$j] = PMA_Util::backquoteCompat( + $fields_meta[$j]->name, + $compat, + $sql_backquotes + ); + } + } + + if (isset($GLOBALS['sql_type']) + && $GLOBALS['sql_type'] == 'UPDATE' + ) { + // update + $schema_insert = 'UPDATE '; + if (isset($GLOBALS['sql_ignore'])) { + $schema_insert .= 'IGNORE '; + } + // avoid EOL blank + $schema_insert .= PMA_Util::backquoteCompat( + $table, + $compat, + $sql_backquotes + ) . ' SET'; + } else { + // insert or replace + if (isset($GLOBALS['sql_type']) + && $GLOBALS['sql_type'] == 'REPLACE' + ) { + $sql_command = 'REPLACE'; + } else { + $sql_command = 'INSERT'; + } + + // delayed inserts? + if (isset($GLOBALS['sql_delayed'])) { + $insert_delayed = ' DELAYED'; + } else { + $insert_delayed = ''; + } + + // insert ignore? + if (isset($GLOBALS['sql_type']) + && $GLOBALS['sql_type'] == 'INSERT' + && isset($GLOBALS['sql_ignore']) + ) { + $insert_delayed .= ' IGNORE'; + } + //truncate table before insert + if (isset($GLOBALS['sql_truncate']) + && $GLOBALS['sql_truncate'] + && $sql_command == 'INSERT' + ) { + $truncate = 'TRUNCATE TABLE ' + . PMA_Util::backquoteCompat( + $table, + $compat, + $sql_backquotes + ) . ";"; + $truncatehead = $this->_possibleCRLF() + . $this->_exportComment() + . $this->_exportComment( + __('Truncate table before insert') . ' ' + . $formatted_table_name + ) + . $this->_exportComment() + . $crlf; + PMA_exportOutputHandler($truncatehead); + PMA_exportOutputHandler($truncate); + } else { + $truncate = ''; + } + + // scheme for inserting fields + if ($GLOBALS['sql_insert_syntax'] == 'complete' + || $GLOBALS['sql_insert_syntax'] == 'both' + ) { + $fields = implode(', ', $field_set); + $schema_insert = $sql_command . $insert_delayed .' INTO ' + . PMA_Util::backquoteCompat( + $table, + $compat, + $sql_backquotes + ) + // avoid EOL blank + . ' (' . $fields . ') VALUES'; + } else { + $schema_insert = $sql_command . $insert_delayed .' INTO ' + . PMA_Util::backquoteCompat( + $table, + $compat, + $sql_backquotes + ) + . ' VALUES'; + } + } + + //\x08\\x09, not required + $search = array("\x00", "\x0a", "\x0d", "\x1a"); + $replace = array('\0', '\n', '\r', '\Z'); + $current_row = 0; + $query_size = 0; + if (($GLOBALS['sql_insert_syntax'] == 'extended' + || $GLOBALS['sql_insert_syntax'] == 'both') + && (! isset($GLOBALS['sql_type']) + || $GLOBALS['sql_type'] != 'UPDATE') + ) { + $separator = ','; + $schema_insert .= $crlf; + } else { + $separator = ';'; + } + + while ($row = PMA_DBI_fetch_row($result)) { + if ($current_row == 0) { + $head = $this->_possibleCRLF() + . $this->_exportComment() + . $this->_exportComment( + __('Dumping data for table') . ' ' + . $formatted_table_name + ) + . $this->_exportComment() + . $crlf; + if (! PMA_exportOutputHandler($head)) { + return false; + } + } + // We need to SET IDENTITY_INSERT ON for MSSQL + if (isset($GLOBALS['sql_compatibility']) + && $GLOBALS['sql_compatibility'] == 'MSSQL' + && $current_row == 0 + ) { + if (! PMA_exportOutputHandler( + 'SET IDENTITY_INSERT ' + . PMA_Util::backquoteCompat( + $table, + $compat + ) + . ' ON ;'.$crlf + )) { + return false; + } + } + $current_row++; + for ($j = 0; $j < $fields_cnt; $j++) { + // NULL + if (! isset($row[$j]) || is_null($row[$j])) { + $values[] = 'NULL'; + } elseif ($fields_meta[$j]->numeric + && $fields_meta[$j]->type != 'timestamp' + && ! $fields_meta[$j]->blob + ) { + // a number + // timestamp is numeric on some MySQL 4.1, BLOBs are + // sometimes numeric + $values[] = $row[$j]; + } elseif (stristr($field_flags[$j], 'BINARY') + && $fields_meta[$j]->blob + && isset($GLOBALS['sql_hex_for_blob']) + ) { + // a true BLOB + // - mysqldump only generates hex data when the --hex-blob + // option is used, for fields having the binary attribute + // no hex is generated + // - a TEXT field returns type blob but a real blob + // returns also the 'binary' flag + + // empty blobs need to be different, but '0' is also empty + // :-( + if (empty($row[$j]) && $row[$j] != '0') { + $values[] = '\'\''; + } else { + $values[] = '0x' . bin2hex($row[$j]); + } + } elseif ($fields_meta[$j]->type == 'bit') { + // detection of 'bit' works only on mysqli extension + $values[] = "b'" . PMA_Util::sqlAddSlashes( + PMA_Util::printableBitValue( + $row[$j], $fields_meta[$j]->length + ) + ) + . "'"; + } else { + // something else -> treat as a string + $values[] = '\'' + . str_replace( + $search, $replace, + PMA_Util::sqlAddSlashes($row[$j]) + ) + . '\''; + } // end if + } // end for + + // should we make update? + if (isset($GLOBALS['sql_type']) + && $GLOBALS['sql_type'] == 'UPDATE' + ) { + + $insert_line = $schema_insert; + for ($i = 0; $i < $fields_cnt; $i++) { + if (0 == $i) { + $insert_line .= ' '; + } + if ($i > 0) { + // avoid EOL blank + $insert_line .= ','; + } + $insert_line .= $field_set[$i] . ' = ' . $values[$i]; + } + + list($tmp_unique_condition, $tmp_clause_is_unique) + = PMA_Util::getUniqueCondition( + $result, + $fields_cnt, + $fields_meta, + $row + ); + $insert_line .= ' WHERE ' . $tmp_unique_condition; + unset($tmp_unique_condition, $tmp_clause_is_unique); + + } else { + + // Extended inserts case + if ($GLOBALS['sql_insert_syntax'] == 'extended' + || $GLOBALS['sql_insert_syntax'] == 'both' + ) { + if ($current_row == 1) { + $insert_line = $schema_insert . '(' + . implode(', ', $values) . ')'; + } else { + $insert_line = '(' . implode(', ', $values) . ')'; + $sql_max_size = $GLOBALS['sql_max_query_size']; + if (isset($sql_max_size) + && $sql_max_size > 0 + && $query_size + strlen($insert_line) > $sql_max_size + ) { + if (! PMA_exportOutputHandler(';' . $crlf)) { + return false; + } + $query_size = 0; + $current_row = 1; + $insert_line = $schema_insert . $insert_line; + } + } + $query_size += strlen($insert_line); + // Other inserts case + } else { + $insert_line = $schema_insert + . '(' + . implode(', ', $values) + . ')'; + } + } + unset($values); + + if (! PMA_exportOutputHandler( + ($current_row == 1 ? '' : $separator . $crlf) + . $insert_line + )) { + return false; + } + + } // end while + + if ($current_row > 0) { + if (! PMA_exportOutputHandler(';' . $crlf)) { + return false; + } + } + + // We need to SET IDENTITY_INSERT OFF for MSSQL + if (isset($GLOBALS['sql_compatibility']) + && $GLOBALS['sql_compatibility'] == 'MSSQL' + && $current_row > 0 + ) { + $outputSucceeded = PMA_exportOutputHandler( + $crlf . 'SET IDENTITY_INSERT ' + . PMA_Util::backquoteCompat($table, $compat) + . ' OFF;' . $crlf + ); + if (! $outputSucceeded) { + return false; + } + } + } // end if ($result != false) + PMA_DBI_free_result($result); + + return true; + } // end of the 'exportData()' function +} diff --git a/hugo/libraries/plugins/export/ExportTexytext.class.php b/hugo/libraries/plugins/export/ExportTexytext.class.php new file mode 100644 index 0000000..3aa609c --- /dev/null +++ b/hugo/libraries/plugins/export/ExportTexytext.class.php @@ -0,0 +1,574 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Export to Texy! text. + * + * @package PhpMyAdmin-Export + * @subpackage Texy!text + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the export interface */ +require_once 'libraries/plugins/ExportPlugin.class.php'; + +/** + * 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() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/RadioPropertyItem.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + include_once "$props/options/items/TextPropertyItem.class.php"; + + $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(); + $exportSpecificOptions->setName("Format Specific Options"); + + // what to dump (structure/data/both) main group + $dumpWhat = new OptionsPropertyMainGroup(); + $dumpWhat->setName("general_opts"); + $dumpWhat->setText(__('Dump table')); + // create primary items and add them to the group + $leaf = new RadioPropertyItem(); + $leaf->setName("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(); + $dataOptions->setName("data"); + $dataOptions->setText(__('Data dump options')); + $dataOptions->setForce('structure'); + // create primary items and add them to the group + $leaf = new BoolPropertyItem(); + $leaf->setName("columns"); + $leaf->setText(__('Put columns names in the first row')); + $dataOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName('null'); + $leaf->setText(__('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; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * 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 + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + return PMA_exportOutputHandler( + '===' . __('Database') . ' ' . $db . "\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 + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + 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 + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + global $what; + + if (! PMA_exportOutputHandler( + '== ' . __('Dumping data for table') . ' ' . $table . "\n\n" + )) { + return false; + } + + // Gets the data from the database + $result = PMA_DBI_query($sql_query, null, PMA_DBI_QUERY_UNBUFFERED); + $fields_cnt = PMA_DBI_num_fields($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++) { + $text_output .= '|' + . htmlspecialchars( + stripslashes(PMA_DBI_field_name($result, $i)) + ); + } // end for + $text_output .= "\n|------\n"; + if (! PMA_exportOutputHandler($text_output)) { + return false; + } + } // end if + + // Format the data + while ($row = PMA_DBI_fetch_row($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( + '|', '|', htmlspecialchars($value) + ); + } // end for + $text_output .= "\n"; + if (! PMA_exportOutputHandler($text_output)) { + return false; + } + } // end while + PMA_DBI_free_result($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 + * + * @return string resulting definition + */ + function getTableDefStandIn($db, $view, $crlf) + { + $text_output = ''; + + /** + * Get the unique keys in the table + */ + $unique_keys = array(); + $keys = PMA_DBI_get_table_indexes($db, $view); + foreach ($keys as $key) { + if ($key['Non_unique'] == 0) { + $unique_keys[] = $key['Column_name']; + } + } + + /** + * Gets fields properties + */ + PMA_DBI_select_db($db); + + /** + * Displays the table structure + */ + + $text_output .= "|------\n" + . '|' . __('Column') + . '|' . __('Type') + . '|' . __('Null') + . '|' . __('Default') + . "\n|------\n"; + + $columns = PMA_DBI_get_columns($db, $view); + foreach ($columns as $column) { + $text_output .= $this->formatOneColumnDefinition($column, $unique_keys); + $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 + * + * @return string resulting schema + */ + function getTableDef( + $db, + $table, + $crlf, + $error_url, + $do_relation, + $do_comments, + $do_mime, + $show_dates = false, + $add_semicolon = true, + $view = false + ) { + global $cfgRelation; + + $text_output = ''; + + /** + * Get the unique keys in the table + */ + $unique_keys = array(); + $keys = PMA_DBI_get_table_indexes($db, $table); + foreach ($keys as $key) { + if ($key['Non_unique'] == 0) { + $unique_keys[] = $key['Column_name']; + } + } + + /** + * Gets fields properties + */ + PMA_DBI_select_db($db); + + // Check if we can use Relations + if ($do_relation && ! empty($cfgRelation['relation'])) { + // Find which tables are related with the current one and write it in + // an array + $res_rel = PMA_getForeigners($db, $table); + + if ($res_rel && count($res_rel) > 0) { + $have_rel = true; + } else { + $have_rel = false; + } + } else { + $have_rel = false; + } // end if + + /** + * Displays the table structure + */ + + $columns_cnt = 4; + if ($do_relation && $have_rel) { + $columns_cnt++; + } + if ($do_comments && $cfgRelation['commwork']) { + $columns_cnt++; + } + if ($do_mime && $cfgRelation['mimework']) { + $columns_cnt++; + } + + $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 = PMA_DBI_get_columns($db, $table); + foreach ($columns as $column) { + $text_output .= $this->formatOneColumnDefinition($column, $unique_keys); + $field_name = $column['Field']; + + if ($do_relation && $have_rel) { + $text_output .= '|' + . (isset($res_rel[$field_name]) + ? htmlspecialchars( + $res_rel[$field_name]['foreign_table'] + . ' (' . $res_rel[$field_name]['foreign_field'] . ')' + ) + : ''); + } + 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 + */ + function getTriggers($db, $table) + { + $text_output .= "|------\n"; + $text_output .= '|' . __('Column'); + $dump = "|------\n"; + $dump .= '|' . __('Name'); + $dump .= '|' . __('Time'); + $dump .= '|' . __('Event'); + $dump .= '|' . __('Definition'); + $dump .= "\n|------\n"; + + $triggers = PMA_DBI_get_triggers($db, $table); + + foreach ($triggers as $trigger) { + $dump .= '|' . $trigger['name']; + $dump .= '|' . $trigger['action_timing']; + $dump .= '|' . $trigger['event_manipulation']; + $dump .= '|' . + str_replace( + '|', + '|', + htmlspecialchars($trigger['definition']) + ); + $dump .= "\n"; + } + + return $dump; + } + + /** + * Outputs table's structure + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $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 + * + * @return bool Whether it succeeded + */ + function exportStructure( + $db, + $table, + $crlf, + $error_url, + $export_mode, + $export_type, + $do_relation = false, + $do_comments = false, + $do_mime = false, + $dates = false + ) { + $dump = ''; + + switch($export_mode) { + case 'create_table': + $dump .= '== ' . __('Table structure for table') . ' ' .$table . "\n\n"; + $dump .= $this->getTableDef( + $db, $table, $crlf, $error_url, $do_relation, $do_comments, + $do_mime, $dates + ); + break; + case 'triggers': + $dump = ''; + $triggers = PMA_DBI_get_triggers($db, $table); + if ($triggers) { + $dump .= '== ' . __('Triggers') . ' ' .$table . "\n\n"; + $dump .= $this->getTriggers($db, $table); + } + break; + case 'create_view': + $dump .= '== ' . __('Structure for view') . ' ' .$table . "\n\n"; + $dump .= $this->getTableDef( + $db, $table, $crlf, $error_url, $do_relation, $do_comments, + $do_mime, $dates, true, true + ); + 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); + } // 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 + * + * @return string Formatted column definition + */ + function formatOneColumnDefinition( + $column, $unique_keys + ) { + $extracted_columnspec + = PMA_Util::extractColumnSpec($column['Type']); + $type = $extracted_columnspec['print_type']; + if (empty($type)) { + $type = ' '; + } + + if (! isset($column['Default'])) { + if ($column['Null'] != 'NO') { + $column['Default'] = 'NULL'; + } + } + + $fmt_pre = ''; + $fmt_post = ''; + if (in_array($column['Field'], $unique_keys)) { + $fmt_pre = '**' . $fmt_pre; + $fmt_post = $fmt_post . '**'; + } + if ($column['Key']=='PRI') { + $fmt_pre = '//' . $fmt_pre; + $fmt_post = $fmt_post . '//'; + } + $definition = '|' + . $fmt_pre . htmlspecialchars($column['Field']) . $fmt_post; + $definition .= '|' . htmlspecialchars($type); + $definition .= '|' + . (($column['Null'] == '' || $column['Null'] == 'NO') + ? __('No') : __('Yes')); + $definition .= '|' + . htmlspecialchars( + isset($column['Default']) ? $column['Default'] : '' + ); + return $definition; + } +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/export/ExportXml.class.php b/hugo/libraries/plugins/export/ExportXml.class.php new file mode 100644 index 0000000..711824c --- /dev/null +++ b/hugo/libraries/plugins/export/ExportXml.class.php @@ -0,0 +1,536 @@ +<?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 + */ +if (! defined('PHPMYADMIN')) { + exit; +} +if (! strlen($GLOBALS['db'])) { /* Can't do server export */ + $GLOBALS['skip_import'] = true; + return; +} + +/* Get the export interface */ +require_once 'libraries/plugins/ExportPlugin.class.php'; + +/** + * 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() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/HiddenPropertyItem.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + + // 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(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create primary items and add them to the group + $leaf = new HiddenPropertyItem(); + $leaf->setName("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->setName("structure"); + $structure->setText(__('Object creation options (all are recommended)')); + // create primary items and add them to the group + if (! PMA_DRIZZLE) { + $leaf = new BoolPropertyItem(); + $leaf->setName("export_functions"); + $leaf->setText(__('Functions')); + $structure->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName("export_procedures"); + $leaf->setText(__('Procedures')); + $structure->addProperty($leaf); + } + $leaf = new BoolPropertyItem(); + $leaf->setName("export_tables"); + $leaf->setText(__('Tables')); + $structure->addProperty($leaf); + if (! PMA_DRIZZLE) { + $leaf = new BoolPropertyItem(); + $leaf->setName("export_triggers"); + $leaf->setText(__('Triggers')); + $structure->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName("export_views"); + $leaf->setText(__('Views')); + $structure->addProperty($leaf); + } + $exportSpecificOptions->addProperty($structure); + + // data main group + $data = new OptionsPropertyMainGroup(); + $data->setName("data"); + $data->setText(__('Data dump options')); + // create primary items and add them to the group + $leaf = new BoolPropertyItem(); + $leaf->setName("export_contents"); + $leaf->setText(__('Export contents')); + $data->addProperty($leaf); + $exportSpecificOptions->addProperty($data); + + // set the options for the export plugin property item + $exportPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $exportPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * 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_of_file']; + } else { + $charset = 'utf-8'; + } + + $head = '<?xml version="1.0" encoding="' . $charset . '"?>' . $crlf + . '<!--' . $crlf + . '- phpMyAdmin XML Dump' . $crlf + . '- version ' . PMA_VERSION . $crlf + . '- http://www.phpmyadmin.net' . $crlf + . '-' . $crlf + . '- ' . __('Host') . ': ' . $cfg['Server']['host']; + if (! empty($cfg['Server']['port'])) { + $head .= ':' . $cfg['Server']['port']; + } + $head .= $crlf + . '- ' . __('Generation Time') . ': ' + . PMA_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="http://www.phpmyadmin.net/some_doc_url/"' + : '') + . '>' . $crlf; + + if ($export_struct) { + if (PMA_DRIZZLE) { + $result = PMA_DBI_fetch_result( + "SELECT + 'utf8' AS DEFAULT_CHARACTER_SET_NAME, + DEFAULT_COLLATION_NAME + FROM data_dictionary.SCHEMAS + WHERE SCHEMA_NAME = '" + . PMA_Util::sqlAddSlashes($db) . "'" + ); + } else { + $result = PMA_DBI_fetch_result( + 'SELECT `DEFAULT_CHARACTER_SET_NAME`, `DEFAULT_COLLATION_NAME`' + . ' FROM `information_schema`.`SCHEMATA` WHERE `SCHEMA_NAME`' + . ' = \''.PMA_Util::sqlAddSlashes($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="' . $db_collation . '" charset="' . $db_charset + . '">' . $crlf; + + if (count($tables) == 0) { + $tables[] = $table; + } + + foreach ($tables as $table) { + // Export tables and views + $result = PMA_DBI_fetch_result( + 'SHOW CREATE TABLE ' . PMA_Util::backquote($db) . '.' + . PMA_Util::backquote($table), + 0 + ); + $tbl = $result[$table][1]; + + $is_view = PMA_Table::isView($db, $table); + + 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="' . $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 = PMA_DBI_get_triggers($db, $table); + if ($triggers) { + foreach ($triggers as $trigger) { + $code = $trigger['create']; + $head .= ' <pma:trigger name="' + . $trigger['name'] . '">' . $crlf; + + // Do some formatting + $code = 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'] + ) { + // Export functions + $functions = PMA_DBI_get_procedures_or_functions($db, 'FUNCTION'); + if ($functions) { + foreach ($functions as $function) { + $head .= ' <pma:function name="' + . $function . '">' . $crlf; + + // Do some formatting + $sql = PMA_DBI_get_definition($db, 'FUNCTION', $function); + $sql = rtrim($sql); + $sql = " " . htmlspecialchars($sql); + $sql = str_replace("\n", "\n ", $sql); + + $head .= $sql . $crlf; + $head .= ' </pma:function>' . $crlf; + } + + unset($function); + unset($functions); + } + } + + if (isset($GLOBALS['xml_export_procedures']) + && $GLOBALS['xml_export_procedures'] + ) { + // Export procedures + $procedures = PMA_DBI_get_procedures_or_functions($db, 'PROCEDURE'); + if ($procedures) { + foreach ($procedures as $procedure) { + $head .= ' <pma:procedure name="' + . $procedure . '">' . $crlf; + + // Do some formatting + $sql = PMA_DBI_get_definition($db, 'PROCEDURE', $procedure); + $sql = rtrim($sql); + $sql = " " . htmlspecialchars($sql); + $sql = str_replace("\n", "\n ", $sql); + + $head .= $sql . $crlf; + $head .= ' </pma:procedure>' . $crlf; + } + + unset($procedure); + unset($procedures); + } + } + + 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 + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + global $crlf; + + if (isset($GLOBALS['xml_export_contents']) + && $GLOBALS['xml_export_contents'] + ) { + $head = ' <!--' . $crlf + . ' - ' . __('Database') . ': ' . '\'' . $db . '\'' . $crlf + . ' -->' . $crlf + . ' <database name="' . htmlspecialchars($db) . '">' . $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 + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + 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 + * + * @return bool Whether it succeeded + */ + public function exportData ($db, $table, $crlf, $error_url, $sql_query) + { + if (isset($GLOBALS['xml_export_contents']) + && $GLOBALS['xml_export_contents'] + ) { + $result = PMA_DBI_query($sql_query, null, PMA_DBI_QUERY_UNBUFFERED); + + $columns_cnt = PMA_DBI_num_fields($result); + $columns = array(); + for ($i = 0; $i < $columns_cnt; $i++) { + $columns[$i] = stripslashes(PMA_DBI_field_name($result, $i)); + } + unset($i); + + $buffer = ' <!-- ' . __('Table') . ' ' . $table . ' -->' . $crlf; + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + + while ($record = PMA_DBI_fetch_row($result)) { + $buffer = ' <table name="' + . htmlspecialchars($table) . '">' . $crlf; + for ($i = 0; $i < $columns_cnt; $i++) { + // 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($columns[$i]) . '">' + . htmlspecialchars((string)$record[$i]) + . '</column>' . $crlf; + } + $buffer .= ' </table>' . $crlf; + + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + } + PMA_DBI_free_result($result); + } + + return true; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the table name + * + * @return void + */ + 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; + } +} +?> diff --git a/hugo/libraries/plugins/export/ExportYaml.class.php b/hugo/libraries/plugins/export/ExportYaml.class.php new file mode 100644 index 0000000..044daee --- /dev/null +++ b/hugo/libraries/plugins/export/ExportYaml.class.php @@ -0,0 +1,214 @@ +<?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 + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the export interface */ +require_once 'libraries/plugins/ExportPlugin.class.php'; + +/** + * 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() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/HiddenPropertyItem.class.php"; + + $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(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create primary items and add them to the group + $leaf = new HiddenPropertyItem(); + $leaf->setName("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; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * 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 + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + 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 + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + 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 + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + $result = PMA_DBI_query($sql_query, null, PMA_DBI_QUERY_UNBUFFERED); + + $columns_cnt = PMA_DBI_num_fields($result); + for ($i = 0; $i < $columns_cnt; $i++) { + $columns[$i] = stripslashes(PMA_DBI_field_name($result, $i)); + } + unset($i); + + $buffer = ''; + $record_cnt = 0; + while ($record = PMA_DBI_fetch_row($result)) { + $record_cnt++; + + // Output table name as comment if this is the first record of the table + if ($record_cnt == 1) { + $buffer = '# ' . $db . '.' . $table . $crlf; + $buffer .= '-' . $crlf; + } else { + $buffer = '-' . $crlf; + } + + for ($i = 0; $i < $columns_cnt; $i++) { + if (! isset($record[$i])) { + continue; + } + + $column = $columns[$i]; + + if (is_null($record[$i])) { + $buffer .= ' ' . $column . ': null' . $crlf; + continue; + } + + if (is_numeric($record[$i])) { + $buffer .= ' ' . $column . ': ' . $record[$i] . $crlf; + continue; + } + + $record[$i] = str_replace( + array('\\', '"', "\n", "\r"), + array('\\\\', '\"', '\n', '\r'), + $record[$i] + ); + $buffer .= ' ' . $column . ': "' . $record[$i] . '"' . $crlf; + } + + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + } + PMA_DBI_free_result($result); + + return true; + } // end getTableYAML +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/export/PMA_ExportPdf.class.php b/hugo/libraries/plugins/export/PMA_ExportPdf.class.php new file mode 100644 index 0000000..1913d5e --- /dev/null +++ b/hugo/libraries/plugins/export/PMA_ExportPdf.class.php @@ -0,0 +1,408 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * TableProperty class + * + * @package PhpMyAdmin-Export + * @subpackage PDF + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the PDF class */ +require_once 'libraries/PDF.class.php'; + +/** + * Adapted from a LGPL script by Philip Clarke + * + * @package PhpMyAdmin-Export + * @subpackage PDF + */ +class PMA_ExportPdf extends PMA_PDF +{ + var $tablewidths; + var $headerset; + + /** + * Add page if needed. + * + * @param float $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. + */ + function checkPageBreak($h = 0, $y = '', $addpage = true) + { + if ($this->empty_string($y)) { + $y = $this->y; + } + $current_page = $this->page; + if ((($y + $h) > $this->PageBreakTrigger) + AND (! $this->InFooter) + AND ($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 + */ + 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( + PMA_PDF_FONT, + '', + ($this->titleFontSize + ? $this->titleFontSize + : $this->FontSizePt) + ); + $this->Cell(0, $this->FontSizePt, $this->titleText, 0, 1, 'C'); + $this->SetFont(PMA_PDF_FONT, '', $this->cellFontSize); + $this->SetY(($this->tMargin) - ($this->FontSizePt / $this->k) * 2.5); + $this->Cell( + 0, + $this->FontSizePt, + __('Database') . ': ' . $this->currentDb . ', ' + . __('Table') . ': ' . $this->currentTable, + 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); + } + + 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 = PMA_DBI_fetch_row($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 + */ + 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 + */ + function setTopMargin($topMargin) + { + $this->tMargin = $topMargin; + } + + 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 = PMA_DBI_query($query, null, PMA_DBI_QUERY_UNBUFFERED); + $this->numFields = PMA_DBI_num_fields($this->results); + $this->fields = PMA_DBI_get_fields_meta($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(); + for ($i = 0; $i < $this->numFields; $i++) { + $stringWidth = $this->getstringwidth($this->fields[$i]->name) + 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] = $this->fields[$i]->name; + $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 = PMA_DBI_fetch_row($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); + + PMA_DBI_free_result($this->results); + + // Pass 2 + + $this->results = PMA_DBI_query($query, null, PMA_DBI_QUERY_UNBUFFERED); + $this->setY($this->tMargin); + $this->AddPage(); + $this->SetFont(PMA_PDF_FONT, '', 9); + $this->morepagestable($this->FontSizePt); + PMA_DBI_free_result($this->results); + + } // end of mysqlReport function + +} // end of PMA_Export_PDF class +?> diff --git a/hugo/libraries/plugins/export/README b/hugo/libraries/plugins/export/README new file mode 100644 index 0000000..68d5a26 --- /dev/null +++ b/hugo/libraries/plugins/export/README @@ -0,0 +1,276 @@ +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; +} + +/* Get the export interface */ +require_once 'libraries/plugins/ExportPlugin.class.php'; + +/** + * Handles the export for the [Name] format + * + * @package PhpMyAdmin-Export + */ +class Export[Name] extends 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() + { + // set properties + $props = 'libraries/properties/'; + // include the main class for properties for the export plug-ins + include_once "$props/plugins/ExportPluginProperties.class.php"; + // include the group properties classes + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + // include the needed single property items + include_once "$props/options/items/RadioPropertyItem.class.php"; + + $exportPluginProperties = new 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 OptionsPropertyRootGroup(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("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 RadioPropertyItem(); + $leaf->setName("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; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * 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 + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + // 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 + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + // 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 + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + // implementation; + return true; + } + + // optional - implement other methods defined in 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 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; + } +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/export/TableProperty.class.php b/hugo/libraries/plugins/export/TableProperty.class.php new file mode 100644 index 0000000..a928a6c --- /dev/null +++ b/hugo/libraries/plugins/export/TableProperty.class.php @@ -0,0 +1,288 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Holds the TableProperty class + * + * @package PhpMyAdmin-Export + * @subpackage CodeGen + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/** + * TableProperty class + * + * @package PhpMyAdmin-Export + * @subpackage CodeGen + */ +class TableProperty +{ + /** + * Name + * + * @var string + */ + public $name; + + /** + * Type + * + * @var string + */ + public $type; + + /** + * Wheter 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 + * + * @return void + */ + 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 + */ + function getPureType() + { + $pos = strpos($this->type, "("); + if ($pos > 0) { + return 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 + */ + 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 + */ + function isUnique() + { + return $this->key == "PRI" || $this->key == "UNI" ? "true" : "false"; + } + + /** + * Gets the .NET primitive type + * + * @return string type + */ + function getDotNetPrimitiveType() + { + if (strpos($this->type, "int") === 0) { + return "int"; + } + if (strpos($this->type, "long") === 0) { + return "long"; + } + if (strpos($this->type, "char") === 0) { + return "string"; + } + if (strpos($this->type, "varchar") === 0) { + return "string"; + } + if (strpos($this->type, "text") === 0) { + return "string"; + } + if (strpos($this->type, "longtext") === 0) { + return "string"; + } + if (strpos($this->type, "tinyint") === 0) { + return "bool"; + } + if (strpos($this->type, "datetime") === 0) { + return "DateTime"; + } + return "unknown"; + } + + /** + * Gets the .NET object type + * + * @return string type + */ + function getDotNetObjectType() + { + if (strpos($this->type, "int") === 0) { + return "Int32"; + } + if (strpos($this->type, "long") === 0) { + return "Long"; + } + if (strpos($this->type, "char") === 0) { + return "String"; + } + if (strpos($this->type, "varchar") === 0) { + return "String"; + } + if (strpos($this->type, "text") === 0) { + return "String"; + } + if (strpos($this->type, "longtext") === 0) { + return "String"; + } + if (strpos($this->type, "tinyint") === 0) { + return "Boolean"; + } + if (strpos($this->type, "datetime") === 0) { + return "DateTime"; + } + return "Unknown"; + } + + /** + * Gets the index name + * + * @return string containing the name of the index + */ + function getIndexName() + { + if (strlen($this->key) > 0) { + return "index=\"" + . htmlspecialchars($this->name, ENT_COMPAT, 'UTF-8') + . "\""; + } + return ""; + } + + /** + * Tells whether the key is primary or not + * + * @return bool true if the key is primary, false otherwise + */ + function isPK() + { + return $this->key=="PRI"; + } + + /** + * Formats a string for C# + * + * @param string $text string to be formatted + * + * @return string formatted text + */ + 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 + */ + 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 + */ + 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; + } +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/import/AbstractImportCsv.class.php b/hugo/libraries/plugins/import/AbstractImportCsv.class.php new file mode 100644 index 0000000..62ca8bb --- /dev/null +++ b/hugo/libraries/plugins/import/AbstractImportCsv.class.php @@ -0,0 +1,91 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Super class of CSV import plugins for phpMyAdmin + * + * @package PhpMyAdmin-Import + * @subpackage CSV + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the import interface */ +require_once 'libraries/plugins/ImportPlugin.class.php'; + +/** + * 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 object OptionsPropertyMainGroup object of the plugin + */ + protected function setProperties() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ImportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + include_once "$props/options/items/TextPropertyItem.class.php"; + + $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(); + $importSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + + // create common items and add them to the group + $leaf = new BoolPropertyItem(); + $leaf->setName("replace"); + $leaf->setText(__('Replace table data with file')); + $generalOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("terminated"); + $leaf->setText(__('Columns separated with:')); + $leaf->setSize(2); + $leaf->setLen(2); + $generalOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("enclosed"); + $leaf->setText(__('Columns enclosed with:')); + $leaf->setSize(2); + $leaf->setLen(2); + $generalOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("escaped"); + $leaf->setText(__('Columns escaped with:')); + $leaf->setSize(2); + $leaf->setLen(2); + $generalOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("new_line"); + $leaf->setText(__('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; + } +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/import/ImportCsv.class.php b/hugo/libraries/plugins/import/ImportCsv.class.php new file mode 100644 index 0000000..d480564 --- /dev/null +++ b/hugo/libraries/plugins/import/ImportCsv.class.php @@ -0,0 +1,588 @@ +<?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 + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the import interface */ +require_once 'libraries/plugins/import/AbstractImportCsv.class.php'; + +/** + * 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(); + $leaf->setName("col_names"); + $leaf->setText( + __( + '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_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(); + $leaf->setName("columns"); + $leaf->setText( + __('Column names: ') + . PMA_Util::showHint($hint) + ); + $generalOptions->addProperty($leaf); + } + + $leaf = new BoolPropertyItem(); + $leaf->setName("ignore"); + $leaf->setText(__('Do not abort on INSERT error')); + $generalOptions->addProperty($leaf); + + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Handles the whole import logic + * + * @return void + */ + public function doImport() + { + 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 (strlen($csv_terminated) != 1) { + $message = PMA_Message::error( + __('Invalid parameter for CSV import: %s') + ); + $message->addParam(__('Columns terminated by'), 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 (strlen($csv_enclosed) > 1) { + $message = PMA_Message::error( + __('Invalid parameter for CSV import: %s') + ); + $message->addParam(__('Columns enclosed by'), false); + $error = true; + $param_error = true; + } elseif (strlen($csv_escaped) != 1) { + $message = PMA_Message::error( + __('Invalid parameter for CSV import: %s') + ); + $message->addParam(__('Columns escaped by'), false); + $error = true; + $param_error = true; + } elseif (strlen($csv_new_line) != 1 && $csv_new_line != 'auto') { + $message = PMA_Message::error( + __('Invalid parameter for CSV import: %s') + ); + $message->addParam(__('Lines terminated by'), false); + $error = true; + $param_error = true; + } + + // If there is an error in the parameters entered, + // indicate that immediately. + if ($param_error) { + PMA_Util::mysqlDie($message->getMessage(), '', '', $err_url); + } + + $buffer = ''; + $required_fields = 0; + + if (! $this->_getAnalyze()) { + if (isset($_POST['csv_replace'])) { + $sql_template = 'REPLACE'; + } else { + $sql_template = 'INSERT'; + if (isset($_POST['csv_ignore'])) { + $sql_template .= ' IGNORE'; + } + } + $sql_template .= ' INTO ' . PMA_Util::backquote($table); + + $tmp_fields = PMA_DBI_get_columns($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_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_Util::backquote($val); + } + $sql_template .= ') '; + } + + $required_fields = count($fields); + + $sql_template .= ' VALUES ('; + } + + // Defaults for parser + $i = 0; + $len = 0; + $line = 1; + $lasti = -1; + $values = array(); + $csv_finish = false; + + $tempRow = array(); + $rows = array(); + $col_names = array(); + $tables = array(); + + $col_count = 0; + $max_cols = 0; + + while (! ($finished && $i >= $len) && ! $error && ! $timeout_passed) { + $data = PMA_importGetNextChunk(); + if ($data === false) { + // subtract data we didn't handle yet and stop processing + $offset -= strlen($buffer); + break; + } elseif ($data === true) { + // Handle rest of buffer + } else { + // Append new data to buffer + $buffer .= $data; + unset($data); + // Do not parse string when we're not at the end + // and don't have new line inside + if (($csv_new_line == 'auto' + && strpos($buffer, "\r") === false + && strpos($buffer, "\n") === false) + || ($csv_new_line != 'auto' + && strpos($buffer, $csv_new_line) === false) + ) { + continue; + } + } + + // Current length of our buffer + $len = strlen($buffer); + // Currently parsed char + $ch = $buffer[$i]; + while ($i < $len) { + // Deadlock protection + if ($lasti == $i && $lastlen == $len) { + $message = PMA_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 = $buffer[$i]; + continue; + } + + // Grab one field + $fallbacki = $i; + if ($ch == $csv_enclosed) { + if ($i == $len - 1) { + break; + } + $need_end = true; + $i++; + $ch = $buffer[$i]; + } 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 = $buffer[$i]; + 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 = $buffer[$i]; + } + + // unquoted NULL string + if (false === $need_end && $value === 'NULL') { + $value = null; + } + + if ($fail) { + $i = $fallbacki; + $ch = $buffer[$i]; + 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 = $buffer[$i]; + break; + } else { + $i++; + $ch = $buffer[$i]; + } + } + // 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 = $buffer[$i]; + break; + } + $i++; + $ch = $buffer[$i]; + } + // 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 ($buffer[$i + 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_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 .= '\'' + . PMA_Util::sqlAddSlashes($val) + . '\''; + } + + $first = false; + } + $sql .= ')'; + + /** + * @todo maybe we could add original line to verbose + * SQL in comment + */ + PMA_importRunQuery($sql, $sql); + } + + $line++; + $csv_finish = false; + $values = array(); + $buffer = substr($buffer, $i + 1); + $len = strlen($buffer); + $i = 0; + $lasti = -1; + $ch = $buffer[0]; + } + } // 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]; + } + + 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 (strlen($db)) { + $result = PMA_DBI_fetch_result('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 */ + if (strlen($db)) { + $db_name = $db; + $options = array('create_db' => false); + } else { + $db_name = 'CSV_DB'; + $options = null; + } + + /* Non-applicable parameters */ + $create = null; + + /* Created and execute necessary SQL statements from data */ + PMA_buildSQL($db_name, $tables, $analyses, $create, $options); + + unset($tables); + unset($analyses); + } + + // Commit any possible data in buffers + PMA_importRunQuery(); + + if (count($values) != 0 && ! $error) { + $message = PMA_Message::error( + __('Invalid format of CSV input on line %d.') + ); + $message->addParam($line); + $error = true; + } + } + + + /* ~~~~~~~~~~~~~~~~~~~~ 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; + } +} diff --git a/hugo/libraries/plugins/import/ImportLdi.class.php b/hugo/libraries/plugins/import/ImportLdi.class.php new file mode 100644 index 0000000..e38def9 --- /dev/null +++ b/hugo/libraries/plugins/import/ImportLdi.class.php @@ -0,0 +1,172 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * CSV import plugin for phpMyAdmin using LOAD DATA + * + * @package PhpMyAdmin-Import + * @subpackage LDI + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the import interface */ +require_once 'libraries/plugins/import/AbstractImportCsv.class.php'; + +// 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 = PMA_DBI_try_query('SHOW VARIABLES LIKE \'local\\_infile\';'); + if ($result != false && PMA_DBI_num_rows($result) > 0) { + $tmp = PMA_DBI_fetch_row($result); + if ($tmp[1] == 'ON') { + $GLOBALS['cfg']['Import']['ldi_local_option'] = true; + } + } + PMA_DBI_free_result($result); + unset($result); + } + + $generalOptions = parent::setProperties(); + $this->properties->setText('CSV using LOAD DATA'); + $this->properties->setExtension('ldi'); + + $leaf = new TextPropertyItem(); + $leaf->setName("columns"); + $leaf->setText(__('Column names: ')); + $generalOptions->addProperty($leaf); + + $leaf = new BoolPropertyItem(); + $leaf->setName("ignore"); + $leaf->setText(__('Do not abort on INSERT error')); + $generalOptions->addProperty($leaf); + + $leaf = new BoolPropertyItem(); + $leaf->setName("local_option"); + $leaf->setText(__('Use LOCAL keyword')); + $generalOptions->addProperty($leaf); + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Handles the whole import logic + * + * @return void + */ + public function doImport() + { + global $finished, $error, $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! + $message = PMA_Message::error( + __('This plugin does not support compressed imports!') + ); + $error = true; + return; + } + + $sql = 'LOAD DATA'; + if (isset($ldi_local_option)) { + $sql .= ' LOCAL'; + } + $sql .= ' INFILE \'' . PMA_Util::sqlAddSlashes($import_file) . '\''; + if (isset($ldi_replace)) { + $sql .= ' REPLACE'; + } elseif (isset($ldi_ignore)) { + $sql .= ' IGNORE'; + } + $sql .= ' INTO TABLE ' . PMA_Util::backquote($table); + + if (strlen($ldi_terminated) > 0) { + $sql .= ' FIELDS TERMINATED BY \'' . $ldi_terminated . '\''; + } + if (strlen($ldi_enclosed) > 0) { + $sql .= ' ENCLOSED BY \'' + . PMA_Util::sqlAddSlashes($ldi_enclosed) . '\''; + } + if (strlen($ldi_escaped) > 0) { + $sql .= ' ESCAPED BY \'' + . PMA_Util::sqlAddSlashes($ldi_escaped) . '\''; + } + if (strlen($ldi_new_line) > 0) { + if ($ldi_new_line == 'auto') { + $ldi_new_line + = (PMA_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_Util::backquote( + trim($tmp[$i], " \t\r\n\0\x0B`") + ); + } // end for + $sql .= ')'; + } + + PMA_importRunQuery($sql, $sql); + PMA_importRunQuery(); + $finished = true; + } +}
\ No newline at end of file diff --git a/hugo/libraries/plugins/import/ImportMediawiki.class.php b/hugo/libraries/plugins/import/ImportMediawiki.class.php new file mode 100644 index 0000000..767c966 --- /dev/null +++ b/hugo/libraries/plugins/import/ImportMediawiki.class.php @@ -0,0 +1,573 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * MediaWiki import plugin for phpMyAdmin + * + * @package PhpMyAdmin-Import + * @subpackage MediaWiki + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the import interface */ +require_once 'libraries/plugins/ImportPlugin.class.php'; + +/** + * 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); + } + + $props = 'libraries/properties/'; + include_once "$props/plugins/ImportPluginProperties.class.php"; + + $importPluginProperties = new ImportPluginProperties(); + $importPluginProperties->setText(__('MediaWiki Table')); + $importPluginProperties->setExtension('txt'); + $importPluginProperties->setMimeType('text/plain'); + $importPluginProperties->setOptions(array()); + $importPluginProperties->setOptionsText(__('Options')); + + $this->properties = $importPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Handles the whole import logic + * + * @return void + */ + public function doImport() + { + 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 + $offset -= 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 ( 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) { + $full_buffer_lines_count -= 1; + $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 beginnning of comment + if (! strcmp(substr($cur_buffer_line, 0, 4), "<!--")) { + $inside_comment = true; + continue; + } elseif ($inside_comment) { + // Check end of comment + if (! strcmp(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; + + // End ignoring structure rows + if ($inside_structure_comment) { + $inside_structure_comment = false; + } + } 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 (substr($cur_buffer_line, 0, 2) === '|-' + || substr($cur_buffer_line, 0, 2) === '|+' + || 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 (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); + + // 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) { + // 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 (strpos($cell_data[0], '[[') === true ) { + if (count($cell_data) == 1) { + $cell = $cell_data[0]; + } else { + $cell = $cell_data[1]; + } + } + + // 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) { + if (strpos($cell, $col_start_char) === 0) { + $cell = trim(substr($cell, 1)); + } + } + + // 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_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> + * + * @global bool $analyze whether to scan for column types + * + * @return void + */ + private function _importDataOneTable ($table) + { + $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); + } + + // Commit any possible data in buffers + PMA_importRunQuery(); + } + + /** + * 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 = PMA_DBI_fetch_result('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) + * ) + * + * @global string $db name of the database to import in + * + * @return void + */ + private function _executeImportTables(&$tables, &$analyses) + { + global $db; + + // $db_name : The currently selected database name, if applicable + // No backquotes + // $options : An associative array of options + if (strlen($db)) { + $db_name = $db; + $options = array('create_db' => false); + } else { + $db_name = 'mediawiki_DB'; + $options = null; + } + + // 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); + + unset($tables); + unset($analyses); + } + + + /** + * Replaces all instances of the '||' separator between delimiters + * in a given string + * + * @param string $start_delim start delimiter + * @param string $end_delim end delimiter + * @param string $replace the string to be replaced with + * @param string $subject the text to be replaced + * + * @return string with replacements + */ + private function _delimiterReplace($start_delim, $end_delim, $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 rembembers 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; + } +}
\ No newline at end of file diff --git a/hugo/libraries/plugins/import/ImportOds.class.php b/hugo/libraries/plugins/import/ImportOds.class.php new file mode 100644 index 0000000..8ec95fe --- /dev/null +++ b/hugo/libraries/plugins/import/ImportOds.class.php @@ -0,0 +1,416 @@ +<?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 + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/** + * We need way to disable external XML entities processing. + */ +if (! function_exists('libxml_disable_entity_loader')) { + $GLOBALS['skip_import'] = true; + return; +} + +/* Get the import interface */ +require_once 'libraries/plugins/ImportPlugin.class.php'; + +/** + * 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() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ImportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + + $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(); + $importSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create primary items and add them to the group + $leaf = new BoolPropertyItem(); + $leaf->setName("col_names"); + $leaf->setText( + __( + '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(); + $leaf->setName("empty_rows"); + $leaf->setText(__('Do not import empty rows')); + $generalOptions->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName("recognize_percentages"); + $leaf->setText( + __( + 'Import percentages as proper decimals <i>(ex. 12.00% to .12)</i>' + ) + ); + $generalOptions->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName("recognize_currency"); + $leaf->setText(__('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; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Handles the whole import logic + * + * @return void + */ + public function doImport() + { + 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 */ + $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(); + $message = PMA_Message::error( + __( + 'The XML file specified was either malformed or incomplete.' + . ' Please correct the issue and try again.' + ) + ); + $error = true; + } else { + $root = $xml->children('office', true)->{'body'}->{'spreadsheet'}; + if (empty($root)) { + $sheets = array(); + $message = PMA_Message::error( + __('Could not parse OpenDocument Spreadsheet!') + ); + $error = true; + } else { + $sheets = $root->children('table', true); + } + } + + $tables = array(); + + $max_cols = 0; + + $row_count = 0; + $col_count = 0; + $col_names = array(); + + $tempRow = array(); + $tempRows = array(); + $rows = array(); + + /* Iterate over tables */ + foreach ($sheets as $sheet) { + $col_names_in_first_row = isset($_REQUEST['ods_col_names']); + + /* Iterate over rows */ + foreach ($sheet as $row) { + $type = $row->getName(); + if (! strcmp('table-row', $type)) { + /* Iterate over columns */ + foreach ($row as $cell) { + $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++) { + if ($_REQUEST['ods_recognize_percentages'] + && ! strcmp( + 'percentage', + $cell_attrs['value-type'] + ) + ) { + $value = (double)$cell_attrs['value']; + } elseif ($_REQUEST['ods_recognize_currency'] + && !strcmp('currency', $cell_attrs['value-type']) + ) { + $value = (double)$cell_attrs['value']; + } else { + /* We need to concatenate all paragraphs */ + $values = array(); + foreach ($text as $paragraph) { + $values[] = (string)$paragraph; + } + $value = implode("\n", $values); + } + if (! $col_names_in_first_row) { + $tempRow[] = $value; + } else { + $col_names[] = $value; + } + + ++$col_count; + } + } else { + /* Number of blank columns repeated */ + if ($col_count < count($row->children('table', true)) - 1 + ) { + $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; + } + } + } + } + + /* 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_tbls = count($tables); + for ($i = 0; $i < $num_tbls; ++$i) { + for ($j = 0; $j < count($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]; + } + } + } + + /* 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 */ + if (strlen($db)) { + $db_name = $db; + $options = array('create_db' => false); + } else { + $db_name = 'ODS_DB'; + $options = null; + } + + /* Non-applicable parameters */ + $create = null; + + /* Created and execute necessary SQL statements from data */ + PMA_buildSQL($db_name, $tables, $analyses, $create, $options); + + unset($tables); + unset($analyses); + + /* Commit any possible data in buffers */ + PMA_importRunQuery(); + } +} diff --git a/hugo/libraries/plugins/import/ImportShp.class.php b/hugo/libraries/plugins/import/ImportShp.class.php new file mode 100644 index 0000000..6fa9ac9 --- /dev/null +++ b/hugo/libraries/plugins/import/ImportShp.class.php @@ -0,0 +1,343 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * ESRI Shape file import plugin for phpMyAdmin + * + * @package PhpMyAdmin-Import + * @subpackage ESRI_Shape + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +// Drizzle does not support GIS data types +if (PMA_DRIZZLE) { + $GLOBALS['skip_import'] = true; + return; +} + +/* Get the import interface*/ +require_once 'libraries/plugins/ImportPlugin.class.php'; +/* Get the ShapeFile class */ +require_once 'libraries/bfShapeFiles/ShapeFile.lib.php'; +require_once 'libraries/plugins/import/ShapeFile.class.php'; +require_once 'libraries/plugins/import/ShapeRecord.class.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() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ImportPluginProperties.class.php"; + + $importPluginProperties = new ImportPluginProperties(); + $importPluginProperties->setText(__('ESRI Shape File')); + $importPluginProperties->setExtension('shp'); + $importPluginProperties->setOptions(array()); + $importPluginProperties->setOptionsText(__('Options')); + + $this->properties = $importPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Handles the whole import logic + * + * @return void + */ + public function doImport() + { + global $db, $error, $finished, $compression, + $import_file, $local_import_file; + + if ((int) ini_get('memory_limit') < 512) { + @ini_set('memory_limit', '512M'); + } + @set_time_limit(300); + + $GLOBALS['finished'] = false; + $buffer = ''; + $eof = false; + + + $shp = new PMA_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, + realpath($GLOBALS['cfg']['TempDir']), + array($dbf_file_name) + ); + if ($extracted) { + $dbf_file_path = realpath($GLOBALS['cfg']['TempDir']) + . (PMA_IS_WINDOWS ? '\\' : '/') . $dbf_file_name; + $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 = substr($import_file, 0, strlen($import_file) - 4) + . '.*'; + $shp->FileName = $file_name; + } + } + + // Load data + $shp->loadFromFile(''); + if ($shp->lastError != "") { + $error = true; + $message = PMA_Message::error( + __('There was an error importing the ESRI shape file: "%s".') + ); + $message->addParam($shp->lastError); + return; + } + + // Delete the .dbf file extracted to 'TempDir' + if ($temp_dbf_file + && isset($dbf_file_path) + && file_exists($dbf_file_path) + ) { + unlink($dbf_file_path); + } + + $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_Message::error( + __( + 'You tried to import an invalid file or the imported file' + . ' contains invalid data' + ) + ); + } else { + $message = PMA_Message::error( + __('MySQL Spatial Extension does not support ESRI type "%s".') + ); + $message->addParam($param); + } + return; + } + + if (isset($gis_type)) { + include_once './libraries/gis/pma_gis_factory.php'; + $gis_obj = PMA_GIS_Factory::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_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 (strlen($db)) { + $result = PMA_DBI_fetch_result('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 (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); + + unset($tables); + unset($analyses); + + $finished = true; + $error = false; + + // Commit any possible data in buffers + PMA_importRunQuery(); + } + + /** + * 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; + } +}
\ No newline at end of file diff --git a/hugo/libraries/plugins/import/ImportSql.class.php b/hugo/libraries/plugins/import/ImportSql.class.php new file mode 100644 index 0000000..146485a --- /dev/null +++ b/hugo/libraries/plugins/import/ImportSql.class.php @@ -0,0 +1,440 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * SQL import plugin for phpMyAdmin + * + * @package PhpMyAdmin-Import + * @subpackage SQL + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the import interface */ +require_once 'libraries/plugins/ImportPlugin.class.php'; + +/** + * 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() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ImportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/SelectPropertyItem.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + + $importPluginProperties = new ImportPluginProperties(); + $importPluginProperties->setText('SQL'); + $importPluginProperties->setExtension('sql'); + $importPluginProperties->setOptionsText(__('Options')); + + $compats = PMA_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(); + $importSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create primary items and add them to the group + $leaf = new SelectPropertyItem(); + $leaf->setName("compatibility"); + $leaf->setText(__('SQL compatibility mode:')); + $leaf->setValues($values); + $leaf->setDoc( + array( + 'manual_MySQL_Database_Administration', + 'Server_SQL_mode', + ) + ); + $generalOptions->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName("no_auto_value_on_zero"); + $leaf->setText( + __('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; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * 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; + + $buffer = ''; + // Defaults for parser + $sql = ''; + $start_pos = 0; + $i = 0; + $len= 0; + $big_value = 2147483647; + // include the space because it's mandatory + $delimiter_keyword = 'DELIMITER '; + $length_of_delimiter_keyword = strlen($delimiter_keyword); + + if (isset($_POST['sql_delimiter'])) { + $sql_delimiter = $_POST['sql_delimiter']; + } else { + $sql_delimiter = ';'; + } + + // Handle compatibility options + $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) { + PMA_DBI_try_query('SET SQL_MODE="' . implode(',', $sql_modes) . '"'); + } + unset($sql_modes); + + /** + * will be set in PMA_importGetNextChunk() + * + * @global boolean $GLOBALS['finished'] + */ + $GLOBALS['finished'] = false; + + while (! ($GLOBALS['finished'] && $i >= $len) + && ! $error + && ! $timeout_passed + ) { + $data = PMA_importGetNextChunk(); + if ($data === false) { + // subtract data we didn't handle yet and stop processing + $offset -= strlen($buffer); + break; + } elseif ($data === true) { + // Handle rest of buffer + } else { + // Append new data to buffer + $buffer .= $data; + // free memory + unset($data); + // Do not parse string when we're not at the end + // and don't have ; inside + if ((strpos($buffer, $sql_delimiter, $i) === false) + && ! $GLOBALS['finished'] + ) { + continue; + } + } + // Current length of our buffer + $len = strlen($buffer); + + // Grab some SQL queries out of it + while ($i < $len) { + $found_delimiter = false; + // Find first interesting character + $old_i = $i; + // this is about 7 times faster that looking for each sequence i + // one by one with strpos() + $match = preg_match( + '/(\'|"|#|-- |\/\*|`|(?i)(?<![A-Z0-9_])' + . $delimiter_keyword . ')/', + $buffer, + $matches, + PREG_OFFSET_CAPTURE, + $i + ); + if ($match) { + // in $matches, index 0 contains the match for the complete + // expression but we don't use it + $first_position = $matches[1][1]; + } else { + $first_position = $big_value; + } + /** + * @todo we should not look for a delimiter that might be + * inside quotes (or even double-quotes) + */ + // the cost of doing this one with preg_match() would be too high + $first_sql_delimiter = strpos($buffer, $sql_delimiter, $i); + if ($first_sql_delimiter === false) { + $first_sql_delimiter = $big_value; + } else { + $found_delimiter = true; + } + + // set $i to the position of the first quote, + // comment.start or delimiter found + $i = min($first_position, $first_sql_delimiter); + + if ($i == $big_value) { + // none of the above was found in the string + + $i = $old_i; + if (! $GLOBALS['finished']) { + break; + } + // at the end there might be some whitespace... + if (trim($buffer) == '') { + $buffer = ''; + $len = 0; + break; + } + // We hit end of query, go there! + $i = strlen($buffer) - 1; + } + + // Grab current character + $ch = $buffer[$i]; + + // Quotes + if (strpos('\'"`', $ch) !== false) { + $quote = $ch; + $endq = false; + while (! $endq) { + // Find next quote + $pos = strpos($buffer, $quote, $i + 1); + /* + * Behave same as MySQL and accept end of query as end + * of backtick. + * I know this is sick, but MySQL behaves like this: + * + * SELECT * FROM `table + * + * is treated like + * + * SELECT * FROM `table` + */ + if ($pos === false && $quote == '`' && $found_delimiter) { + $pos = $first_sql_delimiter - 1; + } elseif ($pos === false) { // No quote? Too short string + // We hit end of string => unclosed quote, + // but we handle it as end of query + if ($GLOBALS['finished']) { + $endq = true; + $i = $len - 1; + } + $found_delimiter = false; + break; + } + // Was not the quote escaped? + $j = $pos - 1; + while ($buffer[$j] == '\\') { + $j--; + } + // Even count means it was not escaped + $endq = (((($pos - 1) - $j) % 2) == 0); + // Skip the string + $i = $pos; + + if ($first_sql_delimiter < $pos) { + $found_delimiter = false; + } + } + if (! $endq) { + break; + } + $i++; + // Aren't we at the end? + if ($GLOBALS['finished'] && $i == $len) { + $i--; + } else { + continue; + } + } + + // Not enough data to decide + if ((($i == ($len - 1) && ($ch == '-' || $ch == '/')) + || ($i == ($len - 2) && (($ch == '-' && $buffer[$i + 1] == '-') + || ($ch == '/' && $buffer[$i + 1] == '*')))) + && ! $GLOBALS['finished'] + ) { + break; + } + + // Comments + if ($ch == '#' + || ($i < ($len - 1) && $ch == '-' && $buffer[$i + 1] == '-' + && (($i < ($len - 2) && $buffer[$i + 2] <= ' ') + || ($i == ($len - 1) && $GLOBALS['finished']))) + || ($i < ($len - 1) && $ch == '/' && $buffer[$i + 1] == '*') + ) { + // Copy current string to SQL + if ($start_pos != $i) { + $sql .= substr($buffer, $start_pos, $i - $start_pos); + } + // Skip the rest + $start_of_comment = $i; + // do not use PHP_EOL here instead of "\n", because the export + // file might have been produced on a different system + $i = strpos($buffer, $ch == '/' ? '*/' : "\n", $i); + // didn't we hit end of string? + if ($i === false) { + if ($GLOBALS['finished']) { + $i = $len - 1; + } else { + break; + } + } + // Skip * + if ($ch == '/') { + $i++; + } + // Skip last char + $i++; + // We need to send the comment part in case we are defining + // a procedure or function and comments in it are valuable + $sql .= substr( + $buffer, + $start_of_comment, + $i - $start_of_comment + ); + // Next query part will start here + $start_pos = $i; + // Aren't we at the end? + if ($i == $len) { + $i--; + } else { + continue; + } + } + // Change delimiter, if redefined, and skip it + // (don't send to server!) + if (($i + $length_of_delimiter_keyword < $len) + && strtoupper( + substr($buffer, $i, $length_of_delimiter_keyword) + ) == $delimiter_keyword + ) { + // look for EOL on the character immediately after 'DELIMITER ' + // (see previous comment about PHP_EOL) + $new_line_pos = strpos( + $buffer, + "\n", + $i + $length_of_delimiter_keyword + ); + // it might happen that there is no EOL + if (false === $new_line_pos) { + $new_line_pos = $len; + } + $sql_delimiter = substr( + $buffer, + $i + $length_of_delimiter_keyword, + $new_line_pos - $i - $length_of_delimiter_keyword + ); + $i = $new_line_pos + 1; + // Next query part will start here + $start_pos = $i; + continue; + } + + // End of SQL + if ($found_delimiter + || ($GLOBALS['finished'] + && ($i == $len - 1)) + ) { + $tmp_sql = $sql; + if ($start_pos < $len) { + $length_to_grab = $i - $start_pos; + + if (! $found_delimiter) { + $length_to_grab++; + } + $tmp_sql .= substr($buffer, $start_pos, $length_to_grab); + unset($length_to_grab); + } + // Do not try to execute empty SQL + if (! preg_match('/^([\s]*;)*$/', trim($tmp_sql))) { + $sql = $tmp_sql; + PMA_importRunQuery( + $sql, + substr($buffer, 0, $i + strlen($sql_delimiter)), + false, + $sql_data + ); + $buffer = substr($buffer, $i + strlen($sql_delimiter)); + // Reset parser: + $len = strlen($buffer); + $sql = ''; + $i = 0; + $start_pos = 0; + // Any chance we will get a complete query? + //if ((strpos($buffer, ';') === false) + //&& ! $GLOBALS['finished']) { + if (strpos($buffer, $sql_delimiter) === false + && ! $GLOBALS['finished'] + ) { + break; + } + } else { + $i++; + $start_pos = $i; + } + } + } // End of parser loop + } // End of import loop + // Commit any possible data in buffers + PMA_importRunQuery('', substr($buffer, 0, $len), false, $sql_data); + PMA_importRunQuery('', '', false, $sql_data); + } +}
\ No newline at end of file diff --git a/hugo/libraries/plugins/import/ImportXml.class.php b/hugo/libraries/plugins/import/ImportXml.class.php new file mode 100644 index 0000000..2a5c24d --- /dev/null +++ b/hugo/libraries/plugins/import/ImportXml.class.php @@ -0,0 +1,380 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * XML import plugin for phpMyAdmin + * + * @todo Improve efficiency + * @package PhpMyAdmin-Import + * @subpackage XML + */ + +if (! defined('PHPMYADMIN')) { + exit; +} + +/** + * We need way to disable external XML entities processing. + */ +if (! function_exists('libxml_disable_entity_loader')) { + $GLOBALS['skip_import'] = true; + return; +} + +/* Get the import interface */ +require_once 'libraries/plugins/ImportPlugin.class.php'; + +/** + * 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() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ImportPluginProperties.class.php"; + + $importPluginProperties = new ImportPluginProperties(); + $importPluginProperties->setText(__('XML')); + $importPluginProperties->setExtension('xml'); + $importPluginProperties->setMimeType('text/xml'); + $importPluginProperties->setOptions(array()); + $importPluginProperties->setOptionsText(__('Options')); + + $this->properties = $importPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Handles the whole import logic + * + * @return void + */ + public function doImport() + { + 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 */ + $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_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_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 + */ + $struct = $xml->children($namespaces['pma']); + + $create = array(); + + foreach ($struct as $tier1 => $val1) { + foreach ($val1 as $tier2 => $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_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 $k1 => $v1) { + $tbl_attr = $v1->attributes(); + + $isInTables = false; + for ($i = 0; $i < count($tables); ++$i) { + if (! strcmp($tables[$i][TBL_NAME], (string)$tbl_attr['name'])) { + $isInTables = true; + break; + } + } + + if ($isInTables == false) { + $tables[] = array((string)$tbl_attr['name']); + } + + foreach ($v1 as $k2 => $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_tbls = count($tables); + for ($i = 0; $i < $num_tbls; ++$i) { + for ($j = 0; $j < count($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($tempRows); + 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); + + unset($analyses); + unset($tables); + unset($create); + + /* Commit any possible data in buffers */ + PMA_importRunQuery(); + } +}
\ No newline at end of file diff --git a/hugo/libraries/plugins/import/README b/hugo/libraries/plugins/import/README new file mode 100644 index 0000000..76d2b07 --- /dev/null +++ b/hugo/libraries/plugins/import/README @@ -0,0 +1,173 @@ +This directory holds import 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] import plugin for phpMyAdmin + * + * @package PhpMyAdmin-Import + * @subpackage [Name] + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the import interface */ +require_once 'libraries/plugins/ImportPlugin.class.php'; + +/** + * Handles the import for the [Name] format + * + * @package PhpMyAdmin-Import + */ +class Import[Name] extends 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() + { + // set properties + $props = 'libraries/properties/'; + // include the main class for properties for the import plug-ins + include_once "$props/plugins/ImportPluginProperties.class.php"; + // include the group properties classes + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + // include the needed single property items + include_once "$props/options/items/RadioPropertyItem.class.php"; + + $importPluginProperties = new 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 OptionsPropertyRootGroup(); + $importSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("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 RadioPropertyItem(); + $leaf->setName("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; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Handles the whole import logic + * + * @return void + */ + public function doImport() + { + // 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 + $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); + } // End of import loop + // Commit any possible data in buffers + PMA_importRunQuery(); + } + + + // 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; + } +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/import/ShapeFile.class.php b/hugo/libraries/plugins/import/ShapeFile.class.php new file mode 100644 index 0000000..121bf12 --- /dev/null +++ b/hugo/libraries/plugins/import/ShapeFile.class.php @@ -0,0 +1,102 @@ +<?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 + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/** + * 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 ImportShp::readFromBuffer() in place + * of fread(). This makes it possible to use compressions. + * + * @package PhpMyAdmin-Import + * @subpackage ESRI_Shape + */ +class PMA_ShapeFile extends ShapeFile +{ + /** + * Returns whether the 'dbase' extension is loaded + * + * @return boolean whether the 'dbase' extension is loaded + */ + 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 overidden + * + * @return void + * @see ShapeFile::loadFromFile() + */ + 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() + */ + 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 void + * @see ShapeFile::_loadRecords() + */ + function _loadRecords() + { + global $eof; + ImportShp::readFromBuffer(32); + while (true) { + $record = new PMA_ShapeRecord(-1); + $record->loadFromFile($this->SHPFile, $this->DBFFile); + if ($record->lastError != "") { + return false; + } + if ($eof) { + break; + } + + $this->records[] = $record; + } + } +} +?> diff --git a/hugo/libraries/plugins/import/ShapeRecord.class.php b/hugo/libraries/plugins/import/ShapeRecord.class.php new file mode 100644 index 0000000..efefd0c --- /dev/null +++ b/hugo/libraries/plugins/import/ShapeRecord.class.php @@ -0,0 +1,161 @@ +<?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 + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/** + * 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 ImportShp::readFromBuffer() in place + * of fread(). This makes it possible to use compressions. + * + * @package PhpMyAdmin-Import + * @subpackage ESRI_Shape + */ +class PMA_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() + */ + 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() + */ + 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 void + * @see ShapeRecord::_loadPoint() + */ + 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() + */ + 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() + */ + 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; + reset($this->SHPData["parts"]); + while (list($partIndex, $partData) = each($this->SHPData["parts"])) { + if (! isset($this->SHPData["parts"][$partIndex]["points"]) + || !is_array($this->SHPData["parts"][$partIndex]["points"]) + ) { + $this->SHPData["parts"][$partIndex] = array(); + $this->SHPData["parts"][$partIndex]["points"] = array(); + } + while (! in_array($readPoints, $this->SHPData["parts"]) + && ($readPoints < ($this->SHPData["numpoints"])) + ) { + $this->SHPData["parts"][$partIndex]["points"][] + = $this->_loadPoint(); + $readPoints++; + } + } + } +} +?> diff --git a/hugo/libraries/plugins/import/upload/UploadApc.class.php b/hugo/libraries/plugins/import/upload/UploadApc.class.php new file mode 100644 index 0000000..881832f --- /dev/null +++ b/hugo/libraries/plugins/import/upload/UploadApc.class.php @@ -0,0 +1,84 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Provides upload functionalities for the import plugins + * + * @package PhpMyAdmin + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the transformations interface */ +require_once 'libraries/plugins/UploadInterface.int.php'; + +/** + * 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; + } +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/import/upload/UploadNoplugin.class.php b/hugo/libraries/plugins/import/upload/UploadNoplugin.class.php new file mode 100644 index 0000000..90148de --- /dev/null +++ b/hugo/libraries/plugins/import/upload/UploadNoplugin.class.php @@ -0,0 +1,64 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Provides upload functionalities for the import plugins + * + * @package PhpMyAdmin + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the transformations interface */ +require_once 'libraries/plugins/UploadInterface.int.php'; + +/** + * 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; + } +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/import/upload/UploadProgress.class.php b/hugo/libraries/plugins/import/upload/UploadProgress.class.php new file mode 100644 index 0000000..1a50776 --- /dev/null +++ b/hugo/libraries/plugins/import/upload/UploadProgress.class.php @@ -0,0 +1,94 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Provides upload functionalities for the import plugins + * + * @package PhpMyAdmin + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the transformations interface */ +require_once 'libraries/plugins/UploadInterface.int.php'; + +/** + * 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; + } +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/import/upload/UploadSession.class.php b/hugo/libraries/plugins/import/upload/UploadSession.class.php new file mode 100644 index 0000000..3640413 --- /dev/null +++ b/hugo/libraries/plugins/import/upload/UploadSession.class.php @@ -0,0 +1,96 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Provides upload functionalities for the import plugins + * + * @package PhpMyAdmin + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the transformations interface */ +require_once 'libraries/plugins/UploadInterface.int.php'; + +/** + * 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; + } +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/transformations/Application_Octetstream_Download.class.php b/hugo/libraries/plugins/transformations/Application_Octetstream_Download.class.php new file mode 100644 index 0000000..46bda70 --- /dev/null +++ b/hugo/libraries/plugins/transformations/Application_Octetstream_Download.class.php @@ -0,0 +1,64 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Application OctetStream Download Transformations plugin for phpMyAdmin + * + * @package PhpMyAdmin-Transformations + * @subpackage Download + */ +if (! defined('PHPMYADMIN')) { + exit; +} +/* Get the download transformations interface */ +require_once 'abstract/DownloadTransformationsPlugin.class.php'; + +/** + * Handles the download transformation for application octetstream + * + * @package PhpMyAdmin-Transformations + * @subpackage Download + */ +class Application_Octetstream_Download extends DownloadTransformationsPlugin +{ + /** + * Gets the plugin`s MIME type + * + * @return string + */ + public static function getMIMEType() + { + return "Application"; + } + + /** + * Gets the plugin`s MIME subtype + * + * @return string + */ + public static function getMIMESubtype() + { + return "OctetStream"; + } +} + +/** + * Function to call Application_Octetstream_Download::getInfo(); + * + * Temporary workaround for bug #3783 : + * Calling a method from a variable class is not possible before PHP 5.3. + * + * This function is called by PMA_getTransformationDescription() + * in libraries/transformations.lib.php using a variable to construct it's name. + * This function then calls the static method. + * + * Don't use this function unless you are affected by the same issue. + * Call the static method directly instead. + * + * @deprecated + * @return string Info about transformation class + */ +function Application_Octetstream_Download_getInfo() +{ + return Application_Octetstream_Download::getInfo(); +} +?> diff --git a/hugo/libraries/plugins/transformations/Application_Octetstream_Hex.class.php b/hugo/libraries/plugins/transformations/Application_Octetstream_Hex.class.php new file mode 100644 index 0000000..f876abb --- /dev/null +++ b/hugo/libraries/plugins/transformations/Application_Octetstream_Hex.class.php @@ -0,0 +1,65 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Application OctetStream Hex Transformations plugin for phpMyAdmin + * + * @package PhpMyAdmin-Transformations + * @subpackage Hex + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the hex transformations interface */ +require_once 'abstract/HexTransformationsPlugin.class.php'; + +/** + * Handles the hex transformation for application octetstream + * + * @package PhpMyAdmin-Transformations + * @subpackage Hex + */ +class Application_Octetstream_Hex extends HexTransformationsPlugin +{ + /** + * Gets the plugin`s MIME type + * + * @return string + */ + public static function getMIMEType() + { + return "Application"; + } + + /** + * Gets the plugin`s MIME subtype + * + * @return string + */ + public static function getMIMESubtype() + { + return "OctetStream"; + } +} + +/** + * Function to call Application_Octetstream_Hex::getInfo(); + * + * Temporary workaround for bug #3783 : + * Calling a method from a variable class is not possible before PHP 5.3. + * + * This function is called by PMA_getTransformationDescription() + * in libraries/transformations.lib.php using a variable to construct it's name. + * This function then calls the static method. + * + * Don't use this function unless you are affected by the same issue. + * Call the static method directly instead. + * + * @deprecated + * @return string Info about transformation class + */ +function Application_Octetstream_Hex_getInfo() +{ + return Application_Octetstream_Hex::getInfo(); +} +?> diff --git a/hugo/libraries/plugins/transformations/Image_JPEG_Inline.class.php b/hugo/libraries/plugins/transformations/Image_JPEG_Inline.class.php new file mode 100644 index 0000000..934df75 --- /dev/null +++ b/hugo/libraries/plugins/transformations/Image_JPEG_Inline.class.php @@ -0,0 +1,65 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Image JPEG Inline Transformations plugin for phpMyAdmin + * + * @package PhpMyAdmin-Transformations + * @subpackage Inline + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the inline transformations interface */ +require_once 'abstract/InlineTransformationsPlugin.class.php'; + +/** + * Handles the inline transformation for image jpeg + * + * @package PhpMyAdmin-Transformations + * @subpackage Inline + */ +class Image_JPEG_Inline extends InlineTransformationsPlugin +{ + /** + * Gets the plugin`s MIME type + * + * @return string + */ + public static function getMIMEType() + { + return "Image"; + } + + /** + * Gets the plugin`s MIME subtype + * + * @return string + */ + public static function getMIMESubtype() + { + return "JPEG"; + } +} + +/** + * Function to call Image_JPEG_Inline::getInfo(); + * + * Temporary workaround for bug #3783 : + * Calling a method from a variable class is not possible before PHP 5.3. + * + * This function is called by PMA_getTransformationDescription() + * in libraries/transformations.lib.php using a variable to construct it's name. + * This function then calls the static method. + * + * Don't use this function unless you are affected by the same issue. + * Call the static method directly instead. + * + * @deprecated + * @return string Info about transformation class + */ +function Image_JPEG_Inline_getInfo() +{ + return Image_JPEG_Inline::getInfo(); +} +?> diff --git a/hugo/libraries/plugins/transformations/Image_JPEG_Link.class.php b/hugo/libraries/plugins/transformations/Image_JPEG_Link.class.php new file mode 100644 index 0000000..fc04040 --- /dev/null +++ b/hugo/libraries/plugins/transformations/Image_JPEG_Link.class.php @@ -0,0 +1,65 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Image JPEG Link Transformations plugin for phpMyAdmin + * + * @package PhpMyAdmin-Transformations + * @subpackage Link + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the link transformations interface */ +require_once 'abstract/ImageLinkTransformationsPlugin.class.php'; + +/** + * Handles the link transformation for image jpeg + * + * @package PhpMyAdmin-Transformations + * @subpackage Link + */ +class Image_JPEG_Link extends ImageLinkTransformationsPlugin +{ + /** + * Gets the plugin`s MIME type + * + * @return string + */ + public static function getMIMEType() + { + return "Image"; + } + + /** + * Gets the plugin`s MIME subtype + * + * @return string + */ + public static function getMIMESubtype() + { + return "JPEG"; + } +} + +/** + * Function to call Image_JPEG_Link::getInfo(); + * + * Temporary workaround for bug #3783 : + * Calling a method from a variable class is not possible before PHP 5.3. + * + * This function is called by PMA_getTransformationDescription() + * in libraries/transformations.lib.php using a variable to construct it's name. + * This function then calls the static method. + * + * Don't use this function unless you are affected by the same issue. + * Call the static method directly instead. + * + * @deprecated + * @return string Info about transformation class + */ +function Image_JPEG_Link_getInfo() +{ + return Image_JPEG_Link::getInfo(); +} +?> diff --git a/hugo/libraries/plugins/transformations/Image_PNG_Inline.class.php b/hugo/libraries/plugins/transformations/Image_PNG_Inline.class.php new file mode 100644 index 0000000..e879c23 --- /dev/null +++ b/hugo/libraries/plugins/transformations/Image_PNG_Inline.class.php @@ -0,0 +1,65 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Image PNG Inline Transformations plugin for phpMyAdmin + * + * @package PhpMyAdmin-Transformations + * @subpackage Inline + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the inline transformations interface */ +require_once 'abstract/InlineTransformationsPlugin.class.php'; + +/** + * Handles the inline transformation for image png + * + * @package PhpMyAdmin-Transformations + * @subpackage Inline + */ +class Image_PNG_Inline extends InlineTransformationsPlugin +{ + /** + * Gets the plugin`s MIME type + * + * @return string + */ + public static function getMIMEType() + { + return "Image"; + } + + /** + * Gets the plugin`s MIME subtype + * + * @return string + */ + public static function getMIMESubtype() + { + return "PNG"; + } +} + +/** + * Function to call Image_PNG_Inline::getInfo(); + * + * Temporary workaround for bug #3783 : + * Calling a method from a variable class is not possible before PHP 5.3. + * + * This function is called by PMA_getTransformationDescription() + * in libraries/transformations.lib.php using a variable to construct it's name. + * This function then calls the static method. + * + * Don't use this function unless you are affected by the same issue. + * Call the static method directly instead. + * + * @deprecated + * @return string Info about transformation class + */ +function Image_PNG_Inline_getInfo() +{ + return Image_PNG_Inline::getInfo(); +} +?> diff --git a/hugo/libraries/plugins/transformations/README b/hugo/libraries/plugins/transformations/README new file mode 100644 index 0000000..7d7a125 --- /dev/null +++ b/hugo/libraries/plugins/transformations/README @@ -0,0 +1,4 @@ +TRANSFORMATION USAGE (Garvin Hicking, <me@supergarv.de>) +==================== + +See the documentation for complete instructions on how to use transformation plugins. diff --git a/hugo/libraries/plugins/transformations/TEMPLATE b/hugo/libraries/plugins/transformations/TEMPLATE new file mode 100644 index 0000000..b0ce2f0 --- /dev/null +++ b/hugo/libraries/plugins/transformations/TEMPLATE @@ -0,0 +1,68 @@ +<?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] + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the [TransformationName] transformations interface */ +require_once 'abstract/[TransformationName]TransformationsPlugin.class.php'; + +/** + * 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]"; + } +} + +/** + * Function to call [MIMEType]_[MIMESubtype]_[TransformationName]::getInfo(); + * + * Temporary workaround for bug #3783 : + * Calling a method from a variable class is not possible before PHP 5.3. + * + * This function is called by PMA_getTransformationDescription() + * in libraries/transformations.lib.php using a variable to construct it's name. + * This function then calls the static method. + * + * Don't use this function unless you are affected by the same issue. + * Call the static method directly instead. + * + * @deprecated + * @return string Info about transformation class + */ + +function [MIMEType]_[MIMESubtype]_[TransformationName]_getInfo() +{ + return [MIMEType]_[MIMESubtype]_[TransformationName]::getInfo(); +} +?> diff --git a/hugo/libraries/plugins/transformations/TEMPLATE_ABSTRACT b/hugo/libraries/plugins/transformations/TEMPLATE_ABSTRACT new file mode 100644 index 0000000..5cc1d26 --- /dev/null +++ b/hugo/libraries/plugins/transformations/TEMPLATE_ABSTRACT @@ -0,0 +1,89 @@ +<?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] + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the transformations interface */ +require_once 'libraries/plugins/TransformationsPlugin.class.php'; + +/** + * Provides common methods for all of the [TransformationName] transformations plugins. + * + * @package PhpMyAdmin + */ +abstract class [TransformationName]TransformationsPlugin + extends TransformationsPlugin +{ + /** + * 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 http://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; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the TransformationName of the specific plugin + * + * @return string + */ + public static function getName() + { + return "[TransformationName]"; + } +} +?> diff --git a/hugo/libraries/plugins/transformations/Text_Plain_Append.class.php b/hugo/libraries/plugins/transformations/Text_Plain_Append.class.php new file mode 100644 index 0000000..8a102cb --- /dev/null +++ b/hugo/libraries/plugins/transformations/Text_Plain_Append.class.php @@ -0,0 +1,66 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Text Plain Append Transformations plugin for phpMyAdmin + * + * @package PhpMyAdmin-Transformations + * @subpackage Append + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the append transformations interface */ +require_once 'abstract/AppendTransformationsPlugin.class.php'; + +/** + * Handles the append transformation for text plain. + * Has one option: the text to be appended (default '') + * + * @package PhpMyAdmin-Transformations + * @subpackage Append + */ +class Text_Plain_Append extends AppendTransformationsPlugin +{ + /** + * 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"; + } +} + +/** + * Function to call Text_Plain_Append::getInfo(); + * + * Temporary workaround for bug #3783 : + * Calling a method from a variable class is not possible before PHP 5.3. + * + * This function is called by PMA_getTransformationDescription() + * in libraries/transformations.lib.php using a variable to construct it's name. + * This function then calls the static method. + * + * Don't use this function unless you are affected by the same issue. + * Call the static method directly instead. + * + * @deprecated + * @return string Info about transformation class + */ +function Text_Plain_Append_getInfo() +{ + return Text_Plain_Append::getInfo(); +} +?> diff --git a/hugo/libraries/plugins/transformations/Text_Plain_Dateformat.class.php b/hugo/libraries/plugins/transformations/Text_Plain_Dateformat.class.php new file mode 100644 index 0000000..ed8c9e5 --- /dev/null +++ b/hugo/libraries/plugins/transformations/Text_Plain_Dateformat.class.php @@ -0,0 +1,65 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Text Plain Date Format Transformations plugin for phpMyAdmin + * + * @package PhpMyAdmin-Transformations + * @subpackage DateFormat + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the date format transformations interface */ +require_once 'abstract/DateFormatTransformationsPlugin.class.php'; + +/** + * Handles the date format transformation for text plain + * + * @package PhpMyAdmin-Transformations + * @subpackage DateFormat + */ +class Text_Plain_Dateformat extends DateFormatTransformationsPlugin +{ + /** + * 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"; + } +} + +/** + * Function to call Text_Plain_Dateformat::getInfo(); + * + * Temporary workaround for bug #3783 : + * Calling a method from a variable class is not possible before PHP 5.3. + * + * This function is called by PMA_getTransformationDescription() + * in libraries/transformations.lib.php using a variable to construct it's name. + * This function then calls the static method. + * + * Don't use this function unless you are affected by the same issue. + * Call the static method directly instead. + * + * @deprecated + * @return string Info about transformation class + */ +function Text_Plain_Dateformat_getInfo() +{ + return Text_Plain_Dateformat::getInfo(); +} +?> diff --git a/hugo/libraries/plugins/transformations/Text_Plain_External.class.php b/hugo/libraries/plugins/transformations/Text_Plain_External.class.php new file mode 100644 index 0000000..1aa321a --- /dev/null +++ b/hugo/libraries/plugins/transformations/Text_Plain_External.class.php @@ -0,0 +1,65 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Text Plain External Transformations plugin for phpMyAdmin + * + * @package PhpMyAdmin-Transformations + * @subpackage External + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the external transformations interface */ +require_once 'abstract/ExternalTransformationsPlugin.class.php'; + +/** + * Handles the external transformation for text plain + * + * @package PhpMyAdmin-Transformations + * @subpackage External + */ +class Text_Plain_External extends ExternalTransformationsPlugin +{ + /** + * 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"; + } +} + +/** + * Function to call Text_Plain_External::getInfo(); + * + * Temporary workaround for bug #3783 : + * Calling a method from a variable class is not possible before PHP 5.3. + * + * This function is called by PMA_getTransformationDescription() + * in libraries/transformations.lib.php using a variable to construct it's name. + * This function then calls the static method. + * + * Don't use this function unless you are affected by the same issue. + * Call the static method directly instead. + * + * @deprecated + * @return string Info about transformation class + */ +function Text_Plain_External_getInfo() +{ + return Text_Plain_External::getInfo(); +} +?> diff --git a/hugo/libraries/plugins/transformations/Text_Plain_Formatted.class.php b/hugo/libraries/plugins/transformations/Text_Plain_Formatted.class.php new file mode 100644 index 0000000..5c6b683 --- /dev/null +++ b/hugo/libraries/plugins/transformations/Text_Plain_Formatted.class.php @@ -0,0 +1,65 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Text Plain Formatted Transformations plugin for phpMyAdmin + * + * @package PhpMyAdmin-Transformations + * @subpackage Formatted + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the formatted transformations interface */ +require_once 'abstract/FormattedTransformationsPlugin.class.php'; + +/** + * Handles the formatted transformation for text plain + * + * @package PhpMyAdmin-Transformations + * @subpackage Formatted + */ +class Text_Plain_Formatted extends FormattedTransformationsPlugin +{ + /** + * 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"; + } +} + +/** + * Function to call Text_Plain_Formatted::getInfo(); + * + * Temporary workaround for bug #3783 : + * Calling a method from a variable class is not possible before PHP 5.3. + * + * This function is called by PMA_getTransformationDescription() + * in libraries/transformations.lib.php using a variable to construct it's name. + * This function then calls the static method. + * + * Don't use this function unless you are affected by the same issue. + * Call the static method directly instead. + * + * @deprecated + * @return string Info about transformation class + */ +function Text_Plain_Formatted_getInfo() +{ + return Text_Plain_Formatted::getInfo(); +} +?> diff --git a/hugo/libraries/plugins/transformations/Text_Plain_Imagelink.class.php b/hugo/libraries/plugins/transformations/Text_Plain_Imagelink.class.php new file mode 100644 index 0000000..4cb1800 --- /dev/null +++ b/hugo/libraries/plugins/transformations/Text_Plain_Imagelink.class.php @@ -0,0 +1,65 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Text Plain Image Link Transformations plugin for phpMyAdmin + * + * @package PhpMyAdmin-Transformations + * @subpackage ImageLink + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the image link transformations interface */ +require_once 'abstract/TextImageLinkTransformationsPlugin.class.php'; + +/** + * Handles the image link transformation for text plain + * + * @package PhpMyAdmin-Transformations + * @subpackage ImageLink + */ +class Text_Plain_Imagelink extends TextImageLinkTransformationsPlugin +{ + /** + * 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"; + } +} + +/** + * Function to call Text_Plain_Imagelink::getInfo(); + * + * Temporary workaround for bug #3783 : + * Calling a method from a variable class is not possible before PHP 5.3. + * + * This function is called by PMA_getTransformationDescription() + * in libraries/transformations.lib.php using a variable to construct it's name. + * This function then calls the static method. + * + * Don't use this function unless you are affected by the same issue. + * Call the static method directly instead. + * + * @deprecated + * @return string Info about transformation class + */ +function Text_Plain_Imagelink_getInfo() +{ + return Text_Plain_Imagelink::getInfo(); +} +?> diff --git a/hugo/libraries/plugins/transformations/Text_Plain_Link.class.php b/hugo/libraries/plugins/transformations/Text_Plain_Link.class.php new file mode 100644 index 0000000..1e64203 --- /dev/null +++ b/hugo/libraries/plugins/transformations/Text_Plain_Link.class.php @@ -0,0 +1,65 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Text Plain Link Transformations plugin for phpMyAdmin + * + * @package PhpMyAdmin-Transformations + * @subpackage Link + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the link transformations interface */ +require_once 'abstract/TextLinkTransformationsPlugin.class.php'; + +/** + * 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"; + } +} + +/** + * Function to call Text_Plain_Link::getInfo(); + * + * Temporary workaround for bug #3783 : + * Calling a method from a variable class is not possible before PHP 5.3. + * + * This function is called by PMA_getTransformationDescription() + * in libraries/transformations.lib.php using a variable to construct it's name. + * This function then calls the static method. + * + * Don't use this function unless you are affected by the same issue. + * Call the static method directly instead. + * + * @deprecated + * @return string Info about transformation class + */ +function Text_Plain_Link_getInfo() +{ + return Text_Plain_Link::getInfo(); +} +?> diff --git a/hugo/libraries/plugins/transformations/Text_Plain_Longtoipv4.class.php b/hugo/libraries/plugins/transformations/Text_Plain_Longtoipv4.class.php new file mode 100644 index 0000000..44eea50 --- /dev/null +++ b/hugo/libraries/plugins/transformations/Text_Plain_Longtoipv4.class.php @@ -0,0 +1,65 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Text Plain Long To IPv4 Transformations plugin for phpMyAdmin + * + * @package PhpMyAdmin-Transformations + * @subpackage LongToIPv4 + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the long to ipv4 transformations interface */ +require_once 'abstract/LongToIPv4TransformationsPlugin.class.php'; + +/** + * 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"; + } +} + +/** + * Function to call Text_Plain_Longtoipv4::getInfo(); + * + * Temporary workaround for bug #3783 : + * Calling a method from a variable class is not possible before PHP 5.3. + * + * This function is called by PMA_getTransformationDescription() + * in libraries/transformations.lib.php using a variable to construct it's name. + * This function then calls the static method. + * + * Don't use this function unless you are affected by the same issue. + * Call the static method directly instead. + * + * @deprecated + * @return string Info about transformation class + */ +function Text_Plain_Longtoipv4_getInfo() +{ + return Text_Plain_Longtoipv4::getInfo(); +} +?> diff --git a/hugo/libraries/plugins/transformations/Text_Plain_Sql.class.php b/hugo/libraries/plugins/transformations/Text_Plain_Sql.class.php new file mode 100644 index 0000000..cc92491 --- /dev/null +++ b/hugo/libraries/plugins/transformations/Text_Plain_Sql.class.php @@ -0,0 +1,65 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Text Plain SQL Transformations plugin for phpMyAdmin + * + * @package PhpMyAdmin-Transformations + * @subpackage SQL + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the sql transformations interface */ +require_once 'abstract/SQLTransformationsPlugin.class.php'; + +/** + * Handles the sql transformation for text plain + * + * @package PhpMyAdmin-Transformations + * @subpackage SQL + */ +class Text_Plain_Sql extends SQLTransformationsPlugin +{ + /** + * 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"; + } +} + +/** + * Function to call Text_Plain_Sql::getInfo(); + * + * Temporary workaround for bug #3783 : + * Calling a method from a variable class is not possible before PHP 5.3. + * + * This function is called by PMA_getTransformationDescription() + * in libraries/transformations.lib.php using a variable to construct it's name. + * This function then calls the static method. + * + * Don't use this function unless you are affected by the same issue. + * Call the static method directly instead. + * + * @deprecated + * @return string Info about transformation class + */ +function Text_Plain_Sql_getInfo() +{ + return Text_Plain_Sql::getInfo(); +} +?> diff --git a/hugo/libraries/plugins/transformations/Text_Plain_Substring.class.php b/hugo/libraries/plugins/transformations/Text_Plain_Substring.class.php new file mode 100644 index 0000000..b04231f --- /dev/null +++ b/hugo/libraries/plugins/transformations/Text_Plain_Substring.class.php @@ -0,0 +1,65 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Text Plain Substring Transformations plugin for phpMyAdmin + * + * @package PhpMyAdmin-Transformations + * @subpackage Substring + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the substring transformations interface */ +require_once 'abstract/SubstringTransformationsPlugin.class.php'; + +/** + * 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"; + } +} + +/** + * Function to call Text_Plain_Substring::getInfo(); + * + * Temporary workaround for bug #3783 : + * Calling a method from a variable class is not possible before PHP 5.3. + * + * This function is called by PMA_getTransformationDescription() + * in libraries/transformations.lib.php using a variable to construct it's name. + * This function then calls the static method. + * + * Don't use this function unless you are affected by the same issue. + * Call the static method directly instead. + * + * @deprecated + * @return string Info about transformation class + */ +function Text_Plain_Substring_getInfo() +{ + return Text_Plain_Substring::getInfo(); +} +?> diff --git a/hugo/libraries/plugins/transformations/abstract/AppendTransformationsPlugin.class.php b/hugo/libraries/plugins/transformations/abstract/AppendTransformationsPlugin.class.php new file mode 100644 index 0000000..0fc3b4d --- /dev/null +++ b/hugo/libraries/plugins/transformations/abstract/AppendTransformationsPlugin.class.php @@ -0,0 +1,86 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Abstract class for the append transformations plugins + * + * @package PhpMyAdmin-Transformations + * @subpackage Append + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the transformations interface */ +require_once 'libraries/plugins/TransformationsPlugin.class.php'; + +/** + * Provides common methods for all of the append transformations plugins. + * + * @package PhpMyAdmin-Transformations + * @subpackage Append + */ +abstract class AppendTransformationsPlugin extends TransformationsPlugin +{ + /** + * Gets the transformation description of the specific plugin + * + * @return string + */ + public static function getInfo() + { + return __( + 'Appends text to a string. The only option is the text to be 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 void + */ + public function applyTransformation($buffer, $options = array(), $meta = '') + { + if (! isset($options[0]) || $options[0] == '') { + $options[0] = ''; + } + //just append the option to the original text + $newtext = $buffer . htmlspecialchars($options[0]); + + return $newtext; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the transformation name of the specific plugin + * + * @return string + */ + public static function getName() + { + return "Append"; + } +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/transformations/abstract/DateFormatTransformationsPlugin.class.php b/hugo/libraries/plugins/transformations/abstract/DateFormatTransformationsPlugin.class.php new file mode 100644 index 0000000..530379f --- /dev/null +++ b/hugo/libraries/plugins/transformations/abstract/DateFormatTransformationsPlugin.class.php @@ -0,0 +1,178 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Abstract class for the date format transformations plugins + * + * @package PhpMyAdmin-Transformations + * @subpackage DateFormat + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the transformations interface */ +require_once 'libraries/plugins/TransformationsPlugin.class.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 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. + if (empty($options[0])) { + $options[0] = 0; + } + + if (empty($options[2])) { + $options[2] = 'local'; + } else { + $options[2] = 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 (strlen($buffer) == 14 || strlen($buffer) == 8) { + $offset = 4; + } else { + $offset = 2; + } + + $d = array(); + $d['year'] = substr($buffer, 0, $offset); + $d['month'] = substr($buffer, $offset, 2); + $d['day'] = substr($buffer, $offset + 2, 2); + $d['hour'] = substr($buffer, $offset + 4, 2); + $d['minute'] = substr($buffer, $offset + 6, 2); + $d['second'] = substr($buffer, $offset + 8, 2); + + if (checkdate($d['month'], $d['day'], $d['year'])) { + $timestamp = mktime( + $d['hour'], + $d['minute'], + $d['second'], + $d['month'], + $d['day'], + $d['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_Util::localisedDate( + $timestamp, + $options[1] + ); + } elseif ($options[2] == 'utc') { + $text = gmdate($options[1], $timestamp); + } else { + $text = 'INVALID DATE TYPE'; + } + $buffer = '<dfn onclick="alert(\'' . $source . '\');" title="' + . $source . '">' . $text . '</dfn>'; + } + + return $buffer; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the transformation name of the specific plugin + * + * @return string + */ + public static function getName() + { + return "Date Format"; + } +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/transformations/abstract/DownloadTransformationsPlugin.class.php b/hugo/libraries/plugins/transformations/abstract/DownloadTransformationsPlugin.class.php new file mode 100644 index 0000000..82eda40 --- /dev/null +++ b/hugo/libraries/plugins/transformations/abstract/DownloadTransformationsPlugin.class.php @@ -0,0 +1,110 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Abstract class for the download transformations plugins + * + * @package PhpMyAdmin-Transformations + * @subpackage Download + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the transformations interface */ +require_once 'libraries/plugins/TransformationsPlugin.class.php'; + +/** + * 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 void + */ + 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&ct=application' + . '/octet-stream&cn=%s" title="%s">%s</a>', + $options['wrapper_link'], + urlencode($cn), + htmlspecialchars($cn), + htmlspecialchars($cn) + ); + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the transformation name of the specific plugin + * + * @return string + */ + public static function getName() + { + return "Download"; + } +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/transformations/abstract/ExternalTransformationsPlugin.class.php b/hugo/libraries/plugins/transformations/abstract/ExternalTransformationsPlugin.class.php new file mode 100644 index 0000000..f93f069 --- /dev/null +++ b/hugo/libraries/plugins/transformations/abstract/ExternalTransformationsPlugin.class.php @@ -0,0 +1,182 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Abstract class for the external transformations plugins + * + * @package PhpMyAdmin-Transformations + * @subpackage External + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the transformations interface */ +require_once 'libraries/plugins/TransformationsPlugin.class.php'; + +/** + * 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/Text_Plain_External' + . '.class.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 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. + + $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; + } + + if (! isset($options[0]) + || $options[0] == '' + || ! isset($allowed_programs[$options[0]]) + ) { + $program = $allowed_programs[0]; + } else { + $program = $allowed_programs[$options[0]]; + } + + if (!isset($options[1]) || $options[1] == '') { + $poptions = '-f /dev/null -i -wrap -q'; + } else { + $poptions = $options[1]; + } + + if (!isset($options[2]) || $options[2] == '') { + $options[2] = 1; + } + + if (!isset($options[3]) || $options[3] == '') { + $options[3] = 1; + } + + // needs PHP >= 4.3.0 + $newstring = ''; + $descriptorspec = array( + 0 => array("pipe", "r"), + 1 => array("pipe", "w") + ); + $process = proc_open($program . ' ' . $poptions, $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; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the transformation name of the specific plugin + * + * @return string + */ + public static function getName() + { + return "External"; + } +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/transformations/abstract/FormattedTransformationsPlugin.class.php b/hugo/libraries/plugins/transformations/abstract/FormattedTransformationsPlugin.class.php new file mode 100644 index 0000000..e6bb8d9 --- /dev/null +++ b/hugo/libraries/plugins/transformations/abstract/FormattedTransformationsPlugin.class.php @@ -0,0 +1,80 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Abstract class for the formatted transformations plugins + * + * @package PhpMyAdmin-Transformations + * @subpackage Formatted + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the transformations interface */ +require_once 'libraries/plugins/TransformationsPlugin.class.php'; + +/** + * 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 void + */ + public function applyTransformation($buffer, $options = array(), $meta = '') + { + return $buffer; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the transformation name of the specific plugin + * + * @return string + */ + public static function getName() + { + return "Formatted"; + } +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/transformations/abstract/HexTransformationsPlugin.class.php b/hugo/libraries/plugins/transformations/abstract/HexTransformationsPlugin.class.php new file mode 100644 index 0000000..8022da9 --- /dev/null +++ b/hugo/libraries/plugins/transformations/abstract/HexTransformationsPlugin.class.php @@ -0,0 +1,91 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Abstract class for the hex transformations plugins + * + * @package PhpMyAdmin-Transformations + * @subpackage Hex + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the transformations interface */ +require_once 'libraries/plugins/TransformationsPlugin.class.php'; + +/** + * 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 void + */ + public function applyTransformation($buffer, $options = array(), $meta = '') + { + // possibly use a global transform and feed it with special options + if (!isset($options[0])) { + $options[0] = 2; + } else { + $options[0] = (int)$options[0]; + } + + if ($options[0] < 1) { + return bin2hex($buffer); + } else { + return chunk_split(bin2hex($buffer), $options[0], ' '); + } + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the transformation name of the specific plugin + * + * @return string + */ + public static function getName() + { + return "Hex"; + } +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/transformations/abstract/ImageLinkTransformationsPlugin.class.php b/hugo/libraries/plugins/transformations/abstract/ImageLinkTransformationsPlugin.class.php new file mode 100644 index 0000000..456f102 --- /dev/null +++ b/hugo/libraries/plugins/transformations/abstract/ImageLinkTransformationsPlugin.class.php @@ -0,0 +1,89 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Abstract class for the link transformations plugins + * + * @package PhpMyAdmin-Transformations + * @subpackage Link + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the transformations interface */ +require_once 'libraries/plugins/TransformationsPlugin.class.php'; +/* For PMA_transformation_global_html_replace */ +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 void + */ + public function applyTransformation($buffer, $options = array(), $meta = '') + { + $transform_options = array ( + 'string' => '<a href="transformation_wrapper.php' + . $options['wrapper_link'] . '" alt="[__BUFFER__]">[BLOB]</a>' + ); + $buffer = PMA_transformation_global_html_replace( + $buffer, + $transform_options + ); + + return $buffer; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the transformation name of the specific plugin + * + * @return string + */ + public static function getName() + { + return "Link"; + } +} +?> diff --git a/hugo/libraries/plugins/transformations/abstract/InlineTransformationsPlugin.class.php b/hugo/libraries/plugins/transformations/abstract/InlineTransformationsPlugin.class.php new file mode 100644 index 0000000..b1ef0ae --- /dev/null +++ b/hugo/libraries/plugins/transformations/abstract/InlineTransformationsPlugin.class.php @@ -0,0 +1,103 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Abstract class for the inline transformations plugins + * + * @package PhpMyAdmin-Transformations + * @subpackage Inline + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the transformations interface */ +require_once 'libraries/plugins/TransformationsPlugin.class.php'; +/* For PMA_transformation_global_html_replace */ +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 void + */ + public function applyTransformation($buffer, $options = array(), $meta = '') + { + if (PMA_IS_GD2) { + $transform_options = array ( + 'string' => '<a href="transformation_wrapper.php' + . $options['wrapper_link'] + . '" target="_blank"><img src="transformation_wrapper.php' + . $options['wrapper_link'] . '&resize=jpeg&newWidth=' + . (isset($options[0]) ? $options[0] : '100') . '&newHeight=' + . (isset($options[1]) ? $options[1] : 100) + . '" alt="[__BUFFER__]" border="0" /></a>' + ); + } else { + $transform_options = array ( + 'string' => '<img src="transformation_wrapper.php' + . $options['wrapper_link'] + . '" alt="[__BUFFER__]" width="320" height="240" />' + ); + } + $buffer = PMA_transformation_global_html_replace( + $buffer, + $transform_options + ); + + return $buffer; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the transformation name of the specific plugin + * + * @return string + */ + public static function getName() + { + return "Inline"; + } +} +?> diff --git a/hugo/libraries/plugins/transformations/abstract/LongToIPv4TransformationsPlugin.class.php b/hugo/libraries/plugins/transformations/abstract/LongToIPv4TransformationsPlugin.class.php new file mode 100644 index 0000000..58dda95 --- /dev/null +++ b/hugo/libraries/plugins/transformations/abstract/LongToIPv4TransformationsPlugin.class.php @@ -0,0 +1,83 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Abstract class for the long to IPv4 transformations plugins + * + * @package PhpMyAdmin-Transformations + * @subpackage LongToIPv4 + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the transformations interface */ +require_once 'libraries/plugins/TransformationsPlugin.class.php'; + +/** + * 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 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 void + */ + public function applyTransformation($buffer, $options = array(), $meta = '') + { + if ($buffer < 0 || $buffer > 4294967295) { + return $buffer; + } + + return long2ip($buffer); + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the transformation name of the specific plugin + * + * @return string + */ + public static function getName() + { + return "Long To IPv4"; + } +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/transformations/abstract/SQLTransformationsPlugin.class.php b/hugo/libraries/plugins/transformations/abstract/SQLTransformationsPlugin.class.php new file mode 100644 index 0000000..2123cdb --- /dev/null +++ b/hugo/libraries/plugins/transformations/abstract/SQLTransformationsPlugin.class.php @@ -0,0 +1,81 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Abstract class for the SQL transformations plugins + * + * @package PhpMyAdmin-Transformations + * @subpackage SQL + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the transformations interface */ +require_once 'libraries/plugins/TransformationsPlugin.class.php'; + +/** + * 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 void + */ + public function applyTransformation($buffer, $options = array(), $meta = '') + { + $result = PMA_SQP_formatHtml(PMA_SQP_parse($buffer)); + // Need to clear error state not to break subsequent queries display. + PMA_SQP_resetError(); + return $result; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the transformation name of the specific plugin + * + * @return string + */ + public static function getName() + { + return "SQL"; + } +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/transformations/abstract/SubstringTransformationsPlugin.class.php b/hugo/libraries/plugins/transformations/abstract/SubstringTransformationsPlugin.class.php new file mode 100644 index 0000000..2de48e6 --- /dev/null +++ b/hugo/libraries/plugins/transformations/abstract/SubstringTransformationsPlugin.class.php @@ -0,0 +1,116 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Abstract class for the substring transformations plugins + * + * @package PhpMyAdmin-Transformations + * @subpackage Substring + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the transformations interface */ +require_once 'libraries/plugins/TransformationsPlugin.class.php'; + +/** + * Provides common methods for all of the substring transformations plugins. + * + * @package PhpMyAdmin + */ +abstract class SubstringTransformationsPlugin extends TransformationsPlugin +{ + /** + * Gets the transformation description of the specific plugin + * + * @return string + */ + public static function getInfo() + { + return __( + 'Displays a part of a string. The first option is the number of' + . ' characters to skip from the beginning of the string (Default 0).' + . ' The second option is the number of characters to return (Default:' + . ' until end of string). The third option is the string to append' + . ' and/or prepend when truncation occurs (Default: "…").' + ); + } + + /** + * 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. + if (!isset($options[0]) || $options[0] == '') { + $options[0] = 0; + } + + if (!isset($options[1]) || $options[1] == '') { + $options[1] = 'all'; + } + + if (!isset($options[2]) || $options[2] == '') { + $options[2] = '…'; + } + + $newtext = ''; + if ($options[1] != 'all') { + $newtext = PMA_substr($buffer, $options[0], $options[1]); + } else { + $newtext = PMA_substr($buffer, $options[0]); + } + + $length = strlen($newtext); + $baselength = strlen($buffer); + if ($length != $baselength) { + if ($options[0] != 0) { + $newtext = $options[2] . $newtext; + } + + if (($length + $options[0]) != $baselength) { + $newtext .= $options[2]; + } + } + + return $newtext; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the transformation name of the specific plugin + * + * @return string + */ + public static function getName() + { + return "Substring"; + } +} +?>
\ No newline at end of file diff --git a/hugo/libraries/plugins/transformations/abstract/TextImageLinkTransformationsPlugin.class.php b/hugo/libraries/plugins/transformations/abstract/TextImageLinkTransformationsPlugin.class.php new file mode 100644 index 0000000..054b2f9 --- /dev/null +++ b/hugo/libraries/plugins/transformations/abstract/TextImageLinkTransformationsPlugin.class.php @@ -0,0 +1,96 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Abstract class for the image link transformations plugins + * + * @package PhpMyAdmin-Transformations + * @subpackage ImageLink + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the transformations interface */ +require_once 'libraries/plugins/TransformationsPlugin.class.php'; +/* For PMA_transformation_global_html_replace */ +require_once 'libraries/transformations.lib.php'; + +/** + * Provides common methods for all of the image link transformations plugins. + * + * @package PhpMyAdmin + */ +abstract class TextImageLinkTransformationsPlugin extends TransformationsPlugin +{ + /** + * Gets the transformation description of the specific plugin + * + * @return string + */ + public static function getInfo() + { + return __( + 'Displays an image and a link; the column contains the filename. The' + . ' first option is a URL prefix like "http://www.example.com/". The' + . ' second and third options are the width and the height in pixels.' + ); + } + + /** + * 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 = '') + { + $transform_options = array ( + 'string' => '<a href="' . (isset($options[0]) ? $options[0] : '') + . $buffer . '" target="_blank"><img src="' + . (isset($options[0]) ? $options[0] : '') . $buffer + . '" border="0" width="' . (isset($options[1]) ? $options[1] : 100) + . '" height="' . (isset($options[2]) ? $options[2] : 50) . '" />' + . $buffer . '</a>' + ); + + $buffer = PMA_transformation_global_html_replace( + $buffer, + $transform_options + ); + + return $buffer; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the transformation name of the specific plugin + * + * @return string + */ + public static function getName() + { + return "Image Link"; + } +} +?> diff --git a/hugo/libraries/plugins/transformations/abstract/TextLinkTransformationsPlugin.class.php b/hugo/libraries/plugins/transformations/abstract/TextLinkTransformationsPlugin.class.php new file mode 100644 index 0000000..f61e9a9 --- /dev/null +++ b/hugo/libraries/plugins/transformations/abstract/TextLinkTransformationsPlugin.class.php @@ -0,0 +1,100 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Abstract class for the link transformations plugins + * + * @package PhpMyAdmin-Transformations + * @subpackage Link + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/* Get the transformations interface */ +require_once 'libraries/plugins/TransformationsPlugin.class.php'; +/* For PMA_transformation_global_html_replace */ +require_once 'libraries/transformations.lib.php'; + +/** + * Provides common methods for all of the link transformations plugins. + * + * @package PhpMyAdmin + */ +abstract class TextLinkTransformationsPlugin extends TransformationsPlugin +{ + /** + * Gets the transformation description of the specific plugin + * + * @return string + */ + public static function getInfo() + { + return __( + 'Displays a link; the column contains the filename. The first option' + . ' is a URL prefix like "http://www.example.com/". The second option' + . ' is a title for the link.' + ); + } + + /** + * 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 = '') + { + + $append_part = (isset($options[2]) && $options[2]) ? '' : $buffer; + + $transform_options = array ( + 'string' => '<a href="' + . PMA_linkURL((isset($options[0]) ? $options[0] : '') . $append_part) + . '" title="' + . htmlspecialchars(isset($options[1]) ? $options[1] : '') + . '" target="_new">' + . htmlspecialchars(isset($options[1]) ? $options[1] : $buffer) + . '</a>' + ); + + $buffer = PMA_transformation_global_html_replace( + $buffer, + $transform_options + ); + + return $buffer; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the transformation name of the specific plugin + * + * @return string + */ + public static function getName() + { + return "Link"; + } +} +?> diff --git a/hugo/libraries/plugins/transformations/generator_main_class.sh b/hugo/libraries/plugins/transformations/generator_main_class.sh new file mode 100755 index 0000000..0587667 --- /dev/null +++ b/hugo/libraries/plugins/transformations/generator_main_class.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# +# Shell script that creates only the main class for a new transformation +# plug-in, using a template +# +# $1: MIMEType +# $2: MIMESubtype +# $3: Transformation Name + +if [ $# != 3 ] +then + echo -e "Usage: ./generator_main_class.sh MIMEType MIMESubtype TransformationName\n" + exit 65 +fi + +./generator_plugin.sh "$1" "$2" "$3" "--generate_only_main_class"
\ No newline at end of file diff --git a/hugo/libraries/plugins/transformations/generator_plugin.sh b/hugo/libraries/plugins/transformations/generator_plugin.sh new file mode 100755 index 0000000..225a2cb --- /dev/null +++ b/hugo/libraries/plugins/transformations/generator_plugin.sh @@ -0,0 +1,64 @@ +#!/bin/bash +# +# Shell script that creates a new transformation plug-in (both main and +# abstract class) using a template. +# +# The 'description' parameter will add a new entry in the language file. +# Watch out for special escaping. +# +# $1: MIMEType +# $2: MIMESubtype +# $3: Transformation Name +# $4: (optional) Description + +echo $# +if [ $# -ne 3 -a $# -ne 4 ]; then + echo -e "Usage: ./generator_plugin.sh MIMEType MIMESubtype TransformationName [Description]\n" + exit 65 +fi + +# make sure that the MIME Type, MIME Subtype and Transformation names +# are in the correct format + +# make all names lowercase +MT="`echo $1 | tr [:upper:] [:lower:]`" +MS="`echo $2 | tr [:upper:] [:lower:]`" +TN="`echo $3 | tr [:upper:] [:lower:]`" +# make first letter uppercase +MT="${MT^}" +MS="${MS^}" +TN="${TN^}" +# make the first letter after each underscore uppercase +MT="`echo $MT`" +MT="`echo $MT | sed -e 's/_./\U&\E/g'`" +MS="`echo $MS`" +MS="`echo $MS | sed -e 's/_./\U&\E/g'`" +TN="`echo $TN`" +TN="`echo $TN | sed -e 's/_./\U&\E/g'`" + +# define the name of the main class file and of its template +ClassFile=$MT\_$MS\_$TN.class.php +Template=TEMPLATE +# define the name of the abstract class file and its template +AbstractClassFile=abstract/"$TN"TransformationsPlugin.class.php +AbstractTemplate=TEMPLATE_ABSTRACT +# replace template names with argument names +sed "s/\[MIMEType]/$MT/; s/\[MIMESubtype\]/$MS/; s/\[TransformationName\]/$TN/;" < $Template > $ClassFile +echo "Created $ClassFile" + +GenerateAbstractClass=1 +if [ -n $4 ]; then + if [ "$4" == "--generate_only_main_class" ]; then + if [ -e $AbstractClassFile ]; then + GenerateAbstractClass=0 + fi + fi +fi + +if [ $GenerateAbstractClass -eq 1 ]; then + # replace template names with argument names + sed "s/\[TransformationName\]/$TN/; s/Description of the transformation./$4/;" < $AbstractTemplate > $AbstractClassFile + echo "Created $AbstractClassFile" +fi + +echo ""
\ No newline at end of file |
