This commit is contained in:
Hugues Peccatte 2015-08-23 13:04:46 +02:00
commit 00dee1085c
293 changed files with 160841 additions and 152268 deletions

1
.gitignore vendored
View File

@ -46,4 +46,5 @@ phpunit.xml
# Ant cache
cache.properties
# Composer
composer.lock
/vendor/

View File

@ -6,6 +6,7 @@
language: php
php:
- "7.0"
- "5.6"
- "5.5"
- "5.4"
@ -61,6 +62,8 @@ matrix:
env: PHPUNIT_ARGS="--exclude-group selenium"
- php: nightly
env: PHPUNIT_ARGS="--exclude-group selenium"
- php: "7.0"
env: PHPUNIT_ARGS="--exclude-group selenium"
fast_finish: true
include:
- php: 5.6

View File

@ -87,9 +87,26 @@ phpMyAdmin - ChangeLog
+ Upgrade TCPDF to version 6.2.9
+ issue #6102 Add SHA256 security password support
- issue #10250 Displayed git revision info is not set
+ Improved schema SVG export
- issue #10726 Do not try to set port 80 for https requests
+ issue #11394 Export/import Designer view
+ Partition support in table Structure
+ issue #11414 Unclear export options / organization / hierarchy
Set minimum required PHP version to 5.5 (older versions are EOL)
- issue #11407 ALTER TABLE failing on import when table exists
4.4.14.0 (not yet released)
4.4.15.0 (not yet released)
4.4.14.0 (2015-08-20)
- issue #11367 Export after search, missing WHERE clause
- issue #11380 Incomplete message after import
- issue Incorrect scalar type declaration (reported under PHP 7)
- issue #11389 ReCaptcha produces deprecated messages under PHP 7
- issue #11387 phpseclib < 2.0 produces deprecated messages on PHP 7
- issue #11404 "Switch to copied table" doesn't work
- issue #11406 Missing quotes after calling "distinct values"
- issue #11386 Cannot import database with long data in one column
- issue #11410 SPATIAL index option is not clickable
4.4.13.1 (2015-08-08)
- issue #11368 SQL error when importing phpMyAdmin dump file

View File

@ -9,12 +9,6 @@
<exclude name="PEAR.Commenting.FunctionComment" />
<exclude name="Generic.Commenting.DocComment" />
</rule>
<rule ref="Generic.Files.LineLength">
<properties>
<property name="lineLimit" value="85"/>
<property name="absoluteLineLimit" value="0"/>
</properties>
</rule>
<rule ref="Generic.Metrics.NestingLevel" />
<!-- There MUST NOT be trailing whitespace at the end of lines. -->
<rule ref="Squiz.WhiteSpace.SuperfluousWhitespace" />

View File

@ -24,6 +24,13 @@
"require-dev": {
"satooshi/php-coveralls": ">=0.6",
"phpunit/phpunit": ">=3.7",
"phpunit/phpunit-selenium": ">=1.2"
}
"phpunit/phpunit-selenium": ">=1.2",
"squizlabs/php_codesniffer": "2.*"
},
"repositories": [
{
"type": "composer",
"url": "https://www.phpmyadmin.net"
}
]
}

View File

@ -36,12 +36,8 @@ if (isset($_REQUEST['dialog'])) {
if (isset($_REQUEST['operation'])) {
if ($_REQUEST['operation'] == 'deletePage') {
$result = PMA_deletePage($_REQUEST['selected_page']);
if ($result) {
$response->isSuccess(true);
} else {
$response->isSuccess(false);
}
$success = PMA_deletePage($_REQUEST['selected_page']);
$response->isSuccess($success);
} elseif ($_REQUEST['operation'] == 'savePage') {
if ($_REQUEST['save_page'] == 'same') {
$page = $_REQUEST['selected_page'];
@ -49,11 +45,8 @@ if (isset($_REQUEST['operation'])) {
$page = PMA_createNewPage($_REQUEST['selected_value'], $GLOBALS['db']);
$response->addJSON('id', $page);
}
if (PMA_saveTablePositions($page)) {
$response->isSuccess(true);
} else {
$response->isSuccess(false);
}
$success = PMA_saveTablePositions($page);
$response->isSuccess($success);
} elseif ($_REQUEST['operation'] == 'setDisplayField') {
PMA_saveDisplayField(
$_REQUEST['db'], $_REQUEST['table'], $_REQUEST['field']
@ -81,56 +74,8 @@ if (isset($_REQUEST['operation'])) {
$response->isSuccess($success);
$response->addJSON('message', $message);
} elseif ($_REQUEST['operation'] == 'save_setting_value') {
$cfgRelation = PMA_getRelationsParam();
$cfgDesigner = array(
'user' => $GLOBALS['cfg']['Server']['user'],
'db' => $cfgRelation['db'],
'table' => $cfgRelation['designer_settings']
);
if (! empty($cfgDesigner['user'])
&& ! empty($cfgDesigner['db'])
&& ! empty($cfgDesigner['table'])
&& $GLOBALS['cfgRelation']['designersettingswork']
) {
$orig_data_query = 'SELECT ' . PMA_Util::backquote('settings_data')
. ' FROM `' . $cfgDesigner['db'] . '`.`' . $cfgDesigner['table']
. '` WHERE ' . PMA_Util::backquote('username') . ' = "'
. $cfgDesigner['user'] . '"';
$orig_data = $GLOBALS['dbi']->fetchSingleRow($orig_data_query);
$success = false;
if (isset($orig_data)
&& ! empty($orig_data)
&& $orig_data
) {
$orig_data = json_decode($orig_data['settings_data'], true);
$orig_data[$_REQUEST['index']] = $_REQUEST['value'];
$orig_data = json_encode($orig_data);
$save_query = 'UPDATE `' . $cfgDesigner['db'] . '`.`'
. $cfgDesigner['table'] . '` SET '
. PMA_Util::backquote('settings_data') . ' = \''
. $orig_data . '\' WHERE ' . PMA_Util::backquote('username')
. ' = "' . $cfgDesigner['user'] . '";';
$success = $GLOBALS['dbi']->query($save_query);
} else {
$save_data = array($_REQUEST['index'] => $_REQUEST['value']);
$query = 'INSERT INTO ' . PMA_Util::backquote($cfgDesigner['db'])
. '.' . PMA_Util::backquote($cfgDesigner['table'])
. ' VALUES("' . PMA_Util::sqlAddSlashes($cfgDesigner['user'])
. '", \''
. PMA_Util::sqlAddSlashes(json_encode($save_data)) . '\');';
$success = $GLOBALS['dbi']->query($query);
}
$response->isSuccess($success);
}
$success = PMA_saveDesignerSetting($_REQUEST['index'], $_REQUEST['value']);
$response->isSuccess($success);
}
return;

View File

@ -22,5 +22,10 @@ $scripts->addFile('import.js');
require 'libraries/db_common.inc.php';
require 'libraries/db_info.inc.php';
$import_type = 'database';
require 'libraries/display_import.inc.php';
require 'libraries/display_import.lib.php';
$response = PMA_Response::getInstance();
$response->addHTML(
PMA_getImportDisplay(
'database', $db, $table, $max_upload_size
)
);

View File

@ -12,34 +12,26 @@ require_once 'libraries/common.inc.php';
require_once 'libraries/db_common.inc.php';
require_once 'libraries/db_info.inc.php';
require_once 'libraries/di/Container.class.php';
require_once 'libraries/controllers/StructureController.class.php';
require_once 'libraries/controllers/DatabaseStructureController.class.php';
$container = DI\Container::getDefaultContainer();
$container->factory('PMA\Controllers\StructureController');
$container->factory('PMA\Controllers\DatabaseStructureController');
$container->alias(
'StructureController', 'PMA\Controllers\StructureController'
'DatabaseStructureController', 'PMA\Controllers\DatabaseStructureController'
);
global $db, $table, $pos, $db_is_system_schema, $total_num_tables, $tables,
$num_tables, $tbl_is_view, $tbl_storage_engine, $table_info_num_rows, $tbl_collation, $showtable;
global $db, $pos, $db_is_system_schema, $total_num_tables, $tables, $num_tables;
/* Define dependencies for the concerned controller */
$dependency_definitions = array(
'db' => $db,
'table' => $table,
'type' => 'db',
'url_query' => &$GLOBALS['url_query'],
'pos' => $pos,
'db_is_system_schema' => $db_is_system_schema,
'num_tables' => $num_tables,
'total_num_tables' => $total_num_tables,
'tables' => $tables,
'tbl_is_view' => $tbl_is_view,
'tbl_storage_engine' => $tbl_storage_engine,
'table_info_num_rows' => $table_info_num_rows,
'tbl_collation' => $tbl_collation,
'showtable' => $showtable
);
/** @var Controllers\StructureController $controller */
$controller = $container->get('StructureController', $dependency_definitions);
/** @var Controllers\DatabaseStructureController $controller */
$controller = $container->get('DatabaseStructureController', $dependency_definitions);
$controller->indexAction();

View File

@ -110,234 +110,19 @@ $all_tables_result = PMA_queryAsControlUser($all_tables_query);
// If a HEAD version exists
if ($GLOBALS['dbi']->numRows($all_tables_result) > 0) {
?>
<div id="tracked_tables">
<h3><?php echo __('Tracked tables');?></h3>
<form method="post" action="db_tracking.php" name="trackedForm"
id="trackedForm" class="ajax">
<?php
echo PMA_URL_getHiddenInputs($GLOBALS['db'])
?>
<table id="versions" class="data">
<thead>
<tr>
<th></th>
<th><?php echo __('Table');?></th>
<th><?php echo __('Last version');?></th>
<th><?php echo __('Created');?></th>
<th><?php echo __('Updated');?></th>
<th><?php echo __('Status');?></th>
<th><?php echo __('Action');?></th>
<th><?php echo __('Show');?></th>
</tr>
</thead>
<tbody>
<?php
// Print out information about versions
$delete = PMA_Util::getIcon('b_drop.png', __('Delete tracking'));
$versions = PMA_Util::getIcon('b_versions.png', __('Versions'));
$report = PMA_Util::getIcon('b_report.png', __('Tracking report'));
$structure = PMA_Util::getIcon('b_props.png', __('Structure snapshot'));
$style = 'odd';
while ($one_result = $GLOBALS['dbi']->fetchArray($all_tables_result)) {
list($table_name, $version_number) = $one_result;
$table_query = ' SELECT * FROM ' .
PMA_Util::backquote($cfgRelation['db']) . '.' .
PMA_Util::backquote($cfgRelation['tracking']) .
' WHERE `db_name` = \'' . PMA_Util::sqlAddSlashes($_REQUEST['db'])
. '\' AND `table_name` = \'' . PMA_Util::sqlAddSlashes($table_name)
. '\' AND `version` = \'' . $version_number . '\'';
$table_result = PMA_queryAsControlUser($table_query);
$version_data = $GLOBALS['dbi']->fetchArray($table_result);
$tmp_link = 'tbl_tracking.php' . $url_query . '&amp;table='
. htmlspecialchars($version_data['table_name']);
$delete_link = 'db_tracking.php' . $url_query . '&amp;table='
. htmlspecialchars($version_data['table_name'])
. '&amp;delete_tracking=true&amp';
$checkbox_id = "selected_tbl_"
. htmlspecialchars($version_data['table_name']);
?>
<tr class="<?php echo $style;?>">
<td class="center">
<input type="checkbox" name="selected_tbl[]"
class="checkall" id="<?php echo $checkbox_id;?>"
value="<?php echo htmlspecialchars($version_data['table_name']);?>"/>
</td>
<th>
<label for="<?php echo $checkbox_id;?>">
<?php echo htmlspecialchars($version_data['table_name']);?>
</label>
</th>
<td class="right"><?php echo $version_data['version'];?></td>
<td><?php echo $version_data['date_created'];?></td>
<td><?php echo $version_data['date_updated'];?></td>
<td>
<?php
$state = PMA_getVersionStatus($version_data);
$options = array(
0 => array(
'label' => __('not active'),
'value' => 'deactivate_now',
'selected' => ($state != 'active')
),
1 => array(
'label' => __('active'),
'value' => 'activate_now',
'selected' => ($state == 'active')
)
);
echo PMA_Util::toggleButton(
$tmp_link . '&amp;version=' . $version_data['version'],
'toggle_activation',
$options,
null
);
?>
</td>
<td>
<a class="delete_tracking_anchor ajax"
href="<?php echo $delete_link;?>" >
<?php echo $delete; ?></a>
<?php
echo '</td>'
. '<td>'
. '<a href="' . $tmp_link . '">' . $versions . '</a>'
. '&nbsp;&nbsp;'
. '<a href="' . $tmp_link . '&amp;report=true&amp;version='
. $version_data['version'] . '">' . $report . '</a>'
. '&nbsp;&nbsp;'
. '<a href="' . $tmp_link . '&amp;snapshot=true&amp;version='
. $version_data['version'] . '">' . $structure . '</a>'
. '</td>'
. '</tr>';
if ($style == 'even') {
$style = 'odd';
} else {
$style = 'even';
}
}
unset($tmp_link);
?>
</tbody>
</table>
<?php
echo PMA_Util::getWithSelected($pmaThemeImage, $text_dir, "trackedForm");
echo PMA_Util::getButtonOrImage(
'submit_mult', 'mult_submit', 'submit_mult_delete_tracking',
__('Delete tracking'), 'b_drop.png', 'delete_tracking'
PMA_displayTrackedTables(
$GLOBALS['db'], $all_tables_result, $url_query, $pmaThemeImage,
$text_dir, $cfgRelation
);
?>
</form>
</div>
<?php
}
$sep = $GLOBALS['cfg']['NavigationTreeTableSeparator'];
// Get list of tables
$table_list = PMA_Util::getTableList($GLOBALS['db']);
$my_tables = array();
// For each table try to get the tracking version
foreach ($table_list as $key => $value) {
// If $value is a table group.
if (array_key_exists(('is' . $sep . 'group'), $value)
&& $value['is' . $sep . 'group']
) {
foreach ($value as $temp_table) {
// If $temp_table is a table with the value for 'Name' is set,
// rather than a property of the table group.
if (is_array($temp_table)
&& array_key_exists('Name', $temp_table)
) {
$tracking_version = PMA_Tracker::getVersion(
$GLOBALS['db'],
$temp_table['Name']
);
if ($tracking_version == -1) {
$my_tables[] = $temp_table['Name'];
}
}
}
} else { // If $value is a table.
if (PMA_Tracker::getVersion($GLOBALS['db'], $value['Name']) == -1) {
$my_tables[] = $value['Name'];
}
}
}
$untracked_tables = PMA_getUntrackedTables($GLOBALS['db']);
// If untracked tables exist
if (count($my_tables) > 0) {
?>
<h3><?php echo __('Untracked tables');?></h3>
<form method="post" action="db_tracking.php" name="untrackedForm"
id="untrackedForm" class="ajax">
<?php
echo PMA_URL_getHiddenInputs($GLOBALS['db'])
?>
<table id="noversions" class="data">
<thead>
<tr>
<th></th>
<th style="width: 300px"><?php echo __('Table');?></th>
<th><?php echo __('Action');?></th>
</tr>
</thead>
<tbody>
<?php
// Print out list of untracked tables
$style = 'odd';
foreach ($my_tables as $key => $tablename) {
$checkbox_id = "selected_tbl_"
. htmlspecialchars($tablename);
if (PMA_Tracker::getVersion($GLOBALS['db'], $tablename) == -1) {
$my_link = '<a href="tbl_tracking.php' . $url_query
. '&amp;table=' . htmlspecialchars($tablename) . '">';
$my_link .= PMA_Util::getIcon('eye.png', __('Track table'));
$my_link .= '</a>';
?>
<tr class="<?php echo $style;?>">
<td class="center">
<input type="checkbox" name="selected_tbl[]"
class="checkall" id="<?php echo $checkbox_id;?>"
value="<?php echo htmlspecialchars($tablename);?>"/>
</td>
<th>
<label for="<?php echo $checkbox_id;?>">
<?php echo htmlspecialchars($tablename);?>
</label>
</th>
<td><?php echo $my_link;?></td>
</tr>
<?php
if ($style == 'even') {
$style = 'odd';
} else {
$style = 'even';
}
}
}
?>
</tbody>
</table>
<?php
echo PMA_Util::getWithSelected($pmaThemeImage, $text_dir, "untrackedForm");
echo PMA_Util::getButtonOrImage(
'submit_mult', 'mult_submit', 'submit_mult_track',
__('Track table'), 'eye.png', 'track'
if (count($untracked_tables) > 0) {
PMA_displayUntrackedTables(
$GLOBALS['db'], $untracked_tables, $url_query, $pmaThemeImage, $text_dir
);
?>
</form>
<?php
}
// If available print out database log
if (count($data['ddlog']) > 0) {

View File

@ -402,6 +402,18 @@ Credits, in chronological order
* Export with table/column name changes
* Dan Ungureanu (Google Summer of Code 2015)
* New parser and analyzer
* Nisarg Jhaveri (Google Summer of Code 2015)
* Page-related settings
* SQL debugging integration to the Console
* Other UI improvements
And also to the following people who have contributed minor changes,
enhancements, bugfixes or support for a new language since version
2.1.0:

View File

@ -385,8 +385,7 @@ MMCache but upgrading MMCache to version 2.3.21 solves the problem.
Yes.
Since release 4.1 phpMyAdmin supports only PHP 5.3 and newer. For PHP 5.2 you
can use 4.0.x releases.
Since release 4.5, phpMyAdmin supports only PHP 5.5 and newer. Since release 4.1 phpMyAdmin supports only PHP 5.3 and newer. For PHP 5.2 you can use 4.0.x releases.
.. _faq1_32:

View File

@ -12,7 +12,7 @@ web server (such as Apache, nginx, :term:`IIS`) to install phpMyAdmin's files in
PHP
---
* You need PHP 5.3.0 or newer, with ``session`` support, the Standard PHP Library
* You need PHP 5.5.0 or newer, with ``session`` support, the Standard PHP Library
(SPL) extension, JSON support, and the ``mbstring`` extension.
* To support uploading of ZIP files, you need the PHP ``zip`` extension.

View File

@ -253,9 +253,16 @@ Verifying phpMyAdmin releases
+++++++++++++++++++++++++++++
Since July 2015 all phpMyAdmin releases are cryptographically signed by the
releasing developer. You should verify that the signature matches the archive
you have downloaded. This way you can be sure that you are using the same code
that was released.
releasing developer, who is currently Marc Delisle. His key id is
0x81AF644A, his PGP fingerprint is:
.. code-block:: console
436F F188 4B1A 0C3F DCBF 0D79 FEFC 65D1 81AF 644A
and you can get more identification information from `https://keybase.io/lem9 <https://keybase.io/lem9>`_. You should verify that the signature matches
the archive you have downloaded. This way you can be sure that you are using
the same code that was released.
Each archive is accompanied with ``.asc`` files which contains the PGP signature
for it. Once you have both of them in the same folder, you can verify the signature:

View File

@ -114,7 +114,6 @@ if (!defined('TESTSUITE')) {
'sql_create_database',
'sql_drop_table',
'sql_procedure_function',
'sql_create_table_statements',
'sql_create_table',
'sql_create_view',
'sql_create_trigger',

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -301,7 +301,7 @@ for ($a = 0; $a < $geom_count; $a++) {
echo '<label for="y">' . __("Y") . '</label>';
echo '<input type="text" name="gis_data[' . $a . '][' . $type . ']['
. $i . '][' . $j . '][y]"' . ' value="'
. escape($gis_data[$a][$type][$i][$j]['x']) . '" />';
. escape($gis_data[$a][$type][$i][$j]['y']) . '" />';
}
echo '<input type="submit" name="gis_data[' . $a . '][' . $type . ']['
. $i . '][add_point]"'

View File

@ -690,7 +690,7 @@ if (! empty($id_bookmark) && $_REQUEST['action_bookmark'] == 2) {
if ($import_notice) {
$message->addString($import_notice);
}
if (isset($local_import_file)) {
if (! empty($local_import_file)) {
$message->addString('(' . htmlspecialchars($local_import_file) . ')');
} else {
$message->addString(

View File

@ -15,6 +15,7 @@ require_once 'libraries/common.inc.php';
* display Git revision if requested
*/
require_once 'libraries/display_git_revision.lib.php';
require_once 'libraries/Template.class.php';
/**
* pass variables to child pages
@ -187,7 +188,7 @@ if ($server > 0 || count($cfg['Servers']) > 1
if ($cfg['ShowChgPassword']) {
$conditional_class = 'ajax';
PMA_printListItem(
PMA_Util::getImage('s_passwd.png') . " " . __('Change password'),
PMA_Util::getImage('s_passwd.png') . "&nbsp;" . __('Change password'),
'li_change_password',
'user_password.php' . $common_url_query,
null,
@ -202,7 +203,7 @@ if ($server > 0 || count($cfg['Servers']) > 1
echo ' <form method="post" action="index.php">' . "\n"
. PMA_URL_getHiddenInputs(null, null, 4, 'collation_connection')
. ' <label for="select_collation_connection">' . "\n"
. ' ' . PMA_Util::getImage('s_asci.png') . " "
. ' ' . PMA_Util::getImage('s_asci.png') . "&nbsp;"
. __('Server connection collation') . "\n"
// put the doc link in the form so that it appears on the same line
. PMA_Util::showMySQLDocu('Charset-connection')
@ -255,7 +256,7 @@ echo '</ul>';
if ($server > 0) {
echo '<ul>';
PMA_printListItem(
PMA_Util::getImage('b_tblops.png') . " " . __('More settings'),
PMA_Util::getImage('b_tblops.png') . "&nbsp;" . __('More settings'),
'li_user_preferences',
'prefs_manage.php' . $common_url_query,
null,
@ -698,32 +699,19 @@ function PMA_printListItem($name, $listId = null, $url = null,
$mysql_help_page = null, $target = null, $a_id = null, $class = null,
$a_class = null
) {
echo '<li id="' . $listId . '"';
if (null !== $class) {
echo ' class="' . $class . '"';
}
echo '>';
if (null !== $url) {
echo '<a href="' . $url . '"';
if (null !== $target) {
echo ' target="' . $target . '"';
}
if (null !== $a_id) {
echo ' id="' . $a_id . '"';
}
if (null !== $a_class) {
echo ' class="' . $a_class . '"';
}
echo '>';
}
echo $name;
if (null !== $url) {
echo '</a>' . "\n";
}
if (null !== $mysql_help_page) {
echo PMA_Util::showMySQLDocu($mysql_help_page);
}
echo '</li>';
echo PMA\Template::get('list/item')
->render(
array(
'content' => $name,
'id' => $listId,
'class' => $class,
'url' => array(
'href' => $url,
'target' => $target,
'id' => $a_id,
'class' => $a_class,
),
'mysql_help_page' => $mysql_help_page,
)
);
}

View File

@ -539,19 +539,6 @@ function toggle_table_select(row) {
}
AJAX.registerOnload('export.js', function () {
/**
* For SQL plugin, if "CREATE TABLE options" is checked/unchecked, check/uncheck each of its sub-options
*/
var $create = $("#checkbox_sql_create_table_statements");
var $create_options = $("#ul_create_table_statements input");
$create.change(function () {
$create_options.prop('checked', $(this).prop("checked"));
});
$create_options.change(function () {
if ($create_options.is(":checked")) {
$create.prop('checked', true);
}
});
/**
* Disables the view output as text option if the output must be saved as a file

View File

@ -4036,7 +4036,7 @@ function PMA_init_slider()
var $wrapper = $('<div>', {'class': 'slide-wrapper'});
$wrapper.toggle($this.is(':visible'));
$('<a>', {href: '#' + this.id, "class": 'ajax'})
.text(this.title)
.text($this.attr('title'))
.prepend($('<span>'))
.insertBefore($this)
.click(function () {
@ -4053,6 +4053,7 @@ function PMA_init_slider()
return false;
});
$this.wrap($wrapper);
$this.removeAttr('title');
PMA_set_status_label($this);
$this.data('slider_init_done', 1);
});

View File

@ -534,6 +534,7 @@ AJAX.registerOnload('normalization.js', function() {
"db": PMA_commonParams.get('db'),
"table": PMA_commonParams.get('table'),
"dropped_column": selectedCol,
"purge" : 1,
"sql_query": 'ALTER TABLE `' + PMA_commonParams.get('table') + '` DROP `' + selectedCol + '`;',
"is_js_confirmed": 1
},

View File

@ -162,7 +162,7 @@ function verificationsAfterFieldChange(urlField, multi_edit, theType)
{
var evt = window.event || arguments.callee.caller.arguments[0];
var target = evt.target || evt.srcElement;
var $this_input = $("input[name='fields[multi_edit][" + multi_edit + "][" +
var $this_input = $(":input[name^='fields[multi_edit][" + multi_edit + "][" +
urlField + "]']");
// the function drop-down that corresponds to this input field
var $this_function = $("select[name='funcs[multi_edit][" + multi_edit + "][" +
@ -172,12 +172,6 @@ function verificationsAfterFieldChange(urlField, multi_edit, theType)
function_selected = true;
}
// check if it is textarea rather than input
if ($this_input.length === 0) {
$this_input = $("textarea[name='fields[multi_edit][" + multi_edit + "][" +
urlField + "]']");
}
//To generate the textbox that can take the salt
var new_salt_box = "<br><input type=text name=salt[multi_edit][" + multi_edit + "][" + urlField + "]" +
" id=salt_" + target.id + " placeholder='" + PMA_messages.strEncryptionKey + "'>";

View File

@ -14,8 +14,8 @@ var defaultX = 0;
var defaultY = 0;
// Variables
var x;
var y;
var x = 0;
var y = 0;
var scale = 1;
var svg;

View File

@ -27,7 +27,10 @@ AJAX.registerOnload('tbl_operations.js', function () {
$.post($form.attr('action'), $form.serialize() + "&submit_copy=Go", function (data) {
if (typeof data !== 'undefined' && data.success === true) {
if ($form.find("input[name='switch_to_new']").prop('checked')) {
PMA_commonParams.set('db', data.db);
PMA_commonParams.set(
'db',
$form.find("select[name='target_db']").val()
);
PMA_commonParams.set(
'table',
$form.find("input[name='new_name']").val()

View File

@ -92,6 +92,13 @@ AJAX.registerOnload('tbl_select.js', function () {
"!= ''"
];
var geomUnaryFunctions = [
'IsEmpty',
'IsSimple',
'IsRing',
'IsClosed',
];
// jQuery object to reuse
var $search_form = $(this);
event.preventDefault();
@ -120,6 +127,11 @@ AJAX.registerOnload('tbl_select.js', function () {
continue;
}
if (values['geom_func[' + a + ']'] &&
$.isArray(values['geom_func[' + a + ']'], geomUnaryFunctions) >= 0) {
continue;
}
if (values['criteriaValues[' + a + ']'] === '' || values['criteriaValues[' + a + ']'] === null) {
delete values['criteriaValues[' + a + ']'];
delete values['criteriaColumnOperators[' + a + ']'];

View File

@ -85,6 +85,7 @@ AJAX.registerTeardown('tbl_structure.js', function () {
$(document).off('click', "#printView");
$(document).off('submit', ".append_fields_form.ajax");
$('body').off('click', '#fieldsForm.ajax button[name="submit_mult"], #fieldsForm.ajax input[name="submit_mult"]');
$(document).off('click', 'a[name^=partition_action].ajax');
});
AJAX.registerOnload('tbl_structure.js', function () {
@ -432,6 +433,35 @@ AJAX.registerOnload('tbl_structure.js', function () {
AJAX.source = $form;
$.post($form.attr('action'), submitData, AJAX.responseHandler);
});
/**
* Handles clicks on Action links in partition table
*/
$(document).on('click', 'a[name^=partition_action].ajax', function (e) {
e.preventDefault();
var $link = $(this);
function submitPartitionAction(url) {
var submitData = '&ajax_request=true&ajax_page_request=true';
PMA_ajaxShowMessage();
AJAX.source = $link;
$.post(url, submitData, AJAX.responseHandler);
}
if ($link.is('#partition_action_DROP')) {
var question = PMA_messages.strDropPartitionWarning;
$link.PMA_confirm(question, $link.attr('href'), function (url) {
submitPartitionAction(url);
});
} else if ($link.is('#partition_action_TRUNCATE')) {
var question = PMA_messages.strTruncatePartitionWarning;
$link.PMA_confirm(question, $link.attr('href'), function (url) {
submitPartitionAction(url);
});
} else {
submitPartitionAction($link.attr('href'));
}
});
});
/** Handler for "More" dropdown in structure table rows */

View File

@ -1371,8 +1371,10 @@ class PMA_Config
// Add hostname
$pma_absolute_uri .= $url['host'];
// Add port, if it not the default one
// (or 80 for https which is most likely a bug)
if (! empty($url['port'])
&& (($url['scheme'] == 'http' && $url['port'] != 80)
|| ($url['scheme'] == 'https' && $url['port'] != 80)
|| ($url['scheme'] == 'https' && $url['port'] != 443))
) {
$pma_absolute_uri .= ':' . $url['port'];

View File

@ -3161,7 +3161,9 @@ class PMA_DisplayResults
$display_params = $this->__get('display_params');
if ($meta->numeric == 1) {
// in some situations (issue 11406), numeric returns 1
// even for a string type
if ($meta->numeric == 1 && $meta->type != 'string') {
// n u m e r i c
$display_params['data'][$row_no][$i]
@ -3728,7 +3730,7 @@ class PMA_DisplayResults
/**
* Prepare data cell for numeric type fields
*
* @param string $column the relevant column in data row
* @param string $column the column's value
* @param string $class the html class for column
* @param boolean $condition_field the column should highlighted
* or not

View File

@ -165,8 +165,8 @@ class PMA_Menu
private function _getBreadcrumbs()
{
$retval = '';
$table = new PMA_Table($this->_table, $this->_db);
$tbl_is_view = $table->isView();
$tbl_is_view = $GLOBALS['dbi']->getTable($this->_db, $this->_table)
->isView();
$server_info = ! empty($GLOBALS['cfg']['Server']['verbose'])
? $GLOBALS['cfg']['Server']['verbose']
: $GLOBALS['cfg']['Server']['host'];
@ -299,8 +299,8 @@ class PMA_Menu
private function _getTableTabs()
{
$db_is_system_schema = $GLOBALS['dbi']->isSystemSchema($this->_db);
$table = new PMA_Table($this->_table, $this->_db);
$tbl_is_view = $table->isView();
$tbl_is_view = $GLOBALS['dbi']->getTable($this->_db, $this->_table)
->isView();
$is_superuser = $GLOBALS['dbi']->isSuperuser();
$isCreateOrGrantUser = $GLOBALS['dbi']->isUserType('grant')
|| $GLOBALS['dbi']->isUserType('create');

View File

@ -9,13 +9,351 @@ if (! defined('PHPMYADMIN')) {
exit;
}
/**
* Represents a sub partition of a table
*
* @package PhpMyAdmin
*/
class PMA_SubPartition
{
/**
* @var string the database
*/
protected $db;
/**
* @var string the table
*/
protected $table;
/**
* @var string partition name
*/
protected $name;
/**
* @var integer ordinal
*/
protected $ordinal;
/**
* @var string partition method
*/
protected $method;
/**
* @var string partition expression
*/
protected $expression;
/**
* @var integer no of table rows in the partition
*/
protected $rows;
/**
* @var integer data length
*/
protected $dataLength;
/**
* @var integer index length
*/
protected $indexLength;
/**
* @var string partition comment
*/
protected $comment;
/**
* Constructs a partition
*
* @param array $row fetched row from information_schema.PARTITIONS
*/
public function __construct($row)
{
$this->db = $row['TABLE_SCHEMA'];
$this->table = $row['TABLE_NAME'];
$this->loadData($row);
}
/**
* Loads data from the fetched row from information_schema.PARTITIONS
*
* @param array $row fetched row
*
* @return void
*/
protected function loadData($row)
{
$this->name = $row['SUBPARTITION_NAME'];
$this->ordinal = $row['SUBPARTITION_ORDINAL_POSITION'];
$this->method = $row['SUBPARTITION_METHOD'];
$this->expression = $row['SUBPARTITION_EXPRESSION'];
$this->loadCommonData($row);
}
/**
* Loads some data that is common to both partitions and sub partitions
*
* @param array $row fetched row
*
* @return void
*/
protected function loadCommonData($row)
{
$this->rows = $row['TABLE_ROWS'];
$this->dataLength = $row['DATA_LENGTH'];
$this->indexLength = $row['INDEX_LENGTH'];
$this->comment = $row['PARTITION_COMMENT'];
}
/**
* Return the partition name
*
* @return string partition name
*/
public function getName()
{
return $this->name;
}
/**
* Return the ordinal of the partition
*
* @return number the ordinal
*/
public function getOrdinal()
{
return $this->ordinal;
}
/**
* Returns the partition method
*
* @return string partition method
*/
public function getMethod()
{
return $this->method;
}
/**
* Returns the partition expression
*
* @return string partition expression
*/
public function getExpression()
{
return $this->expression;
}
/**
* Returns the number of data rows
*
* @return integer number of rows
*/
public function getRows()
{
return $this->rows;
}
/**
* Returns the data length
*
* @return integer data length
*/
public function getDataLength()
{
return $this->dataLength;
}
/**
* Returns the index length
*
* @return integer index length
*/
public function getIndexLength()
{
return $this->indexLength;
}
/**
* Returns the partition comment
*
* @return string partition comment
*/
public function getComment()
{
return $this->comment;
}
}
/**
* base Partition Class
*
* @package PhpMyAdmin
*/
class PMA_Partition
class PMA_Partition extends PMA_SubPartition
{
/**
* @var string partition description
*/
protected $description;
/**
* @var PMA_SubPartition[] sub partitions
*/
protected $subPartitions = array();
/**
* Loads data from the fetched row from information_schema.PARTITIONS
*
* @param array $row fetched row
*
* @return void
*/
protected function loadData($row)
{
$this->name = $row['PARTITION_NAME'];
$this->ordinal = $row['PARTITION_ORDINAL_POSITION'];
$this->method = $row['PARTITION_METHOD'];
$this->expression = $row['PARTITION_EXPRESSION'];
$this->description = $row['PARTITION_DESCRIPTION'];
// no sub partitions, load all data to this object
if (empty($row['SUBPARTITION_NAME'])) {
$this->loadCommonData($row);
}
}
/**
* Returns the partiotion description
*
* @return string partition description
*/
public function getDescription()
{
return $this->description;
}
/**
* Add a sub partition
*
* @param PMA_SubPartition $partition
*
* @return void
*/
public function addSubPartition(PMA_SubPartition $partition)
{
$this->subPartitions[] = $partition;
}
/**
* Whether there are sub partitions
*
* @return boolean
*/
public function hasSubPartitions()
{
return ! empty($this->subPartitions);
}
/**
* Returns the number of data rows
*
* @return integer number of rows
*/
public function getRows()
{
if (empty($this->subPartitions)) {
return $this->rows;
} else {
$rows = 0;
foreach ($this->subPartitions as $subPartition) {
$rows += $subPartition->rows;
}
return $rows;
}
}
/**
* Returns the total data length
*
* @return integer data length
*/
public function getDataLength()
{
if (empty($this->subPartitions)) {
return $this->dataLength;
} else {
$dataLength = 0;
foreach ($this->subPartitions as $subPartition) {
$dataLength += $subPartition->dataLength;
}
return $dataLength;
}
}
/**
* Returns the tatal index length
*
* @return integer index length
*/
public function getIndexLength()
{
if (empty($this->subPartitions)) {
return $this->indexLength;
} else {
$indexLength = 0;
foreach ($this->subPartitions as $subPartition) {
$indexLength += $subPartition->indexLength;
}
return $indexLength;
}
}
/**
* Returns the list of sub partitions
*
* @return PMA_SubPartition[]
*/
public function getSubPartitions()
{
return $this->subPartitions;
}
/**
* Returns array of partitions for a specific db/table
*
* @param string $db database name
* @param string $table table name
*
* @access public
* @return PMA_Partition[]
*/
static public function getPartitions($db, $table)
{
if (PMA_Partition::havePartitioning()) {
$result = $GLOBALS['dbi']->fetchResult(
"SELECT * FROM `information_schema`.`PARTITIONS`"
. " WHERE `TABLE_SCHEMA` = '" . PMA_Util::sqlAddSlashes($db)
. "' AND `TABLE_NAME` = '" . PMA_Util::sqlAddSlashes($table) . "'"
);
if ($result) {
$partitionMap = array();
foreach ($result as $row) {
if (isset($partitionMap[$row['PARTITION_NAME']])) {
$partition = $partitionMap[$row['PARTITION_NAME']];
} else {
$partition = new PMA_Partition($row);
$partitionMap[$row['PARTITION_NAME']] = $partition;
}
if (! empty($row['SUBPARTITION_NAME'])) {
$parentPartition = $partition;
$partition = new PMA_SubPartition($row);
$parentPartition->addSubPartition($partition);
}
}
return array_values($partitionMap);
}
return array();
} else {
return array();
}
}
/**
* returns array of partition names for a specific db/table
*

View File

@ -2363,7 +2363,7 @@ class PMA_Table
'SELECT COUNT(*) AS %s FROM %s.%s',
PMA_Util::backquote('row_count'),
PMA_Util::backquote($this->_db_name),
PMA_Util::backquote($$this->_name)
PMA_Util::backquote($this->_name)
)
);
return $result['row_count'];

View File

@ -1757,21 +1757,27 @@ class PMA_Util
}
//Set the id for the tab, if set in the params
$id_string = ( empty($tab['id']) ? '' : ' id="' . $tab['id'] . '" ' );
$out = '<li' . ($tab['class'] == 'active' ? ' class="active"' : '') . '>';
$tabId = (empty($tab['id']) ? null : $tab['id']);
if (! empty($tab['link'])) {
$out .= '<a class="tab' . htmlentities($tab['class']) . '"'
. $id_string
. ' href="' . $tab['link'] . '" ' . $tab['attr'] . '>'
. $tab['text'] . '</a>';
$item = array();
if (!empty($tab['link'])) {
$item = array(
'content' => $tab['text'],
'url' => array(
'href' => empty($tab['link']) ? null : $tab['link'],
'id' => $tabId,
'class' => 'tab' . htmlentities($tab['class']),
),
);
} else {
$out .= '<span class="tab' . htmlentities($tab['class']) . '"'
. $id_string . '>' . $tab['text'] . '</span>';
$item['content'] = '<span class="tab' . htmlentities($tab['class']) . '"'
. $tabId . '>' . $tab['text'] . '</span>';
}
$out .= '</li>';
return $out;
$item['class'] = $tab['class'] == 'active' ? 'active' : '';
return Template::get('list/item')
->render($item);
} // end of the 'getHtmlTab()' function
/**

View File

@ -42,8 +42,8 @@ if (getcwd() == dirname(__FILE__)) {
* Minimum PHP version; can't call PMA_fatalError() which uses a
* PHP 5 function, so cannot easily localize this message.
*/
if (version_compare(PHP_VERSION, '5.3.0', 'lt')) {
die('PHP 5.3+ is required');
if (version_compare(PHP_VERSION, '5.5.0', 'lt')) {
die('PHP 5.5+ is required');
}
/**

View File

@ -1965,7 +1965,7 @@ $cfg['Export']['sql_drop_table'] = false;
* of VIEWs and the stand-in table
* @global boolean $cfg['Export']['sql_if_not_exists']
*/
$cfg['Export']['sql_if_not_exists'] = true;
$cfg['Export']['sql_if_not_exists'] = false;
/**
*
@ -2086,13 +2086,6 @@ $cfg['Export']['sql_mime'] = false;
*/
$cfg['Export']['sql_header_comment'] = '';
/**
*
*
* @global boolean $cfg['Export']['sql_create_table_statements']
*/
$cfg['Export']['sql_create_table_statements'] = true;
/**
* Whether to use complete inserts, extended inserts, both, or neither
*
@ -3149,5 +3142,3 @@ $cfg['MysqlMinVersion'] = array(
'internal' => 50500,
'human' => '5.5.0'
);

View File

@ -50,12 +50,23 @@ function PMA_displayFormTop($action = null, $method = 'post', $hidden_fields = n
*/
function PMA_displayTabsTop($tabs)
{
$htmlOutput = '<ul class="tabs">';
$items = array();
foreach ($tabs as $tab_id => $tab_name) {
$htmlOutput .= '<li><a href="#' . $tab_id . '">'
. htmlspecialchars($tab_name) . '</a></li>';
$items[] = array(
'content' => htmlspecialchars($tab_name),
'url' => array(
'href' => '#' . $tab_id,
),
);
}
$htmlOutput .= '</ul>';
include_once './libraries/Template.class.php';
$htmlOutput = PMA\Template::get('list/unordered')->render(
array(
'class' => 'tabs',
'items' => $items,
)
);
$htmlOutput .= '<br clear="right" />';
$htmlOutput .= '<div class="tabs_contents">';
return $htmlOutput;

View File

@ -187,8 +187,6 @@ $strConfigExport_sql_auto_increment_name = __('Add AUTO_INCREMENT value');
$strConfigExport_sql_backquotes_name
= __('Enclose table and column names with backquotes');
$strConfigExport_sql_compatibility_name = __('SQL compatibility mode');
$strConfigExport_sql_create_table_statements_name
= __('<code>CREATE TABLE</code> options:');
$strConfigExport_sql_dates_name = __('Creation/Update/Check dates');
$strConfigExport_sql_delayed_name = __('Use delayed inserts');
$strConfigExport_sql_disable_fk_name = __('Disable foreign key checks');
@ -205,7 +203,10 @@ $strConfigExport_sql_create_view_name = sprintf(__('Add %s'), 'CREATE VIEW');
$strConfigExport_sql_create_trigger_name
= sprintf(__('Add %s'), 'CREATE TRIGGER');
$strConfigExport_sql_hex_for_binary_name = __('Use hexadecimal for BINARY & BLOB');
$strConfigExport_sql_if_not_exists_name = sprintf(__('Add %s'), 'IF NOT EXISTS');
$strConfigExport_sql_if_not_exists_name = __(
'Add IF NOT EXISTS (less efficient as indexes will be generated during'
. ' table creation)'
);
$strConfigExport_sql_ignore_name = __('Use ignore inserts');
$strConfigExport_sql_include_comments_name = __('Comments');
$strConfigExport_sql_insert_syntax_name = __('Syntax to use when inserting data');
@ -1000,4 +1001,3 @@ $strConfigZeroConf_desc = __(
. 'configuration storage tables automatically.'
);
$strConfigZeroConf_name = __('Enable Zero Configuration mode');

View File

@ -323,13 +323,12 @@ $forms['Export']['Sql'] = array('Export' => array(
':group:' . __('Structure'),
'sql_drop_table',
'sql_procedure_function',
'sql_create_table',
'sql_create_view',
'sql_create_trigger',
'sql_create_table_statements' => ':group',
'sql_create_table' => ':group',
'sql_if_not_exists',
'sql_auto_increment',
':group:end',
'sql_create_view',
'sql_create_trigger',
'sql_backquotes',
':group:end',
':group:' . __('Data'),

View File

@ -220,14 +220,13 @@ $forms['Export']['Sql'] = array(
':group:end',
':group:' . __('Structure'),
'Export/sql_drop_table',
'Export/sql_create_table',
'Export/sql_create_view',
'Export/sql_procedure_function',
'Export/sql_create_trigger',
'Export/sql_create_table_statements' => ':group',
'Export/sql_create_table' => ':group',
'Export/sql_if_not_exists',
'Export/sql_auto_increment',
':group:end',
'Export/sql_create_view',
'Export/sql_procedure_function',
'Export/sql_create_trigger',
'Export/sql_backquotes',
':group:end',
':group:' . __('Data'),

View File

@ -0,0 +1,39 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Holds the PMA\DatabaseController
*
* @package PMA
*/
namespace PMA\Controllers;
use PMA\DI\Container;
if (!defined('PHPMYADMIN')) {
exit;
}
require_once 'libraries/controllers/Controller.class.php';
/**
* Handles database related logic
*
* @package PhpMyAdmin
*/
abstract class DatabaseController extends Controller
{
/**
* @var string $db
*/
protected $db;
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->db = $this->container->get('db');
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -166,7 +166,7 @@ class TableChartController extends TableController
* Displays the page
*/
$this->response->addHTML(
Template::get('tbl_chart')->render(
Template::get('table/chart/tbl_chart')->render(
array(
'url_query' => $this->url_query,
'url_params' => $url_params,

View File

@ -124,7 +124,9 @@ class TableGisVisualizationController extends TableController
$this->visualizationSettings = $_REQUEST['visualizationSettings'];
}
if (! isset($this->visualizationSettings['labelColumn']) && isset($labelCandidates[0])) {
if (!isset($this->visualizationSettings['labelColumn'])
&& isset($labelCandidates[0])
) {
$this->visualizationSettings['labelColumn'] = '';
}
@ -134,7 +136,8 @@ class TableGisVisualizationController extends TableController
}
// Convert geometric columns from bytes to text.
$pos = isset($_REQUEST['pos']) ? $_REQUEST['pos'] : $_SESSION['tmpval']['pos'];
$pos = isset($_REQUEST['pos']) ? $_REQUEST['pos']
: $_SESSION['tmpval']['pos'];
if (isset($_REQUEST['session_max_rows'])) {
$rows = $_REQUEST['session_max_rows'];
} else {
@ -186,11 +189,12 @@ class TableGisVisualizationController extends TableController
* Displays the page
*/
$this->url_params['sql_query'] = $this->sql_query;
$downloadUrl = 'tbl_gis_visualization.php' . PMA_URL_getCommon($this->url_params)
. '&saveToFile=true';
$downloadUrl = 'tbl_gis_visualization.php' . PMA_URL_getCommon(
$this->url_params
) . '&saveToFile=true';
$svgSupport = (PMA_USR_BROWSER_AGENT == 'IE' && PMA_USR_BROWSER_VER <= 8)
? false : true;
$html = Template::get('gis_visualization/gis_visualization')->render(
$html = Template::get('table/gis_visualization/gis_visualization')->render(
array(
'url_params' => $this->url_params,
'downloadUrl' => $downloadUrl,
@ -198,7 +202,9 @@ class TableGisVisualizationController extends TableController
'spatialCandidates' => $spatialCandidates,
'visualizationSettings' => $this->visualizationSettings,
'sql_query' => $this->sql_query,
'visualization' => $this->visualization->toImage($svgSupport ? 'svg' : 'png'),
'visualization' => $this->visualization->toImage(
$svgSupport ? 'svg' : 'png'
),
'svgSupport' => $svgSupport,
'drawOl' => $this->visualization->asOl()
)

View File

@ -116,7 +116,7 @@ class TableIndexesController extends TableController
$this->response->getHeader()->getScripts()->addFile('indexes.js');
$this->response->addHTML(
Template::get('index_form')->render(
Template::get('table/index_form')->render(
array(
'fields' => $fields,
'index' => $this->index,

View File

@ -156,9 +156,10 @@ class TableRelationController extends TableController
}
// display secondary level tabs if necessary
$engine = $this->dbi->getTable($this->db, $this->table)->sGetStatusInfo('ENGINE');
$engine = $this->dbi->getTable($this->db, $this->table)
->sGetStatusInfo('ENGINE');
$this->response->addHTML(
Template::get('structure/secondary_tabs')->render(
Template::get('table/secondary_tabs')->render(
array(
'url_params' => array(
'db' => $GLOBALS['db'],
@ -180,7 +181,7 @@ class TableRelationController extends TableController
// common form
$this->response->addHTML(
Template::get('tbl_relation/common_form')->render(
Template::get('table/relation/common_form')->render(
array(
'db' => $this->db,
'table' => $this->table,
@ -274,8 +275,12 @@ class TableRelationController extends TableController
: null;
if ($this->upd_query->updateInternalRelations(
$multi_edit_columns_name, $_POST['destination_db'], $_POST['destination_table'],
$_POST['destination_column'], $this->cfgRelation, isset($this->existrel) ? $this->existrel : null
$multi_edit_columns_name,
$_POST['destination_db'],
$_POST['destination_table'],
$_POST['destination_column'],
$this->cfgRelation,
isset($this->existrel) ? $this->existrel : null
)
) {
$this->response->addHTML(
@ -297,8 +302,9 @@ class TableRelationController extends TableController
{
$foreignTable = $_REQUEST['foreignTable'];
$table_obj = new PMA_Table($foreignTable, $_REQUEST['foreignDb']);
// Since views do not have keys defined on them provide the full list of columns
if ($GLOBALS['dbi']->getTable($_REQUEST['foreignDb'], $foreignTable)->isView()) {
// Since views do not have keys defined on them provide the full list of
// columns
if ($table_obj->isView()) {
$columnList = $table_obj->getColumns(false, false);
} else {
$columnList = $table_obj->getIndexedColumns(false, false);

View File

@ -187,7 +187,7 @@ class TableSearchController extends TableController
// Show secondary level of tabs
$this->response->addHTML(
Template::get('table/secondary_tabs')
Template::get('secondary_tabs')
->render(
array(
'url_params' => array(
@ -214,7 +214,7 @@ class TableSearchController extends TableController
$err_url = $goto . '?' . PMA_URL_getCommon($params);
// Displays the find and replace form
$this->response->addHTML(
Template::get('table/selection_form')
Template::get('table/search/selection_form')
->render(
array(
'searchType' => $this->_searchType,
@ -336,7 +336,7 @@ class TableSearchController extends TableController
// Displays the zoom search form
$this->response->addHTML(
Template::get('table/secondary_tabs')
Template::get('secondary_tabs')
->render(
array(
'url_params' => array(
@ -348,7 +348,7 @@ class TableSearchController extends TableController
)
);
$this->response->addHTML(
Template::get('table/selection_form')
Template::get('table/search/selection_form')
->render(
array(
'searchType' => $this->_searchType,
@ -440,7 +440,7 @@ class TableSearchController extends TableController
)
);
$this->response->addHTML(
Template::get('table/zoom_result_form')
Template::get('table/search/zoom_result_form')
->render(
array(
'_db' => $this->db,
@ -578,7 +578,7 @@ class TableSearchController extends TableController
);
// Displays the table search form
$this->response->addHTML(
Template::get('table/secondary_tabs')
Template::get('secondary_tabs')
->render(
array(
'url_params' => array(
@ -590,7 +590,7 @@ class TableSearchController extends TableController
)
);
$this->response->addHTML(
Template::get('table/selection_form')
Template::get('table/search/selection_form')
->render(
array(
'searchType' => $this->_searchType,
@ -698,7 +698,7 @@ class TableSearchController extends TableController
$result = $this->dbi->fetchResult($sql_query, 0);
}
return Template::get('table/replace_preview')->render(
return Template::get('table/search/replace_preview')->render(
array(
'db' => $this->db,
'table' => $this->table,
@ -920,7 +920,7 @@ class TableSearchController extends TableController
$type = $this->_columnTypes[$column_index];
$collation = $this->_columnCollations[$column_index];
//Gets column's comparison operators depending on column type
$func = Template::get('table/column_comparison_operators')->render(
$func = Template::get('table/search/column_comparison_operators')->render(
array(
'search_index' => $search_index,
'columnTypes' => $this->_columnTypes,
@ -933,7 +933,7 @@ class TableSearchController extends TableController
$foreignData = PMA_getForeignData(
$this->_foreigners, $this->_columnNames[$column_index], false, '', ''
);
$value = Template::get('table/input_box')->render(
$value = Template::get('table/search/input_box')->render(
array(
'str' => '',
'column_type' => (string) $type,
@ -948,7 +948,7 @@ class TableSearchController extends TableController
'criteriaValues' => $entered_value,
'db' => $this->db,
'titles' => $titles,
'in_fbs' => false
'in_fbs' => true
)
);
return array(
@ -976,6 +976,7 @@ class TableSearchController extends TableController
// return
if (! isset($_POST['criteriaValues'])
&& ! isset($_POST['criteriaColumnOperators'])
&& ! isset($_POST['geom_func'])
) {
return '';
}
@ -988,8 +989,8 @@ class TableSearchController extends TableController
)) {
$unaryFlag = $GLOBALS['PMA_Types']->isUnaryOperator($operator);
$tmp_geom_func = isset($geom_func[$column_index])
? $geom_func[$column_index] : null;
$tmp_geom_func = isset($_POST['geom_func'][$column_index])
? $_POST['geom_func'][$column_index] : null;
$whereClause = $this->_getWhereClause(
$_POST['criteriaValues'][$column_index],
@ -1074,33 +1075,37 @@ class TableSearchController extends TableController
// Get details about the geometry functions
$geom_funcs = PMA_Util::getGISFunctions($types, true, false);
// New output type is the output type of the function being applied
$types = $geom_funcs[$geom_func]['type'];
// If the function takes a single parameter
if ($geom_funcs[$geom_func]['params'] == 1) {
$backquoted_name = $geom_func . '(' . PMA_Util::backquote($names) . ')';
} else {
// If the function takes two parameters
// If the function takes multiple parameters
if ($geom_funcs[$geom_func]['params'] > 1) {
// create gis data from the criteria input
$gis_data = PMA_Util::createGISData($criteriaValues);
$where = $geom_func . '(' . PMA_Util::backquote($names)
. ',' . $gis_data . ')';
. ', ' . $gis_data . ')';
return $where;
}
// New output type is the output type of the function being applied
$type = $geom_funcs[$geom_func]['type'];
$geom_function_applied = $geom_func
. '(' . PMA_Util::backquote($names) . ')';
// If the where clause is something like 'IsEmpty(`spatial_col_name`)'
if (isset($geom_unary_functions[$geom_func])
&& trim($criteriaValues) == ''
) {
$where = $backquoted_name;
$where = $geom_function_applied;
} elseif (in_array($types, PMA_Util::getGISDatatypes())
} elseif (in_array($type, PMA_Util::getGISDatatypes())
&& ! empty($criteriaValues)
) {
// create gis data from the criteria input
$gis_data = PMA_Util::createGISData($criteriaValues);
$where = $backquoted_name . ' ' . $func_type . ' ' . $gis_data;
$where = $geom_function_applied . " " . $func_type . " " . $gis_data;
} elseif (/*overload*/mb_strlen($criteriaValues) > 0) {
$where = $geom_function_applied . " "
. $func_type . " '" . $criteriaValues . "'";
}
return $where;
}
@ -1121,7 +1126,7 @@ class TableSearchController extends TableController
$func_type, $unaryFlag, $geom_func = null
) {
// If geometry function is set
if ($geom_func != null && trim($geom_func) != '') {
if (! empty($geom_func)) {
return $this->_getGeomWhereClause(
$criteriaValues, $names, $func_type, $types, $geom_func
);

File diff suppressed because it is too large Load Diff

View File

@ -17,6 +17,7 @@ require_once './libraries/bookmark.lib.php';
PMA_Util::checkParameters(array('db'));
global $cfg;
global $db;
$is_show_stats = $cfg['ShowStats'];

View File

@ -22,7 +22,7 @@ require_once 'libraries/Template.class.php';
*/
function PMA_getHtmlForPageSelector($cfgRelation, $db)
{
return PMA\Template::get('designer/page_selector')
return PMA\Template::get('database/designer/page_selector')
->render(
array(
'db' => $db,
@ -41,7 +41,7 @@ function PMA_getHtmlForPageSelector($cfgRelation, $db)
*/
function PMA_getHtmlForEditOrDeletePages($db, $operation)
{
return PMA\Template::get('designer/edit_delete_pages')
return PMA\Template::get('database/designer/edit_delete_pages')
->render(
array(
'db' => $db,
@ -59,7 +59,7 @@ function PMA_getHtmlForEditOrDeletePages($db, $operation)
*/
function PMA_getHtmlForPageSaveAs($db)
{
return PMA\Template::get('designer/page_save_as')
return PMA\Template::get('database/designer/page_save_as')
->render(
array(
'db' => $db
@ -118,7 +118,7 @@ function PMA_getHtmlForSchemaExport($db, $page)
)->getDisplay();
}
return PMA\Template::get('designer/schema_export')
return PMA\Template::get('database/designer/schema_export')
->render(
array(
'db' => $db,
@ -141,7 +141,7 @@ function PMA_getHtmlForSchemaExport($db, $page)
function PMA_getHtmlForJSFields(
$script_tables, $script_contr, $script_display_field, $display_page
) {
return PMA\Template::get('designer/js_fields')
return PMA\Template::get('database/designer/js_fields')
->render(
array(
'script_tables' => $script_tables,
@ -163,7 +163,7 @@ function PMA_getHtmlForJSFields(
*/
function PMA_getDesignerPageMenu($visualBuilder, $selected_page, $params_array)
{
return PMA\Template::get('designer/side_menu')
return PMA\Template::get('database/designer/side_menu')
->render(
array(
'visualBuilder' => $visualBuilder,
@ -267,7 +267,7 @@ function PMA_returnClassNamesFromMenuButtons()
*/
function PMA_getHTMLCanvas()
{
return PMA\Template::get('designer/canvas')->render();
return PMA\Template::get('database/designer/canvas')->render();
}
/**
@ -280,7 +280,7 @@ function PMA_getHTMLCanvas()
*/
function PMA_getHTMLTableList($tab_pos, $display_page)
{
return PMA\Template::get('designer/table_list')
return PMA\Template::get('database/designer/table_list')
->render(
array(
'tab_pos' => $tab_pos,
@ -303,7 +303,7 @@ function PMA_getHTMLTableList($tab_pos, $display_page)
function PMA_getDatabaseTables(
$tab_pos, $display_page, $tab_column, $tables_all_keys, $tables_pk_or_unique_keys
) {
return PMA\Template::get('designer/database_tables')
return PMA\Template::get('database/designer/database_tables')
->render(
array(
'tab_pos' => $tab_pos,
@ -322,7 +322,7 @@ function PMA_getDatabaseTables(
*/
function PMA_getNewRelationPanel()
{
return PMA\Template::get('designer/new_relation_panel')->render();
return PMA\Template::get('database/designer/new_relation_panel')->render();
}
/**
@ -332,7 +332,7 @@ function PMA_getNewRelationPanel()
*/
function PMA_getDeleteRelationPanel()
{
return PMA\Template::get('designer/delete_relation_panel')->render();
return PMA\Template::get('database/designer/delete_relation_panel')->render();
}
/**
@ -342,7 +342,7 @@ function PMA_getDeleteRelationPanel()
*/
function PMA_getOptionsPanel()
{
return PMA\Template::get('designer/options_panel')->render();
return PMA\Template::get('database/designer/options_panel')->render();
}
/**
@ -352,7 +352,7 @@ function PMA_getOptionsPanel()
*/
function PMA_getRenameToPanel()
{
return PMA\Template::get('designer/rename_to_panel')->render();
return PMA\Template::get('database/designer/rename_to_panel')->render();
}
/**
@ -362,7 +362,7 @@ function PMA_getRenameToPanel()
*/
function PMA_getHavingQueryPanel()
{
return PMA\Template::get('designer/having_query_panel')->render();
return PMA\Template::get('database/designer/having_query_panel')->render();
}
/**
@ -372,7 +372,7 @@ function PMA_getHavingQueryPanel()
*/
function PMA_getAggregateQueryPanel()
{
return PMA\Template::get('designer/aggregate_query_panel')->render();
return PMA\Template::get('database/designer/aggregate_query_panel')->render();
}
/**
@ -382,7 +382,7 @@ function PMA_getAggregateQueryPanel()
*/
function PMA_getWhereQueryPanel()
{
return PMA\Template::get('designer/where_query_panel')->render();
return PMA\Template::get('database/designer/where_query_panel')->render();
}
/**
@ -392,5 +392,5 @@ function PMA_getWhereQueryPanel()
*/
function PMA_getQueryDetails()
{
return PMA\Template::get('designer/query_details')->render();
return PMA\Template::get('database/designer/query_details')->render();
}

View File

@ -16,6 +16,7 @@ if (! defined('PHPMYADMIN')) {
}
global $cfg;
global $db;
/**
* limits for table list

View File

@ -639,6 +639,10 @@ $GLOBALS['dummy_queries'] = array(
array(
'query' => "SHOW TABLE STATUS FROM `db` WHERE `Name` LIKE 'table%'",
'result' => array()
),
array(
'query' => "SHOW VARIABLES LIKE 'have_partitioning'",
'result' => array()
)
);
/**

View File

@ -43,7 +43,7 @@ require_once 'libraries/Template.class.php';
*/
function PMA_getHtmlForCreateTable($db)
{
return PMA\Template::get('table/create_table')->render(
return PMA\Template::get('database/create_table')->render(
array('db' => $db)
);
}

View File

@ -1,64 +0,0 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* include file for display import : server, database, table
*
* @package PhpMyAdmin
*/
if (! defined('PHPMYADMIN')) {
exit;
}
/**
*
*/
require_once './libraries/file_listing.lib.php';
require_once './libraries/plugin_interface.lib.php';
require_once './libraries/display_import.lib.php';
require_once './libraries/display_import_ajax.lib.php';
/* Scan for plugins */
/* @var $import_list ImportPlugin[] */
$import_list = PMA_getPlugins(
"import",
'libraries/plugins/import/',
$import_type
);
/* Fail if we didn't find any plugin */
if (empty($import_list)) {
PMA_Message::error(
__(
'Could not load import plugins, please check your installation!'
)
)->display();
exit;
}
if (PMA_isValid($_REQUEST['offset'], 'numeric')) {
$offset = $_REQUEST['offset'];
}
if (isset($_REQUEST['timeout_passed'])) {
$timeout_passed = $_REQUEST['timeout_passed'];
}
if (isset($_REQUEST['local_import_file'])) {
$local_import_file = $_REQUEST['local_import_file'];
}
$timeout_passed_str = isset($timeout_passed)? $timeout_passed : null;
$offset_str = isset($offset)? $offset : null;
$html = PMA_getHtmlForImport(
$upload_id,
$import_type,
$db,
$table,
$max_upload_size,
$import_list,
$timeout_passed_str,
$offset_str
);
$response = PMA_Response::getInstance();
$response->addHTML($html);

View File

@ -210,13 +210,15 @@ function PMA_getHtmlForImportCharset()
/**
* Prints Html For Display Import options : file property
*
* @param int $max_upload_size Max upload size
* @param ImportPlugin[] $import_list import list
* @param int $max_upload_size Max upload size
* @param ImportPlugin[] $import_list import list
* @param String $local_import_file from upload directory
*
* @return string
*/
function PMA_getHtmlForImportOptionsFile($max_upload_size, $import_list)
{
function PMA_getHtmlForImportOptionsFile(
$max_upload_size, $import_list, $local_import_file
) {
global $cfg;
$html = ' <div class="importoptions">';
$html .= ' <h3>' . __('File to Import:') . '</h3>';
@ -235,7 +237,7 @@ function PMA_getHtmlForImportOptionsFile($max_upload_size, $import_list)
$html .= ' <input type="radio" name="file_location" '
. 'id="radio_local_import_file"';
if (! empty($GLOBALS['timeout_passed'])
&& ! empty($GLOBALS['local_import_file'])
&& ! empty($local_import_file)
) {
$html .= ' checked="checked"';
}
@ -398,20 +400,21 @@ function PMA_getHtmlForImportOptionsSubmit()
/**
* Prints Html For Display Import
*
* @param int $upload_id The selected upload id
* @param String $import_type Import type: server, database, table
* @param String $db Selected DB
* @param String $table Selected Table
* @param int $max_upload_size Max upload size
* @param ImportPlugin[] $import_list Import list
* @param String $timeout_passed Timeout passed
* @param String $offset Timeout offset
* @param int $upload_id The selected upload id
* @param String $import_type Import type: server, database, table
* @param String $db Selected DB
* @param String $table Selected Table
* @param int $max_upload_size Max upload size
* @param ImportPlugin[] $import_list Import list
* @param String $timeout_passed Timeout passed
* @param String $offset Timeout offset
* @param String $local_import_file from upload directory
*
* @return string
*/
function PMA_getHtmlForImport(
$upload_id, $import_type, $db, $table,
$max_upload_size, $import_list, $timeout_passed, $offset
$max_upload_size, $import_list, $timeout_passed, $offset, $local_import_file
) {
global $SESSION_KEY;
$html = '';
@ -440,7 +443,9 @@ function PMA_getHtmlForImport(
$html .= PMA_getHtmlForImportOptions($import_type, $db, $table);
$html .= PMA_getHtmlForImportOptionsFile($max_upload_size, $import_list);
$html .= PMA_getHtmlForImportOptionsFile(
$max_upload_size, $import_list, $local_import_file
);
$html .= PMA_getHtmlForImportOptionsPartialImport($timeout_passed, $offset);
@ -618,3 +623,65 @@ function PMA_getHtmlForImportWithPlugin($upload_id)
return $html;
}
/**
* Gets HTML to display import dialogs
*
* @param String $import_type Import type: server|database|table
* @param String $db Selected DB
* @param String $table Selected Table
* @param int $max_upload_size Max upload size
*
* @return string $html
*/
function PMA_getImportDisplay($import_type, $db, $table, $max_upload_size)
{
global $SESSION_KEY;
include_once './libraries/file_listing.lib.php';
include_once './libraries/plugin_interface.lib.php';
// this one generates also some globals
include_once './libraries/display_import_ajax.lib.php';
/* Scan for plugins */
/* @var $import_list ImportPlugin[] */
$import_list = PMA_getPlugins(
"import",
'libraries/plugins/import/',
$import_type
);
/* Fail if we didn't find any plugin */
if (empty($import_list)) {
PMA_Message::error(
__(
'Could not load import plugins, please check your installation!'
)
)->display();
exit;
}
if (PMA_isValid($_REQUEST['offset'], 'numeric')) {
$offset = $_REQUEST['offset'];
}
if (isset($_REQUEST['timeout_passed'])) {
$timeout_passed = $_REQUEST['timeout_passed'];
}
$local_import_file = '';
if (isset($_REQUEST['local_import_file'])) {
$local_import_file = $_REQUEST['local_import_file'];
}
$timeout_passed_str = isset($timeout_passed)? $timeout_passed : null;
$offset_str = isset($offset)? $offset : null;
return PMA_getHtmlForImport(
$upload_id,
$import_type,
$db,
$table,
$max_upload_size,
$import_list,
$timeout_passed_str,
$offset_str,
$local_import_file
);
}

View File

@ -27,7 +27,7 @@ if (is_readable('js/line_counts.php')) {
/**
* the url where to submit reports to
*/
define('SUBMISSION_URL', "http://reports.phpmyadmin.net/incidents/create");
define('SUBMISSION_URL', "https://reports.phpmyadmin.net/incidents/create");
/**
* returns the pretty printed error report data collected from the

View File

@ -740,6 +740,10 @@ function PMA_exportDatabase(
}
if (! $export_plugin->exportDBFooter($db)) {
return;
}
// export metadata related to this db
if (isset($GLOBALS['sql_metadata'])) {
// Types of metadata to export.
@ -752,9 +756,6 @@ function PMA_exportDatabase(
}
}
if (! $export_plugin->exportDBFooter($db)) {
return;
}
if ($separate_files == 'database') {
PMA_saveObjectInBuffer('extra');
}
@ -849,10 +850,9 @@ function PMA_exportTable(
// If this is an export of a single view, we have to export data;
// for example, a PDF report
// if it is a merge table, no data is exported
$table = new PMA_Table($table, $db);
if (($whatStrucOrData == 'data'
|| $whatStrucOrData == 'structure_and_data')
&& ! $table->isMerge()
&& ! $GLOBALS['dbi']->getTable($db, $table)->isMerge()
) {
if (! empty($sql_query)) {
// only preg_replace if needed

View File

@ -104,9 +104,7 @@ function PMA_importRunQuery($sql = '', $full = '', $controluser = false,
// USE query changes the database, son need to track
// while running multiple queries
$is_use_query
= (/*overload*/mb_stripos($import_run_buffer['sql'], "use ") !== false)
? true
: false;
= /*overload*/mb_stripos($import_run_buffer['sql'], "use ") !== false;
$max_sql_len = max(
$max_sql_len,

View File

@ -814,8 +814,6 @@ function PMA_getPmaTypeEnum($column, $backup_field, $column_name_appendix,
$column_enum_values = $column['values'];
$html_output .= '<input type="hidden" name="fields_type'
. $column_name_appendix . '" value="enum" />';
$html_output .= '<input type="hidden" name="fields'
. $column_name_appendix . '" value="" />';
$html_output .= "\n" . ' ' . $backup_field . "\n";
if (/*overload*/mb_strlen($column['Type']) > 20) {
$html_output .= PMA_getDropDownDependingOnLength(

View File

@ -87,7 +87,7 @@ if (! empty($submit_mult)
exit;
break;
case 'show_create':
$show_create = PMA\Template::get('structure/show_create')->render(
$show_create = PMA\Template::get('database/structure/show_create')->render(
array(
'db' => $GLOBALS['db'],
'db_objects' => $selected

View File

@ -78,7 +78,7 @@ class PMA_NavigationHeader
{
// display Logo, depending on $GLOBALS['cfg']['NavigationDisplayLogo']
if (!$GLOBALS['cfg']['NavigationDisplayLogo']) {
return Template::get('logo')
return Template::get('navigation/logo')
->render(array('displayLogo' => false));
}
@ -92,7 +92,7 @@ class PMA_NavigationHeader
}
if (!$GLOBALS['cfg']['NavigationLogoLink']) {
return Template::get('logo')
return Template::get('navigation/logo')
->render(
array(
'displayLogo' => true,
@ -130,7 +130,7 @@ class PMA_NavigationHeader
}
}
return Template::get('logo')
return Template::get('navigation/logo')
->render(
array(
'displayLogo' => true,

View File

@ -382,6 +382,9 @@ class Node_Database extends Node
{
$db = $this->real_name;
$cfgRelation = PMA_getRelationsParam();
if (empty($cfgRelation['navigationhiding'])) {
return array();
}
$navTable = PMA_Util::backquote($cfgRelation['db'])
. "." . PMA_Util::backquote($cfgRelation['navigationhiding']);
$sqlQuery = "SELECT `item_name` FROM " . $navTable

View File

@ -467,8 +467,7 @@ function PMA_copyTables($tables_full, $move, $db)
// do not copy the data from a Merge table
// note: on the calling FORM, 'data' means 'structure and data'
$table = new PMA_Table($each_table, $db);
if ($table->isMerge()) {
if ($GLOBALS['dbi']->getTable($db, $each_table)->isMerge()) {
if ($this_what == 'data') {
$this_what = 'structure';
}

View File

@ -5,23 +5,27 @@
*
* Uses mcrypt, if available/possible, and an internal implementation, otherwise.
*
* PHP versions 4 and 5
* PHP version 5
*
* If {@link Crypt_AES::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
* {@link Crypt_AES::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's 136-bits
* it'll be null-padded to 192-bits and 192 bits will be the key length until {@link Crypt_AES::setKey() setKey()}
* NOTE: Since AES.php is (for compatibility and phpseclib-historical reasons) virtually
* just a wrapper to Rijndael.php you may consider using Rijndael.php instead of
* to save one include_once().
*
* If {@link \phpseclib\Crypt\AES::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
* {@link \phpseclib\Crypt\AES::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's 136-bits
* it'll be null-padded to 192-bits and 192 bits will be the key length until {@link \phpseclib\Crypt\AES::setKey() setKey()}
* is called, again, at which point, it'll be recalculated.
*
* Since Crypt_AES extends Crypt_Rijndael, some functions are available to be called that, in the context of AES, don't
* make a whole lot of sense. {@link Crypt_AES::setBlockLength() setBlockLength()}, for instance. Calling that function,
* Since \phpseclib\Crypt\AES extends \phpseclib\Crypt\Rijndael, some functions are available to be called that, in the context of AES, don't
* make a whole lot of sense. {@link \phpseclib\Crypt\AES::setBlockLength() setBlockLength()}, for instance. Calling that function,
* however possible, won't do anything (AES has a fixed block length whereas Rijndael has a variable one).
*
* Here's a short example of how to use this library:
* <code>
* <?php
* include 'Crypt/AES.php';
* include 'vendor/autoload.php';
*
* $aes = new Crypt_AES();
* $aes = new \phpseclib\Crypt\AES();
*
* $aes->setKey('abcdefghijklmnop');
*
@ -35,145 +39,33 @@
* ?>
* </code>
*
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @category Crypt
* @package Crypt_AES
* @package AES
* @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVIII Jim Wigginton
* @copyright 2008 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
/**
* Include Crypt_Rijndael
*/
if (!class_exists('Crypt_Rijndael')) {
include_once 'Rijndael.php';
}
namespace phpseclib\Crypt;
/**#@+
* @access public
* @see Crypt_AES::encrypt()
* @see Crypt_AES::decrypt()
*/
/**
* Encrypt / decrypt using the Counter mode.
*
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
*/
define('CRYPT_AES_MODE_CTR', CRYPT_MODE_CTR);
/**
* Encrypt / decrypt using the Electronic Code Book mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
*/
define('CRYPT_AES_MODE_ECB', CRYPT_MODE_ECB);
/**
* Encrypt / decrypt using the Code Book Chaining mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
*/
define('CRYPT_AES_MODE_CBC', CRYPT_MODE_CBC);
/**
* Encrypt / decrypt using the Cipher Feedback mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
*/
define('CRYPT_AES_MODE_CFB', CRYPT_MODE_CFB);
/**
* Encrypt / decrypt using the Cipher Feedback mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
*/
define('CRYPT_AES_MODE_OFB', CRYPT_MODE_OFB);
/**#@-*/
/**#@+
* @access private
* @see Crypt_AES::Crypt_AES()
*/
/**
* Toggles the internal implementation
*/
define('CRYPT_AES_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
/**
* Toggles the mcrypt implementation
*/
define('CRYPT_AES_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
/**#@-*/
use phpseclib\Crypt\Rijndael;
/**
* Pure-PHP implementation of AES.
*
* @package Crypt_AES
* @package AES
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
class Crypt_AES extends Crypt_Rijndael
class AES extends Rijndael
{
/**
* The namespace used by the cipher for its constants.
*
* @see Crypt_Base::const_namespace
* @var String
* @access private
*/
var $const_namespace = 'AES';
/**
* Default Constructor.
*
* Determines whether or not the mcrypt extension should be used.
*
* $mode could be:
*
* - CRYPT_AES_MODE_ECB
*
* - CRYPT_AES_MODE_CBC
*
* - CRYPT_AES_MODE_CTR
*
* - CRYPT_AES_MODE_CFB
*
* - CRYPT_AES_MODE_OFB
*
* If not explicitly set, CRYPT_AES_MODE_CBC will be used.
*
* @see Crypt_Rijndael::Crypt_Rijndael()
* @see Crypt_Base::Crypt_Base()
* @param optional Integer $mode
* @access public
*/
function Crypt_AES($mode = CRYPT_AES_MODE_CBC)
{
parent::Crypt_Rijndael($mode);
}
/**
* Dummy function
*
* Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything.
* Since \phpseclib\Crypt\AES extends \phpseclib\Crypt\Rijndael, this function is, technically, available, but it doesn't do anything.
*
* @see Crypt_Rijndael::setBlockLength()
* @see \phpseclib\Crypt\Rijndael::setBlockLength()
* @access public
* @param Integer $length
*/
@ -181,4 +73,56 @@ class Crypt_AES extends Crypt_Rijndael
{
return;
}
/**
* Sets the key length
*
* Valid key lengths are 128, 192, and 256. If the length is less than 128, it will be rounded up to
* 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
*
* @see \phpseclib\Crypt\Rijndael:setKeyLength()
* @access public
* @param Integer $length
*/
function setKeyLength($length)
{
switch ($length) {
case 160:
$length = 192;
break;
case 224:
$length = 256;
}
parent::setKeyLength($length);
}
/**
* Sets the key.
*
* Rijndael supports five different key lengths, AES only supports three.
*
* @see \phpseclib\Crypt\Rijndael:setKey()
* @see setKeyLength()
* @access public
* @param String $key
*/
function setKey($key)
{
parent::setKey($key);
if (!$this->explicit_key_length) {
$length = strlen($key);
switch (true) {
case $length <= 16:
$this->key_size = 16;
break;
case $length <= 24:
$this->key_size = 24;
break;
default:
$this->key_size = 32;
}
$this->_setEngine();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -3,54 +3,44 @@
/**
* Random Number Generator
*
* PHP versions 4 and 5
* PHP version 5
*
* Here's a short example of how to use this library:
* <code>
* <?php
* include 'Crypt/Random.php';
* include 'vendor/autoload.php';
*
* echo bin2hex(crypt_random_string(8));
* echo bin2hex(\phpseclib\Crypt\Random::string(8));
* ?>
* </code>
*
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @category Crypt
* @package Crypt_Random
* @package Random
* @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton
* @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
// laravel is a PHP framework that utilizes phpseclib. laravel workbenches may, independently,
// have phpseclib as a requirement as well. if you're developing such a program you may encounter
// a "Cannot redeclare crypt_random_string()" error.
if (!function_exists('crypt_random_string')) {
/**
* "Is Windows" test
*
* @access private
*/
define('CRYPT_RANDOM_IS_WINDOWS', strtoupper(substr(PHP_OS, 0, 3)) === 'WIN');
namespace phpseclib\Crypt;
use phpseclib\Crypt\AES;
use phpseclib\Crypt\Base;
use phpseclib\Crypt\Blowfish;
use phpseclib\Crypt\DES;
use phpseclib\Crypt\RC4;
use phpseclib\Crypt\TripleDES;
use phpseclib\Crypt\Twofish;
/**
* Pure-PHP Random Number Generator
*
* @package Random
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
class Random
{
/**
* Generate a random string.
*
@ -60,11 +50,10 @@ if (!function_exists('crypt_random_string')) {
*
* @param Integer $length
* @return String
* @access public
*/
function crypt_random_string($length)
public static function string($length)
{
if (CRYPT_RANDOM_IS_WINDOWS) {
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
// method 1. prior to PHP 5.3 this would call rand() on windows hence the function_exists('class_alias') call.
// ie. class_alias is a function that was introduced in PHP 5.3
if (function_exists('mcrypt_create_iv') && function_exists('class_alias')) {
@ -120,7 +109,7 @@ if (!function_exists('crypt_random_string')) {
// easy to guess at. linux uses mouse clicks, keyboard timings, etc, as entropy sources, but
// PHP isn't low level to be able to use those as sources and on a web server there's not likely
// going to be a ton of keyboard or mouse action. web servers do have one thing that we can use
// however. a ton of people visiting the website. obviously you don't want to base your seeding
// however, a ton of people visiting the website. obviously you don't want to base your seeding
// soley on parameters a potential attacker sends but (1) not everything in $_SERVER is controlled
// by the user and (2) this isn't just looking at the data sent by the current user - it's based
// on the data sent by all users. one user requests the page and a hash of their info is saved.
@ -168,9 +157,9 @@ if (!function_exists('crypt_random_string')) {
ini_set('session.use_cookies', $old_use_cookies);
session_cache_limiter($old_session_cache_limiter);
} else {
if ($_OLD_SESSION !== false) {
$_SESSION = $_OLD_SESSION;
unset($_OLD_SESSION);
if ($_OLD_SESSION !== false) {
$_SESSION = $_OLD_SESSION;
unset($_OLD_SESSION);
} else {
unset($_SESSION);
}
@ -191,21 +180,27 @@ if (!function_exists('crypt_random_string')) {
//
// http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives
switch (true) {
case class_exists('Crypt_AES'):
$crypto = new Crypt_AES(CRYPT_AES_MODE_CTR);
case class_exists('\phpseclib\Crypt\AES'):
$crypto = new AES(Base::MODE_CTR);
break;
case class_exists('Crypt_TripleDES'):
$crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
case class_exists('\phpseclib\Crypt\Twofish'):
$crypto = new Twofish(Base::MODE_CTR);
break;
case class_exists('Crypt_DES'):
$crypto = new Crypt_DES(CRYPT_DES_MODE_CTR);
case class_exists('\phpseclib\Crypt\Blowfish'):
$crypto = new Blowfish(Base::MODE_CTR);
break;
case class_exists('Crypt_RC4'):
$crypto = new Crypt_RC4();
case class_exists('\phpseclib\Crypt\TripleDES'):
$crypto = new TripleDES(Base::MODE_CTR);
break;
case class_exists('\phpseclib\Crypt\DES'):
$crypto = new DES(Base::MODE_CTR);
break;
case class_exists('\phpseclib\Crypt\RC4'):
$crypto = new RC4();
break;
default:
$crypto = $seed;
return crypt_random_string($length);
user_error(__CLASS__ . ' requires at least one symmetric cipher be loaded');
return false;
}
$crypto->setKey($key);
@ -213,37 +208,21 @@ if (!function_exists('crypt_random_string')) {
$crypto->enableContinuousBuffer();
}
if (is_string($crypto)) {
// the following is based off of ANSI X9.31:
//
// http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf
//
// OpenSSL uses that same standard for it's random numbers:
//
// http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c
// (do a search for "ANS X9.31 A.2.4")
//
// ANSI X9.31 recommends ciphers be used and phpseclib does use them if they're available (see
// later on in the code) but if they're not we'll use sha1
$result = '';
while (strlen($result) < $length) { // each loop adds 20 bytes
// microtime() isn't packed as "densely" as it could be but then neither is that the idea.
// the idea is simply to ensure that each "block" has a unique element to it.
$i = pack('H*', sha1(microtime()));
$r = pack('H*', sha1($i ^ $v));
$v = pack('H*', sha1($r ^ $i));
$result.= $r;
}
return substr($result, 0, $length);
}
//return $crypto->encrypt(str_repeat("\0", $length));
// the following is based off of ANSI X9.31:
//
// http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf
//
// OpenSSL uses that same standard for it's random numbers:
//
// http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c
// (do a search for "ANS X9.31 A.2.4")
$result = '';
while (strlen($result) < $length) {
$i = $crypto->encrypt(microtime());
$r = $crypto->encrypt($i ^ $v);
$v = $crypto->encrypt($r ^ $i);
$i = $crypto->encrypt(microtime()); // strlen(microtime()) == 21
$r = $crypto->encrypt($i ^ $v); // strlen($v) == 20
$v = $crypto->encrypt($r ^ $i); // strlen($r) == 20
$result.= $r;
}
return substr($result, 0, $length);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
Copyright 2007-2013 TerraFrost and other contributors
http://phpseclib.sourceforge.net/
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -10,6 +10,8 @@ if (! defined('PHPMYADMIN')) {
exit;
}
use phpseclib\Crypt;
/* Get the authentication interface */
require_once 'libraries/plugins/AuthenticationPlugin.class.php';
@ -36,8 +38,10 @@ if (! function_exists('openssl_encrypt')
|| ! function_exists('openssl_random_pseudo_bytes')
|| PHP_VERSION_ID < 50304
) {
include PHPSECLIB_INC_DIR . '/Crypt/AES.php';
include PHPSECLIB_INC_DIR . '/Crypt/Random.php';
require PHPSECLIB_INC_DIR . '/Crypt/Base.php';
require PHPSECLIB_INC_DIR . '/Crypt/Rijndael.php';
require PHPSECLIB_INC_DIR . '/Crypt/AES.php';
require PHPSECLIB_INC_DIR . '/Crypt/Random.php';
}
/**
@ -370,19 +374,19 @@ class AuthenticationCookie extends AuthenticationPlugin
) {
if (! empty($_POST["g-recaptcha-response"])) {
include_once 'libraries/plugins/auth/recaptcha/recaptchalib.php';
$reCaptcha = new ReCaptcha(
include_once 'libraries/plugins/auth/recaptcha/autoload.php';
$reCaptcha = new \ReCaptcha\ReCaptcha(
$GLOBALS['cfg']['CaptchaLoginPrivateKey']
);
// verify captcha status.
$resp = $reCaptcha->verifyResponse(
$_SERVER["REMOTE_ADDR"],
$_POST["g-recaptcha-response"]
$resp = $reCaptcha->verify(
$_POST["g-recaptcha-response"],
$_SERVER["REMOTE_ADDR"]
);
// Check if the captcha entered is valid, if not stop the login.
if ($resp == null || ! $resp->success) {
if ($resp == null || ! $resp->isSuccess()) {
$conn_error = __('Entered captcha is wrong, try again!');
$_SESSION['last_valid_captcha'] = false;
return false;
@ -721,10 +725,10 @@ class AuthenticationCookie extends AuthenticationPlugin
private function _getSessionEncryptionSecret()
{
if (empty($_SESSION['encryption_key'])) {
if ($this->_useOpenSSL()) {
if (self::useOpenSSL()) {
$_SESSION['encryption_key'] = openssl_random_pseudo_bytes(256);
} else {
$_SESSION['encryption_key'] = crypt_random_string(256);
$_SESSION['encryption_key'] = Crypt\Random::string(256);
}
}
return $_SESSION['encryption_key'];
@ -735,7 +739,7 @@ class AuthenticationCookie extends AuthenticationPlugin
*
* @return boolean
*/
private function _useOpenSSL()
public static function useOpenSSL()
{
return (
function_exists('openssl_encrypt')
@ -756,7 +760,7 @@ class AuthenticationCookie extends AuthenticationPlugin
*/
public function cookieEncrypt($data, $secret)
{
if ($this->_useOpenSSL()) {
if (self::useOpenSSL()) {
return openssl_encrypt(
$data,
'AES-128-CBC',
@ -765,7 +769,7 @@ class AuthenticationCookie extends AuthenticationPlugin
$this->_cookie_iv
);
} else {
$cipher = new Crypt_AES(CRYPT_AES_MODE_CBC);
$cipher = new Crypt\AES(Crypt\Base::MODE_CBC);
$cipher->setIV($this->_cookie_iv);
$cipher->setKey($secret);
return base64_encode($cipher->encrypt($data));
@ -790,7 +794,7 @@ class AuthenticationCookie extends AuthenticationPlugin
$this->createIV();
}
if ($this->_useOpenSSL()) {
if (self::useOpenSSL()) {
return openssl_decrypt(
$encdata,
'AES-128-CBC',
@ -799,7 +803,7 @@ class AuthenticationCookie extends AuthenticationPlugin
$this->_cookie_iv
);
} else {
$cipher = new Crypt_AES(CRYPT_AES_MODE_CBC);
$cipher = new Crypt\AES(Crypt\Base::MODE_CBC);
$cipher->setIV($this->_cookie_iv);
$cipher->setKey($secret);
return $cipher->decrypt(base64_decode($encdata));
@ -813,10 +817,10 @@ class AuthenticationCookie extends AuthenticationPlugin
*/
public function getIVSize()
{
if ($this->_useOpenSSL()) {
if (self::useOpenSSL()) {
return openssl_cipher_iv_length('AES-128-CBC');
}
$cipher = new Crypt_AES(CRYPT_AES_MODE_CBC);
$cipher = new Crypt\AES(Crypt\Base::MODE_CBC);
return $cipher->block_size;
}
@ -830,12 +834,12 @@ class AuthenticationCookie extends AuthenticationPlugin
*/
public function createIV()
{
if ($this->_useOpenSSL()) {
if (self::useOpenSSL()) {
$this->_cookie_iv = openssl_random_pseudo_bytes(
$this->getIVSize()
);
} else {
$this->_cookie_iv = crypt_random_string(
$this->_cookie_iv = Crypt\Random::string(
$this->getIVSize()
);
}
@ -869,3 +873,11 @@ class AuthenticationCookie extends AuthenticationPlugin
$this->storePasswordCookie($password);
}
}
/**
* phpseclib
*/
if (! AuthenticationCookie::useOpenSSL()) {
include PHPSECLIB_INC_DIR . '/Crypt/AES.php';
include PHPSECLIB_INC_DIR . '/Crypt/Random.php';
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,139 +0,0 @@
<?php
/**
* This is a PHP library that handles calling reCAPTCHA.
* - Documentation and latest version
* https://developers.google.com/recaptcha/docs/php
* - Get a reCAPTCHA API Key
* https://www.google.com/recaptcha/admin/create
* - Discussion group
* http://groups.google.com/group/recaptcha
*
* @copyright Copyright (c) 2014, Google Inc.
* @link http://www.google.com/recaptcha
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* A ReCaptchaResponse is returned from checkAnswer().
*/
class ReCaptchaResponse
{
public $success;
public $errorCodes;
}
class ReCaptcha
{
private static $_signupUrl = "https://www.google.com/recaptcha/admin";
private static $_siteVerifyUrl =
"https://www.google.com/recaptcha/api/siteverify?";
private $_secret;
private static $_version = "php_1.0";
/**
* Constructor.
*
* @param string $secret shared secret between site and ReCAPTCHA server.
*/
public function ReCaptcha($secret)
{
if ($secret == null || $secret == "") {
die("To use reCAPTCHA you must get an API key from <a href='"
. self::$_signupUrl . "'>" . self::$_signupUrl . "</a>");
}
$this->_secret=$secret;
}
/**
* Encodes the given data into a query string format.
*
* @param array $data array of string elements to be encoded.
*
* @return string - encoded request.
*/
private function _encodeQS($data)
{
$req = "";
foreach ($data as $key => $value) {
$req .= $key . '=' . urlencode(stripslashes($value)) . '&';
}
// Cut the last '&'
$req=substr($req, 0, strlen($req)-1);
return $req;
}
/**
* Submits an HTTP GET to a reCAPTCHA server.
*
* @param string $path url path to recaptcha server.
* @param array $data array of parameters to be sent.
*
* @return array response
*/
private function _submitHTTPGet($path, $data)
{
$req = $this->_encodeQS($data);
$response = file_get_contents($path . $req);
return $response;
}
/**
* Calls the reCAPTCHA siteverify API to verify whether the user passes
* CAPTCHA test.
*
* @param string $remoteIp IP address of end user.
* @param string $response response string from recaptcha verification.
*
* @return ReCaptchaResponse
*/
public function verifyResponse($remoteIp, $response)
{
// Discard empty solution submissions
if ($response == null || strlen($response) == 0) {
$recaptchaResponse = new ReCaptchaResponse();
$recaptchaResponse->success = false;
$recaptchaResponse->errorCodes = 'missing-input';
return $recaptchaResponse;
}
$getResponse = $this->_submitHttpGet(
self::$_siteVerifyUrl,
array (
'secret' => $this->_secret,
'remoteip' => $remoteIp,
'v' => self::$_version,
'response' => $response
)
);
$answers = json_decode($getResponse, true);
$recaptchaResponse = new ReCaptchaResponse();
if (trim($answers ['success']) == true) {
$recaptchaResponse->success = true;
} else {
$recaptchaResponse->success = false;
$recaptchaResponse->errorCodes = $answers ['error-codes'];
}
return $recaptchaResponse;
}
}

View File

@ -262,13 +262,27 @@ class ExportSql extends ExportPlugin
$leaf->setText(sprintf(__('Add %s statement'), $drop_clause));
$subgroup->addProperty($leaf);
$subgroup_create_table = new OptionsPropertySubgroup();
// Add table structure option
$leaf = new BoolPropertyItem();
$leaf->setName('create_table');
$leaf->setText(
sprintf(__('Add %s statement'), '<code>CREATE TABLE</code>')
);
$subgroup->addProperty($leaf);
$subgroup_create_table->setSubgroupHeader($leaf);
$leaf = new BoolPropertyItem();
$leaf->setName('if_not_exists');
$leaf->setText('<code>IF NOT EXISTS</code> ' . __('(less efficient as indexes will be generated during table creation)'));
$subgroup_create_table->addProperty($leaf);
$leaf = new BoolPropertyItem();
$leaf->setName('auto_increment');
$leaf->setText(sprintf(__('%s value'), '<code>AUTO_INCREMENT</code>'));
$subgroup_create_table->addProperty($leaf);
$subgroup->addProperty($subgroup_create_table);
// Add view option
$leaf = new BoolPropertyItem();
@ -299,21 +313,6 @@ class ExportSql extends ExportPlugin
);
$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();
@ -1036,8 +1035,7 @@ class ExportSql extends ExportPlugin
$types = array(
'bookmark' => 'dbase',
'relation' => 'master_db',
//'pdf_pages' => 'db_name',
//'table_coords' => 'db_name',
'pdf_pages' => 'db_name',
'savedsearches' => 'db_name',
'central_columns' => 'db_name',
);
@ -1071,6 +1069,69 @@ class ExportSql extends ExportPlugin
foreach ($types as $type => $dbNameColumn) {
if (in_array($type, $metadataTypes) && isset($cfgRelation[$type])) {
// special case, designer pages and their coordinates
if ($type == 'pdf_pages') {
$sql_query = "SELECT `page_nr`, `page_descr` FROM "
. PMA_Util::backquote($cfgRelation['db'])
. "." . PMA_Util::backquote($cfgRelation[$type])
. " WHERE " . PMA_Util::backquote($dbNameColumn)
. " = '" . PMA_Util::sqlAddSlashes($db) . "'";
$result = $GLOBALS['dbi']->fetchResult(
$sql_query, 'page_nr', 'page_descr'
);
foreach ($result as $page => $name) {
// insert row for pdf_page
$sql_query_row = "SELECT `db_name`, `page_descr` FROM "
. PMA_Util::backquote($cfgRelation['db'])
. "." . PMA_Util::backquote($cfgRelation[$type])
. " WHERE " . PMA_Util::backquote($dbNameColumn)
. " = '" . PMA_Util::sqlAddSlashes($db) . "'"
. " AND `page_nr` = '" . $page . "'";
if (! $this->exportData(
$cfgRelation['db'],
$cfgRelation[$type],
$GLOBALS['crlf'],
'',
$sql_query_row,
$aliases
)) {
return false;
}
$lastPage = $GLOBALS['crlf']
. "SET @LAST_PAGE = LAST_INSERT_ID();"
. $GLOBALS['crlf'] ;
if (! PMA_exportOutputHandler($lastPage)) {
return false;
}
$sql_query_coords = "SELECT `db_name`, `table_name`, "
. "'@LAST_PAGE' AS `pdf_page_number`, `x`, `y` FROM "
. PMA_Util::backquote($cfgRelation['db'])
. "." . PMA_Util::backquote($cfgRelation['table_coords'])
. " WHERE `pdf_page_number` = '" . $page . "'";
$GLOBALS['exporting_metadata'] = true;
if (! $this->exportData(
$cfgRelation['db'],
$cfgRelation['table_coords'],
$GLOBALS['crlf'],
'',
$sql_query_coords,
$aliases
)) {
$GLOBALS['exporting_metadata'] = false;
return false;
}
$GLOBALS['exporting_metadata'] = false;
}
continue;
}
// remove auto_incrementing id field for some tables
if ($type == 'bookmark') {
$sql_query = "SELECT `dbase`, `user`, `label`, `query` FROM ";
@ -1546,23 +1607,27 @@ class ExportSql extends ExportPlugin
// constraints).
if ($field->key->type === 'FULLTEXT KEY') {
$indexes_fulltext[] = $field->build($field);
} else {
unset($statement->fields[$key]);
} else if (empty($GLOBALS['sql_if_not_exists'])) {
$indexes[] = $field->build($field);
unset($statement->fields[$key]);
}
unset($statement->fields[$key]);
}
// Creating the parts that drop foreign keys.
if (!empty($field->key)) {
if ($field->key->type === 'FOREIGN KEY') {
$dropped[] = 'FOREIGN KEY ' . SqlParser\Context::escape($field->name);
unset($statement->fields[$key]);
}
unset($statement->fields[$key]);
}
// Dropping AUTO_INCREMENT.
if (!empty($field->options)) {
if ($field->options->has('AUTO_INCREMENT')) {
if ($field->options->has('AUTO_INCREMENT')
&& empty($GLOBALS['sql_if_not_exists'])
) {
$auto_increment[] = $field::build($field);
$field->options->remove('AUTO_INCREMENT');
}
@ -1630,14 +1695,17 @@ class ExportSql extends ExportPlugin
}
// Generating auto-increment-related query.
if ((!empty($auto_increment))
if ((! empty($auto_increment))
&& ($update_indexes_increments)
&& ($statement->entityOptions->has('AUTO_INCREMENT') !== false)
) {
$sql_auto_increments_query = $alter_header .
$crlf . ' MODIFY ' . implode(',' . $crlf . ' MODIFY ', $auto_increment) .
', AUTO_INCREMENT=' . $statement->entityOptions->has('AUTO_INCREMENT')
. $alter_footer;
$crlf . ' MODIFY ' . implode(',' . $crlf . ' MODIFY ', $auto_increment);
if (isset($GLOBALS['sql_auto_increment'])) {
$sql_auto_increments_query .= ', AUTO_INCREMENT='
. $statement->entityOptions->has('AUTO_INCREMENT');
}
$sql_auto_increments_query .= ';';
$sql_auto_increments = $this->generateComment(
$crlf, $sql_auto_increments,
@ -1648,7 +1716,9 @@ class ExportSql extends ExportPlugin
// Removing the `AUTO_INCREMENT` attribute from the `CREATE TABLE`
// too.
if (!empty($statement->entityOptions)) {
if (!empty($statement->entityOptions)
&& empty($GLOBALS['sql_if_not_exists'])
) {
$statement->entityOptions->remove('AUTO_INCREMENT');
}
@ -2224,6 +2294,10 @@ class ExportSql extends ExportPlugin
)
)
. "'";
} elseif (! empty($GLOBALS['exporting_metadata'])
&& $row[$j] == '@LAST_PAGE'
) {
$values[] = '@LAST_PAGE';
} else {
// something else -> treat as a string
$values[] = '\''

View File

@ -21,103 +21,6 @@ require_once 'libraries/plugins/ImportPlugin.class.php';
*/
class ImportSql extends ImportPlugin
{
const BIG_VALUE = 2147483647;
const READ_MB_FALSE = 0;
const READ_MB_TRUE = 1;
/**
* @var string SQL delimiter
*/
private $_delimiter;
/**
* @var int SQL delimiter length
*/
private $_delimiterLength;
/**
* @var bool|int SQL delimiter position or false if not found
*/
private $_delimiterPosition = false;
/**
* @var int Query start position
*/
private $_queryBeginPosition = 0;
/**
* @var int|false First special chars position or false if not found
*/
private $_firstSearchChar = null;
/**
* @var bool Current position is in string
*/
private $_isInString = false;
/**
* @var string Quote of current string or null if out of string
*/
private $_quote = null;
/**
* @var bool Current position is in comment
*/
private $_isInComment = false;
/**
* @var string Current comment opener
*/
private $_openingComment = null;
/**
* @var bool Current position is in delimiter definition
*/
private $_isInDelimiter = false;
/**
* @var string Delimiter keyword
*/
private $_delimiterKeyword = 'DELIMITER ';
/**
* @var int Import should be done using multibytes
*/
private $_readMb = self::READ_MB_FALSE;
/**
* @var string Data to parse
*/
private $_data = null;
/**
* @var int Length of data to parse
*/
private $_dataLength = 0;
/**
* @var array List of string functions
* @todo Move this part in string functions definition file.
*/
private $_stringFunctions = array(
self::READ_MB_FALSE => array(
'substr' => 'substr',
'strlen' => 'strlen',
'strpos' => 'strpos',
'strtoupper' => 'strtoupper',
),
self::READ_MB_TRUE => array(
'substr' => 'mb_substr',
'strlen' => 'mb_strlen',
'strpos' => 'mb_strpos',
'strtoupper' => 'mb_strtoupper',
),
);
/**
* @var bool|int List of string functions to use
*/
private $_stringFctToUse = false;
/**
* Constructor
@ -189,13 +92,6 @@ class ImportSql extends ImportPlugin
);
$generalOptions->addProperty($leaf);
$leaf = new BoolPropertyItem();
$leaf->setName("read_as_multibytes");
$leaf->setText(
__('Read as multibytes')
);
$generalOptions->addProperty($leaf);
// add the main group to the root group
$importSpecificOptions->addProperty($generalOptions);
// set the options for the import plugin property item
@ -205,182 +101,7 @@ class ImportSql extends ImportPlugin
$this->properties = $importPluginProperties;
}
/**
* Look for end of string
*
* @return bool End of string found
*/
private function _searchStringEnd()
{
//Search for closing quote
$posClosingString = $this->_stringFctToUse['strpos'](
$this->_data, $this->_quote, $this->_delimiterPosition
);
if (false === $posClosingString) {
return false;
}
//Quotes escaped by quote will be considered as 2 consecutive strings
//and won't pass in this loop.
$posEscape = $posClosingString-1;
while ($this->_stringFctToUse['substr']($this->_data, $posEscape, 1) == '\\'
) {
$posEscape--;
}
// Odd count means it was escaped
$quoteEscaped = (((($posClosingString - 1) - $posEscape) % 2) === 1);
//Move after the escaped quote.
$this->_delimiterPosition = $posClosingString + 1;
if ($quoteEscaped) {
return true;
}
$this->_isInString = false;
$this->_quote = null;
return true;
}
/**
* Return the position of first SQL delimiter or false if no SQL delimiter found.
*
* @return int|bool Delimiter position or false if no delimiter found
*/
private function _findDelimiterPosition()
{
$this->_firstSearchChar = null;
$firstSqlDelimiter = null;
$matches = null;
/* while not at end of line */
while ($this->_delimiterPosition < $this->_dataLength) {
if ($this->_isInString) {
if (false === $this->_searchStringEnd()) {
return false;
}
continue;
}
if ($this->_isInComment) {
if (in_array($this->_openingComment, array('#', '-- '))) {
$posClosingComment = $this->_stringFctToUse['strpos'](
$this->_data,
"\n",
$this->_delimiterPosition
);
if (false === $posClosingComment) {
return false;
}
//Move after the end of the line.
$this->_delimiterPosition = $posClosingComment + 1;
$this->_isInComment = false;
$this->_openingComment = null;
} elseif ('/*' === $this->_openingComment) {
//Search for closing comment
$posClosingComment = $this->_stringFctToUse['strpos'](
$this->_data,
'*/',
$this->_delimiterPosition
);
if (false === $posClosingComment) {
return false;
}
//Move after closing comment.
$this->_delimiterPosition = $posClosingComment + 2;
$this->_isInComment = false;
$this->_openingComment = null;
} else {
//We shouldn't be able to come here.
//throw new Exception('Unknown case.');
break;
}
continue;
}
if ($this->_isInDelimiter) {
//Search for new line.
if (!preg_match(
"/^(.*)\n/",
$this->_stringFctToUse['substr'](
$this->_data,
$this->_delimiterPosition
),
$matches,
PREG_OFFSET_CAPTURE
)) {
return false;
}
$this->_setDelimiter($matches[1][0]);
//Start after delimiter and new line.
$this->_queryBeginPosition = $this->_delimiterPosition
+ $matches[1][1] + $this->_delimiterLength + 1;
$this->_delimiterPosition = $this->_queryBeginPosition;
$this->_isInDelimiter = false;
$firstSqlDelimiter = null;
$this->_firstSearchChar = null;
continue;
}
$matches = $this->_searchSpecialChars($matches);
$firstSqlDelimiter = $this->_searchSqlDelimiter($firstSqlDelimiter);
if (false === $firstSqlDelimiter && false === $this->_firstSearchChar) {
return false;
}
//If first char is delimiter.
if (false === $this->_firstSearchChar
|| (false !== $firstSqlDelimiter
&& $firstSqlDelimiter < $this->_firstSearchChar)
) {
$this->_delimiterPosition = $firstSqlDelimiter;
return true;
}
//Else first char is result of preg_match.
$specialChars = $matches[1][0];
//If string is opened.
if (in_array($specialChars, array('\'', '"', '`'))) {
$this->_isInString = true;
$this->_quote = $specialChars;
//Move before quote.
$this->_delimiterPosition = $this->_firstSearchChar + 1;
continue;
}
//If comment is opened.
if (in_array($specialChars, array('#', '-- ', '/*'))) {
$this->_isInComment = true;
$this->_openingComment = $specialChars;
//Move before comment opening.
$this->_delimiterPosition = $this->_firstSearchChar
+ $this->_stringFctToUse['strlen']($specialChars);
continue;
}
//If DELIMITER is found.
$specialCharsUpper = $this->_stringFctToUse['strtoupper']($specialChars);
if ($specialCharsUpper === $this->_delimiterKeyword) {
$this->_isInDelimiter = true;
$this->_delimiterPosition = $this->_firstSearchChar
+ $this->_stringFctToUse['strlen']($specialChars);
continue;
}
}
return false;
}
/**
/*
* Handles the whole import logic
*
* @param array &$sql_data 2-element array with sql data
@ -391,95 +112,63 @@ class ImportSql extends ImportPlugin
{
global $error, $timeout_passed;
//Manage multibytes or not
if (isset($_REQUEST['sql_read_as_multibytes'])) {
$this->_readMb = self::READ_MB_TRUE;
}
$this->_stringFctToUse = $this->_stringFunctions[$this->_readMb];
if (isset($_POST['sql_delimiter'])) {
$this->_setDelimiter($_POST['sql_delimiter']);
} else {
$this->_setDelimiter(';');
}
// Handle compatibility options
// Handle compatibility options.
$this->_setSQLMode($GLOBALS['dbi'], $_REQUEST);
//Initialise data.
$this->_setData(null);
$bq = new SqlParser\Utils\BufferedQuery();
if (isset($_POST['sql_delimiter'])) {
$bq->setDelimiter($_POST['sql_delimiter']);
}
/**
* will be set in PMA_importGetNextChunk()
*
* @global boolean $GLOBALS['finished']
* Will be set in PMA_importGetNextChunk().
* @global bool $GLOBALS['finished']
*/
$GLOBALS['finished'] = false;
$delimiterFound = false;
while (!$error && !$timeout_passed) {
if (false === $delimiterFound) {
$newData = PMA_importGetNextChunk(200);
while ((!$error) && (!$timeout_passed)) {
// Getting the first statement, the remaining data and the last
// delimiter.
$statement = $bq->extract();
// If there is no full statement, we are looking for more data.
if (empty($statement)) {
// Importing new data.
$newData = PMA_importGetNextChunk();
// Subtract data we didn't handle yet and stop processing.
if ($newData === false) {
// subtract data we didn't handle yet and stop processing
$GLOBALS['offset'] -= $this->_dataLength;
$GLOBALS['offset'] -= mb_strlen($bq->query);
break;
}
// Checking if the input buffer has finished.
if ($newData === true) {
$GLOBALS['finished'] = true;
break;
}
//Convert CR (but not CRLF) to LF otherwise all queries
//may not get executed on some platforms
$this->_addData(preg_replace("/\r($|[^\n])/", "\n$1", $newData));
unset($newData);
}
// Convert CR (but not CRLF) to LF otherwise all queries may
// not get executed on some platforms.
$bq->query .= preg_replace("/\r($|[^\n])/", "\n$1", $newData);
//Find quotes, comments, delimiter definition or delimiter itself.
$delimiterFound = $this->_findDelimiterPosition();
//If no delimiter found, restart and get more data.
if (false === $delimiterFound) {
continue;
}
PMA_importRunQuery(
$this->_stringFctToUse['substr'](
$this->_data,
$this->_queryBeginPosition,
$this->_delimiterPosition - $this->_queryBeginPosition
), //Query to execute
$this->_stringFctToUse['substr'](
$this->_data,
0,
$this->_delimiterPosition + $this->_delimiterLength
), //Query to display
false,
$sql_data
);
$this->_setData(
$this->_stringFctToUse['substr'](
$this->_data,
$this->_delimiterPosition + $this->_delimiterLength
)
);
// Executing the query.
PMA_importRunQuery($statement, $statement, false, $sql_data);
}
if (! $timeout_passed) {
//Commit any possible data in buffers
PMA_importRunQuery(
$this->_stringFctToUse['substr'](
$this->_data,
$this->_queryBeginPosition
), //Query to execute
$this->_data,
false,
$sql_data
);
// Extracting remaining statements.
while ((!$error) && (!$timeout_passed)
&& ($statement = $bq->extract(true))
) {
PMA_importRunQuery($statement, $statement, false, $sql_data);
}
// Finishing.
PMA_importRunQuery('', '', false, $sql_data);
}
@ -508,113 +197,4 @@ class ImportSql extends ImportPlugin
);
}
}
/**
* Look for special chars: comment, string or DELIMITER
*
* @param array $matches Special chars found in data
*
* @return array matches
*/
private function _searchSpecialChars(
$matches
) {
//Don't look for a string/comment/"DELIMITER" if not found previously
//or if it's still after current position.
if (null === $this->_firstSearchChar
|| (false !== $this->_firstSearchChar
&& $this->_firstSearchChar < $this->_delimiterPosition)
) {
$bFind = preg_match(
'/(\'|"|#|-- |\/\*|`|(?i)(?<![A-Z0-9_])'
. $this->_delimiterKeyword . ')/',
$this->_stringFctToUse['substr'](
$this->_data,
$this->_delimiterPosition
),
$matches,
PREG_OFFSET_CAPTURE
);
if (1 === $bFind) {
$this->_firstSearchChar = $matches[1][1] + $this->_delimiterPosition;
} else {
$this->_firstSearchChar = false;
}
}
return $matches;
}
/**
* Look for SQL delimiter
*
* @param int $firstSqlDelimiter First found char position
*
* @return int
*/
private function _searchSqlDelimiter($firstSqlDelimiter)
{
//Don't look for the SQL delimiter if not found previously
//or if it's still after current position.
if (null === $firstSqlDelimiter
|| (false !== $firstSqlDelimiter
&& $firstSqlDelimiter < $this->_delimiterPosition)
) {
// the cost of doing this one with preg_match() would be too high
$firstSqlDelimiter = $this->_stringFctToUse['strpos'](
$this->_data,
$this->_delimiter,
$this->_delimiterPosition
);
}
return $firstSqlDelimiter;
}
/**
* Set new delimiter
*
* @param string $delimiter New delimiter
*
* @return int delimiter length
*/
private function _setDelimiter($delimiter)
{
$this->_delimiter = $delimiter;
$this->_delimiterLength = $this->_stringFctToUse['strlen']($delimiter);
return $this->_delimiterLength;
}
/**
* Set data to parse
*
* @param string $data Data to parse
*
* @return int Data length
*/
private function _setData($data)
{
$this->_data = ltrim($data);
$this->_dataLength = $this->_stringFctToUse['strlen']($this->_data);
$this->_queryBeginPosition = 0;
$this->_delimiterPosition = 0;
return $this->_dataLength;
}
/**
* Add data to parse
*
* @param string $data Data to add to data to parse
*
* @return int Data length
*/
private function _addData($data)
{
$this->_data .= $data;
$this->_dataLength += $this->_stringFctToUse['strlen']($data);
return $this->_dataLength;
}
}

View File

@ -57,59 +57,59 @@ class Relation_Stats_Svg extends RelationStats
{
if ($showColor) {
$listOfColors = array(
'red',
'grey',
'black',
'yellow',
'green',
'cyan',
' orange'
'#c00',
'#bbb',
'#333',
'#cb0',
'#0b0',
'#0bf',
'#b0b'
);
shuffle($listOfColors);
$color = $listOfColors[0];
} else {
$color = 'black';
$color = '#333';
}
$this->diagram->printElementLine(
'line', $this->xSrc, $this->ySrc,
$this->xSrc + $this->srcDir * $this->wTick, $this->ySrc,
'fill:' . $color . ';stroke:black;stroke-width:2;'
'stroke:' . $color . ';stroke-width:1;'
);
$this->diagram->printElementLine(
'line', $this->xDest + $this->destDir * $this->wTick,
$this->yDest, $this->xDest, $this->yDest,
'fill:' . $color . ';stroke:black;stroke-width:2;'
'stroke:' . $color . ';stroke-width:1;'
);
$this->diagram->printElementLine(
'line', $this->xSrc + $this->srcDir * $this->wTick, $this->ySrc,
$this->xDest + $this->destDir * $this->wTick, $this->yDest,
'fill:' . $color . ';stroke:' . $color . ';stroke-width:1;'
'stroke:' . $color . ';stroke-width:1;'
);
$root2 = 2 * sqrt(2);
$this->diagram->printElementLine(
'line', $this->xSrc + $this->srcDir * $this->wTick * 0.75, $this->ySrc,
$this->xSrc + $this->srcDir * (0.75 - 1 / $root2) * $this->wTick,
$this->ySrc + $this->wTick / $root2,
'fill:' . $color . ';stroke:black;stroke-width:2;'
'stroke:' . $color . ';stroke-width:2;'
);
$this->diagram->printElementLine(
'line', $this->xSrc + $this->srcDir * $this->wTick * 0.75, $this->ySrc,
$this->xSrc + $this->srcDir * (0.75 - 1 / $root2) * $this->wTick,
$this->ySrc - $this->wTick / $root2,
'fill:' . $color . ';stroke:black;stroke-width:2;'
'stroke:' . $color . ';stroke-width:2;'
);
$this->diagram->printElementLine(
'line', $this->xDest + $this->destDir * $this->wTick / 2, $this->yDest,
$this->xDest + $this->destDir * (0.5 + 1 / $root2) * $this->wTick,
$this->yDest + $this->wTick / $root2,
'fill:' . $color . ';stroke:black;stroke-width:2;'
'stroke:' . $color . ';stroke-width:2;'
);
$this->diagram->printElementLine(
'line', $this->xDest + $this->destDir * $this->wTick / 2, $this->yDest,
$this->xDest + $this->destDir * (0.5 + 1 / $root2) * $this->wTick,
$this->yDest - $this->wTick / $root2,
'fill:' . $color . ';stroke:black;stroke-width:2;'
'stroke:' . $color . ';stroke-width:2;'
);
}
}

View File

@ -135,16 +135,30 @@ class PMA_SVG extends XMLWriter
*
* @param integer $width total width of the Svg document
* @param integer $height total height of the Svg document
* @param integer $x min-x of the view box
* @param integer $y min-y of the view box
*
* @return void
*
* @see XMLWriter::startElement(),XMLWriter::writeAttribute()
*/
public function startSvgDoc($width,$height)
public function startSvgDoc($width, $height, $x = 0, $y = 0)
{
$this->startElement('svg');
$this->writeAttribute('width', $width);
$this->writeAttribute('height', $height);
if (!is_int($width)) {
$width = intval($width);
}
if (!is_int($height)) {
$height = intval($height);
}
if ($x != 0 || $y != 0) {
$this->writeAttribute('viewBox', "$x $y $width $height");
}
$this->writeAttribute('width', ($width - $x) . 'px');
$this->writeAttribute('height', ($height - $y) . 'px');
$this->writeAttribute('xmlns', 'http://www.w3.org/2000/svg');
$this->writeAttribute('version', '1.1');
}
@ -314,7 +328,6 @@ class PMA_Svg_Relation_Schema extends PMA_Export_Relation_Schema
$this->diagram->SetAuthor('phpMyAdmin ' . PMA_VERSION);
$this->diagram->setFont('Arial');
$this->diagram->setFontSize('16px');
$this->diagram->startSvgDoc('1000px', '1000px');
$alltables = $this->getTablesFromRequest();
@ -330,10 +343,19 @@ class PMA_Svg_Relation_Schema extends PMA_Export_Relation_Schema
}
if ($this->sameWide) {
$this->_tables[$table]->width = $this->_tablewidth;
$this->_tables[$table]->width = &$this->_tablewidth;
}
$this->_setMinMax($this->_tables[$table]);
}
$border = 15;
$this->diagram->startSvgDoc(
$this->_xMax + $border,
$this->_yMax + $border,
$this->_xMin - $border,
$this->_yMin - $border
);
$seen_a_relation = false;
foreach ($alltables as $one_table) {
$exist_rel = PMA_getForeigners($this->db, $one_table, '', 'both');
@ -351,9 +373,13 @@ class PMA_Svg_Relation_Schema extends PMA_Export_Relation_Schema
if ($master_field != 'foreign_keys_data') {
if (in_array($rel['foreign_table'], $alltables)) {
$this->_addRelation(
$one_table, $this->diagram->getFont(), $this->diagram->getFontSize(),
$master_field, $rel['foreign_table'],
$rel['foreign_field'], $this->tableDimension
$one_table,
$this->diagram->getFont(),
$this->diagram->getFontSize(),
$master_field,
$rel['foreign_table'],
$rel['foreign_field'],
$this->tableDimension
);
}
continue;

View File

@ -139,18 +139,18 @@ class Table_Stats_Svg extends TableStats
{
$this->diagram->printElement(
'rect', $this->x, $this->y, $this->width,
$this->heightCell, null, 'fill:red;stroke:black;'
$this->heightCell, null, 'fill:#007;stroke:black;'
);
$this->diagram->printElement(
'text', $this->x + 5, $this->y+ 14, $this->width, $this->heightCell,
$this->getTitle(), 'fill:none;stroke:black;'
$this->getTitle(), 'fill:#fff;'
);
foreach ($this->fields as $field) {
$this->currentCell += $this->heightCell;
$fillColor = 'none';
if ($showColor) {
if (in_array($field, $this->primary)) {
$fillColor = '#0c0';
$fillColor = '#aea';
}
if ($field == $this->displayfield) {
$fillColor = 'none';
@ -162,7 +162,7 @@ class Table_Stats_Svg extends TableStats
);
$this->diagram->printElement(
'text', $this->x + 5, $this->y + 14 + $this->currentCell,
$this->width, $this->heightCell, $field, 'fill:none;stroke:black;'
$this->width, $this->heightCell, $field, 'fill:black;'
);
}
}

View File

@ -442,21 +442,21 @@ function PMA_saveTablePositions($pg)
{
$cfgRelation = PMA_getRelationsParam();
if (! $cfgRelation['pdfwork']) {
return null;
return false;
}
$queury = "DELETE FROM " . PMA_Util::backquote($GLOBALS['cfgRelation']['db'])
$query = "DELETE FROM " . PMA_Util::backquote($GLOBALS['cfgRelation']['db'])
. "." . PMA_Util::backquote($GLOBALS['cfgRelation']['table_coords'])
. " WHERE `db_name` = '" . PMA_Util::sqlAddSlashes($_REQUEST['db']) . "'"
. " AND `pdf_page_number` = '" . PMA_Util::sqlAddSlashes($pg) . "'";
$res = PMA_queryAsControlUser($queury, true, PMA_DatabaseInterface::QUERY_STORE);
$res = PMA_queryAsControlUser($query, true, PMA_DatabaseInterface::QUERY_STORE);
if ($res) {
foreach ($_REQUEST['t_h'] as $key => $value) {
list($DB, $TAB) = explode(".", $key);
if ($value) {
$queury = "INSERT INTO "
$query = "INSERT INTO "
. PMA_Util::backquote($GLOBALS['cfgRelation']['db']) . "."
. PMA_Util::backquote($GLOBALS['cfgRelation']['table_coords'])
. " (`db_name`, `table_name`, `pdf_page_number`, `x`, `y`)"
@ -468,13 +468,13 @@ function PMA_saveTablePositions($pg)
. "'" . PMA_Util::sqlAddSlashes($_REQUEST['t_y'][$key]) . "')";
$res = PMA_queryAsControlUser(
$queury, true, PMA_DatabaseInterface::QUERY_STORE
$query, true, PMA_DatabaseInterface::QUERY_STORE
);
}
}
}
return $res;
return (boolean) $res;
}
/**
@ -700,3 +700,61 @@ function PMA_removeRelation($T1, $F1, $T2, $F2)
return array(true, __('Internal relation has been removed.'));
}
/**
* Save value for a designer setting
*
* @param string $index setting
* @param string $value value
*
* @return bool whether the operation succeeded
*/
function PMA_saveDesignerSetting($index, $value)
{
$cfgRelation = PMA_getRelationsParam();
$cfgDesigner = array(
'user' => $GLOBALS['cfg']['Server']['user'],
'db' => $cfgRelation['db'],
'table' => $cfgRelation['designer_settings']
);
$success = true;
if ($GLOBALS['cfgRelation']['designersettingswork']) {
$orig_data_query = "SELECT settings_data"
. " FROM " . PMA_Util::backquote($cfgDesigner['db'])
. "." . PMA_Util::backquote($cfgDesigner['table'])
. " WHERE username = '"
. PMA_Util::sqlAddSlashes($cfgDesigner['user']) . "';";
$orig_data = $GLOBALS['dbi']->fetchSingleRow(
$orig_data_query, $GLOBALS['controllink']
);
if (! empty($orig_data)) {
$orig_data = json_decode($orig_data['settings_data'], true);
$orig_data[$index] = $value;
$orig_data = json_encode($orig_data);
$save_query = "UPDATE " . PMA_Util::backquote($cfgDesigner['db'])
. "." . PMA_Util::backquote($cfgDesigner['table'])
. " SET settings_data = '" . $orig_data . "'"
. " WHERE username = '"
. PMA_Util::sqlAddSlashes($cfgDesigner['user']) . "';";
$success = PMA_queryAsControlUser($save_query);
} else {
$save_data = array($index => $value);
$query = "INSERT INTO " . PMA_Util::backquote($cfgDesigner['db'])
. "." . PMA_Util::backquote($cfgDesigner['table'])
. " (username, settings_data)"
. " VALUES('" . $cfgDesigner['user'] . "',"
. " '" . json_encode($save_data) . "');";
$success = PMA_queryAsControlUser($query);
}
}
return $success;
}

View File

@ -345,35 +345,30 @@ function PMA_getRelationsParamDiagnostic($cfgRelation)
$retval .= '<p>' . __('Quick steps to setup advanced features:')
. '</p>';
$retval .= '<ul>';
$retval .= '<li>';
$retval .= sprintf(
$items = array();
$items[] = sprintf(
__(
'Create the needed tables with the '
. '<code>%screate_tables.sql</code>.'
),
htmlspecialchars(SQL_DIR)
);
$retval .= ' ' . PMA_Util::showDocu('setup', 'linked-tables');
$retval .= '</li>';
$retval .= '<li>';
$retval .= __('Create a pma user and give access to these tables.');
$retval .= ' ' . PMA_Util::showDocu('config', 'cfg_Servers_controluser');
$retval .= '</li>';
$retval .= '<li>';
$retval .= __(
) . ' ' . PMA_Util::showDocu('setup', 'linked-tables');
$items[] = __('Create a pma user and give access to these tables.') . ' '
. PMA_Util::showDocu('config', 'cfg_Servers_controluser');
$items[] = __(
'Enable advanced features in configuration file '
. '(<code>config.inc.php</code>), for example by '
. 'starting from <code>config.sample.inc.php</code>.'
);
$retval .= ' ' . PMA_Util::showDocu('setup', 'quick-install');
$retval .= '</li>';
$retval .= '<li>';
$retval .= __(
) . ' ' . PMA_Util::showDocu('setup', 'quick-install');
$items[] = __(
'Re-login to phpMyAdmin to load the updated configuration file.'
);
$retval .= '</li>';
$retval .= '</ul>';
include_once './libraries/Template.class.php';
$retval .= PMA\Template::get('list/unordered')->render(
array('items' => $items,)
);
}
}

View File

@ -90,199 +90,7 @@ function PMA_RTN_handleEditor()
{
global $_GET, $_POST, $_REQUEST, $GLOBALS, $db, $errors;
if (! empty($_REQUEST['editor_process_add'])
|| ! empty($_REQUEST['editor_process_edit'])
) {
/**
* Handle a request to create/edit a routine
*/
$sql_query = '';
$routine_query = PMA_RTN_getQueryFromRequest();
if (! count($errors)) { // set by PMA_RTN_getQueryFromRequest()
// Execute the created query
if (! empty($_REQUEST['editor_process_edit'])) {
$isProcOrFunc = in_array(
$_REQUEST['item_original_type'],
array('PROCEDURE', 'FUNCTION')
);
if (!$isProcOrFunc) {
$errors[] = sprintf(
__('Invalid routine type: "%s"'),
htmlspecialchars($_REQUEST['item_original_type'])
);
} else {
// Backup the old routine, in case something goes wrong
$create_routine = $GLOBALS['dbi']->getDefinition(
$db, $_REQUEST['item_original_type'],
$_REQUEST['item_original_name']
);
if (! defined('PMA_DRIZZLE') || ! PMA_DRIZZLE) {
if (isset($GLOBALS['proc_priv']) && $GLOBALS['proc_priv']
&& isset($GLOBALS['flush_priv']) && $GLOBALS['flush_priv']
) {
// Backup the Old Privileges before dropping
// if $_REQUEST['item_adjust_privileges'] set
$privilegesBackup = array();
if (isset($_REQUEST['item_adjust_privileges'])
&& ! empty($_REQUEST['item_adjust_privileges'])
) {
$privilegesBackupQuery = 'SELECT * FROM ' . PMA_Util::backquote('mysql')
. '.' . PMA_Util::backquote('procs_priv')
. ' where Routine_name = "' . $_REQUEST['item_original_name']
. '" AND Routine_type = "' . $_REQUEST['item_original_type']
. '";';
$privilegesBackup = $GLOBALS['dbi']->fetchResult(
$privilegesBackupQuery, 0
);
}
}
}
$drop_routine = "DROP {$_REQUEST['item_original_type']} "
. PMA_Util::backquote($_REQUEST['item_original_name'])
. ";\n";
$result = $GLOBALS['dbi']->tryQuery($drop_routine);
if (! $result) {
$errors[] = sprintf(
__('The following query has failed: "%s"'),
htmlspecialchars($drop_routine)
)
. '<br />'
. __('MySQL said: ') . $GLOBALS['dbi']->getError(null);
} else {
$result = $GLOBALS['dbi']->tryQuery($routine_query);
if (! $result) {
$errors[] = sprintf(
__('The following query has failed: "%s"'),
htmlspecialchars($routine_query)
)
. '<br />'
. __('MySQL said: ') . $GLOBALS['dbi']->getError(null);
// We dropped the old routine,
// but were unable to create the new one
// Try to restore the backup query
$result = $GLOBALS['dbi']->tryQuery($create_routine);
$errors = checkResult(
$result,
__(
'Sorry, we failed to restore'
. ' the dropped routine.'
),
$create_routine,
$errors
);
} else {
// Default value
$resultAdjust = false;
if (! defined('PMA_DRIZZLE') || ! PMA_DRIZZLE) {
if (isset($GLOBALS['proc_priv']) && $GLOBALS['proc_priv']
&& isset($GLOBALS['flush_priv']) && $GLOBALS['flush_priv']
) {
// Insert all the previous privileges
// but with the new name and the new type
foreach ($privilegesBackup as $priv) {
$adjustProcPrivilege = 'INSERT INTO '
. PMA_Util::backquote('mysql') . '.'
. PMA_Util::backquote('procs_priv')
. ' VALUES("' . $priv[0] . '", "'
. $priv[1] . '", "' . $priv[2] . '", "'
. $_REQUEST['item_name'] . '", "'
. $_REQUEST['item_type'] . '", "'
. $priv[5] . '", "'
. $priv[6] . '", "'
. $priv[7] . '");';
$resultAdjust = $GLOBALS['dbi']->query(
$adjustProcPrivilege
);
}
}
}
if ($resultAdjust) {
// Flush the Privileges
$flushPrivQuery = 'FLUSH PRIVILEGES;';
$GLOBALS['dbi']->query($flushPrivQuery);
$message = PMA_Message::success(
__(
'Routine %1$s has been modified. Privileges have been adjusted.'
)
);
} else {
$message = PMA_Message::success(
__('Routine %1$s has been modified.')
);
}
$message->addParam(
PMA_Util::backquote($_REQUEST['item_name'])
);
$sql_query = $drop_routine . $routine_query;
}
}
}
} else {
// 'Add a new routine' mode
$result = $GLOBALS['dbi']->tryQuery($routine_query);
if (! $result) {
$errors[] = sprintf(
__('The following query has failed: "%s"'),
htmlspecialchars($routine_query)
)
. '<br /><br />'
. __('MySQL said: ') . $GLOBALS['dbi']->getError(null);
} else {
$message = PMA_Message::success(
__('Routine %1$s has been created.')
);
$message->addParam(
PMA_Util::backquote($_REQUEST['item_name'])
);
$sql_query = $routine_query;
}
}
}
if (count($errors)) {
$message = PMA_Message::error(
__(
'One or more errors have occurred while'
. ' processing your request:'
)
);
$message->addString('<ul>');
foreach ($errors as $string) {
$message->addString('<li>' . $string . '</li>');
}
$message->addString('</ul>');
}
$output = PMA_Util::getMessage($message, $sql_query);
if ($GLOBALS['is_ajax_request']) {
$response = PMA_Response::getInstance();
if ($message->isSuccess()) {
$routines = $GLOBALS['dbi']->getRoutines(
$db, $_REQUEST['item_type'], $_REQUEST['item_name']
);
$routine = $routines[0];
$response->addJSON(
'name',
htmlspecialchars(
/*overload*/mb_strtoupper($_REQUEST['item_name'])
)
);
$response->addJSON('new_row', PMA_RTN_getRowForList($routine));
$response->addJSON('insert', ! empty($routine));
$response->addJSON('message', $output);
} else {
$response->isSuccess(false);
$response->addJSON('message', $output);
}
exit;
}
}
$errors = PMA_RTN_handleRequestCreateOrEdit($errors, $db);
/**
* Display a form used to add/edit a routine, if necessary
@ -359,6 +167,288 @@ function PMA_RTN_handleEditor()
}
}
}
}
/**
* Handle request to create or edit a routine
*
* @param array $errors Errors
* @param string $db DB name
*
* @return array
*/
function PMA_RTN_handleRequestCreateOrEdit($errors, $db)
{
if (empty($_REQUEST['editor_process_add'])
&& empty($_REQUEST['editor_process_edit'])
) {
return $errors;
}
$sql_query = '';
$routine_query = PMA_RTN_getQueryFromRequest();
if (!count($errors)) { // set by PMA_RTN_getQueryFromRequest()
// Execute the created query
if (!empty($_REQUEST['editor_process_edit'])) {
$isProcOrFunc = in_array(
$_REQUEST['item_original_type'],
array('PROCEDURE', 'FUNCTION')
);
if (!$isProcOrFunc) {
$errors[] = sprintf(
__('Invalid routine type: "%s"'),
htmlspecialchars($_REQUEST['item_original_type'])
);
} else {
// Backup the old routine, in case something goes wrong
$create_routine = $GLOBALS['dbi']->getDefinition(
$db,
$_REQUEST['item_original_type'],
$_REQUEST['item_original_name']
);
$privilegesBackup = PMA_RTN_backupPrivileges();
$drop_routine = "DROP {$_REQUEST['item_original_type']} "
. PMA_Util::backquote($_REQUEST['item_original_name'])
. ";\n";
$result = $GLOBALS['dbi']->tryQuery($drop_routine);
if (!$result) {
$errors[] = sprintf(
__('The following query has failed: "%s"'),
htmlspecialchars($drop_routine)
)
. '<br />'
. __('MySQL said: ') . $GLOBALS['dbi']->getError(null);
} else {
list($newErrors, $message) = PMA_RTN_createRoutine(
$routine_query,
$create_routine,
$privilegesBackup
);
if (empty($newErrors)) {
$sql_query = $drop_routine . $sql_query;
} else {
$errors = array_merge($errors, $newErrors);
}
unset($newErrors);
if (null === $message) {
unset($message);
}
}
}
} else {
// 'Add a new routine' mode
$result = $GLOBALS['dbi']->tryQuery($routine_query);
if (!$result) {
$errors[] = sprintf(
__('The following query has failed: "%s"'),
htmlspecialchars($routine_query)
)
. '<br /><br />'
. __('MySQL said: ') . $GLOBALS['dbi']->getError(null);
} else {
$message = PMA_Message::success(
__('Routine %1$s has been created.')
);
$message->addParam(
PMA_Util::backquote($_REQUEST['item_name'])
);
$sql_query = $routine_query;
}
}
}
if (count($errors)) {
$message = PMA_Message::error(
__(
'One or more errors have occurred while'
. ' processing your request:'
)
);
$message->addString('<ul>');
foreach ($errors as $string) {
$message->addString('<li>' . $string . '</li>');
}
$message->addString('</ul>');
}
$output = PMA_Util::getMessage($message, $sql_query);
if (!$GLOBALS['is_ajax_request']) {
return $errors;
}
$response = PMA_Response::getInstance();
if (!$message->isSuccess()) {
$response->isSuccess(false);
$response->addJSON('message', $output);
exit;
}
$routines = $GLOBALS['dbi']->getRoutines(
$db,
$_REQUEST['item_type'],
$_REQUEST['item_name']
);
$routine = $routines[0];
$response->addJSON(
'name',
htmlspecialchars(
/*overload*/
mb_strtoupper($_REQUEST['item_name'])
)
);
$response->addJSON('new_row', PMA_RTN_getRowForList($routine));
$response->addJSON('insert', !empty($routine));
$response->addJSON('message', $output);
exit;
}
/**
* Backup the privileges
*
* @return array
*/
function PMA_RTN_backupPrivileges()
{
if (defined('PMA_DRIZZLE') && PMA_DRIZZLE) {
return array();
}
if (!(isset($GLOBALS['proc_priv']) && $GLOBALS['proc_priv']
&& isset($GLOBALS['flush_priv'])
&& $GLOBALS['flush_priv'])
) {
return array();
}
// Backup the Old Privileges before dropping
// if $_REQUEST['item_adjust_privileges'] set
if (!isset($_REQUEST['item_adjust_privileges'])
|| empty($_REQUEST['item_adjust_privileges'])
) {
return array();
}
$privilegesBackupQuery = 'SELECT * FROM ' . PMA_Util::backquote(
'mysql'
)
. '.' . PMA_Util::backquote('procs_priv')
. ' where Routine_name = "' . $_REQUEST['item_original_name']
. '" AND Routine_type = "' . $_REQUEST['item_original_type']
. '";';
$privilegesBackup = $GLOBALS['dbi']->fetchResult(
$privilegesBackupQuery,
0
);
return $privilegesBackup;
}
/**
* Create the routine
*
* @param string $routine_query Query to create routine
* @param string $create_routine Query to restore routine
* @param array $privilegesBackup Privileges backup
*
* @return array
*/
function PMA_RTN_createRoutine(
$routine_query,
$create_routine,
$privilegesBackup
) {
$result = $GLOBALS['dbi']->tryQuery($routine_query);
if (!$result) {
$errors = array();
$errors[] = sprintf(
__('The following query has failed: "%s"'),
htmlspecialchars($routine_query)
)
. '<br />'
. __('MySQL said: ') . $GLOBALS['dbi']->getError(null);
// We dropped the old routine,
// but were unable to create the new one
// Try to restore the backup query
$result = $GLOBALS['dbi']->tryQuery($create_routine);
$errors = checkResult(
$result,
__(
'Sorry, we failed to restore'
. ' the dropped routine.'
),
$create_routine,
$errors
);
return array($errors, null);
}
// Default value
$resultAdjust = false;
if (!defined('PMA_DRIZZLE') || !PMA_DRIZZLE) {
if (isset($GLOBALS['proc_priv']) && $GLOBALS['proc_priv']
&& isset($GLOBALS['flush_priv'])
&& $GLOBALS['flush_priv']
) {
// Insert all the previous privileges
// but with the new name and the new type
foreach ($privilegesBackup as $priv) {
$adjustProcPrivilege = 'INSERT INTO '
. PMA_Util::backquote('mysql') . '.'
. PMA_Util::backquote('procs_priv')
. ' VALUES("' . $priv[0] . '", "'
. $priv[1] . '", "' . $priv[2] . '", "'
. $_REQUEST['item_name'] . '", "'
. $_REQUEST['item_type'] . '", "'
. $priv[5] . '", "'
. $priv[6] . '", "'
. $priv[7] . '");';
$resultAdjust = $GLOBALS['dbi']->query(
$adjustProcPrivilege
);
}
}
}
$message = PMA_RTN_flushPrivileges($resultAdjust);
return array(array(), $message);
}
/**
* Flush privileges and get message
*
* @param bool $flushPrivileges Flush privileges
*
* @return PMA_Message
*/
function PMA_RTN_flushPrivileges($flushPrivileges)
{
if ($flushPrivileges) {
// Flush the Privileges
$flushPrivQuery = 'FLUSH PRIVILEGES;';
$GLOBALS['dbi']->query($flushPrivQuery);
$message = PMA_Message::success(
__(
'Routine %1$s has been modified. Privileges have been adjusted.'
)
);
} else {
$message = PMA_Message::success(
__('Routine %1$s has been modified.')
);
}
$message->addParam(
PMA_Util::backquote($_REQUEST['item_name'])
);
return $message;
} // end PMA_RTN_handleEditor()
/**

View File

@ -358,13 +358,24 @@ function PMA_getHtmlForNoticeEnableStatistics($url_query, $html)
. 'heavy traffic between the web server and the MySQL server.'
)
)->getDisplay();
$html = $html . $notice;
$html .= '<ul><li id="li_switch_dbstats"><strong>' . "\n";
$html .= '<a href="server_databases.php' . $url_query . '&amp;dbstats=1"'
. ' title="' . __('Enable Statistics') . '">' . "\n"
. ' ' . __('Enable Statistics');
$html .= '</a></strong><br />' . "\n";
$html .= '</li>' . "\n" . '</ul>' . "\n";
$html .= $notice;
$items = array();
$items[] = array(
'content' => '<strong>' . "\n"
. __('Enable Statistics')
. '</strong><br />' . "\n",
'class' => 'li_switch_dbstats',
'url' => array(
'href' => 'server_databases.php' . $url_query . '&amp;dbstats=1',
'title' => __('Enable Statistics')
),
);
include_once './libraries/Template.class.php';
$html .= PMA\Template::get('list/unordered')->render(
array('items' => $items,)
);
return $html;
}

View File

@ -30,6 +30,13 @@ function PMA_getHtmlForServerStatus($ServerStatusData)
//display the server state connection information
$retval .= PMA_getHtmlForServerStateConnections($ServerStatusData);
// display replication information
if ($GLOBALS['replication_info']['master']['status']
|| $GLOBALS['replication_info']['slave']['status']
) {
$retval .= PMA_getHtmlForReplicationInfo();
}
return $retval;
}
@ -69,48 +76,50 @@ function PMA_getHtmlForServerStateGeneralInfo($ServerStatusData)
) . "\n";
$retval .= '</p>';
return $retval;
}
/**
* Returns HTML to display replication information
*
* @return string HTML on replication
*/
function PMA_getHtmlForReplicationInfo()
{
$retval = '<p class="notice clearfloat">';
if ($GLOBALS['replication_info']['master']['status']
|| $GLOBALS['replication_info']['slave']['status']
&& $GLOBALS['replication_info']['slave']['status']
) {
$retval .= '<p class="notice">';
if ($GLOBALS['replication_info']['master']['status']
&& $GLOBALS['replication_info']['slave']['status']
) {
$retval .= __(
'This MySQL server works as <b>master</b> and '
. '<b>slave</b> in <b>replication</b> process.'
);
} elseif ($GLOBALS['replication_info']['master']['status']) {
$retval .= __(
'This MySQL server works as <b>master</b> '
. 'in <b>replication</b> process.'
);
} elseif ($GLOBALS['replication_info']['slave']['status']) {
$retval .= __(
'This MySQL server works as <b>slave</b> '
. 'in <b>replication</b> process.'
);
}
$retval .= '</p>';
$retval .= __(
'This MySQL server works as <b>master</b> and '
. '<b>slave</b> in <b>replication</b> process.'
);
} elseif ($GLOBALS['replication_info']['master']['status']) {
$retval .= __(
'This MySQL server works as <b>master</b> '
. 'in <b>replication</b> process.'
);
} elseif ($GLOBALS['replication_info']['slave']['status']) {
$retval .= __(
'This MySQL server works as <b>slave</b> '
. 'in <b>replication</b> process.'
);
}
$retval .= '</p>';
/*
* if the server works as master or slave in replication process,
* display useful information
*/
if ($GLOBALS['replication_info']['master']['status']
|| $GLOBALS['replication_info']['slave']['status']
) {
$retval .= '<hr class="clearfloat" />';
$retval .= '<h3><a name="replication">';
$retval .= __('Replication status');
$retval .= '</a></h3>';
foreach ($GLOBALS['replication_types'] as $type) {
if (isset($GLOBALS['replication_info'][$type]['status'])
&& $GLOBALS['replication_info'][$type]['status']
) {
$retval .= PMA_getHtmlForReplicationStatusTable($type);
}
$retval .= '<hr class="clearfloat" />';
$retval .= '<h3><a name="replication">';
$retval .= __('Replication status');
$retval .= '</a></h3>';
foreach ($GLOBALS['replication_types'] as $type) {
if (isset($GLOBALS['replication_info'][$type]['status'])
&& $GLOBALS['replication_info'][$type]['status']
) {
$retval .= PMA_getHtmlForReplicationStatusTable($type);
}
}

View File

@ -70,12 +70,13 @@ namespace SqlParser {
* `static::parse`.
*
* @param mixed $component The component to be built.
* @param array $options Parameters for building.
*
* @throws \Exception Not implemented yet.
*
* @return string
*/
public static function build($component)
public static function build($component, array $options = array())
{
// This method should be abstract, but it can't be both static and
// abstract.

View File

@ -31,47 +31,55 @@ class AlterOperation extends Component
* @var array
*/
public static $OPTIONS = array(
'ADD' => 3,
'ALTER' => 3,
'ANALYZE' => 3,
'CHANGE' => 3,
'CHECK' => 3,
'COALESCE' => 3,
'CONVERT' => 3,
'DISABLE' => 3,
'DISCARD' => 3,
'DROP' => 3,
'ENABLE' => 3,
'IMPORT' => 3,
'MODIFY' => 3,
'OPTIMIZE' => 3,
'ORDER' => 3,
'PARTITION' => 3,
'REBUILD' => 3,
'REMOVE' => 3,
'RENAME' => 3,
'REORGANIZE' => 3,
'REPAIR' => 3,
'COLUMN' => 4,
'CONSTRAINT' => 4,
'DEFAULT' => 4,
'TO' => 4,
'BY' => 4,
'FOREIGN' => 4,
'FULLTEXT' => 4,
'KEY' => 4,
'KEYS' => 4,
'PARTITIONING' => 4,
'PRIMARY KEY' => 4,
'SPATIAL' => 4,
'TABLESPACE' => 4,
'INDEX' => 4,
// table_options
'ENGINE' => array(1, 'var='),
'AUTO_INCREMENT' => array(1, 'var='),
'AVG_ROW_LENGTH' => array(1, 'var'),
'MAX_ROWS' => array(1, 'var'),
'ROW_FORMAT' => array(1, 'var'),
'DEFAULT CHARACTER SET' => array(5, 'var'),
'DEFAULT CHARSET' => array(5, 'var'),
'ADD' => 1,
'ALTER' => 1,
'ANALYZE' => 1,
'CHANGE' => 1,
'CHECK' => 1,
'COALESCE' => 1,
'CONVERT' => 1,
'DISABLE' => 1,
'DISCARD' => 1,
'DROP' => 1,
'ENABLE' => 1,
'IMPORT' => 1,
'MODIFY' => 1,
'OPTIMIZE' => 1,
'ORDER' => 1,
'PARTITION' => 1,
'REBUILD' => 1,
'REMOVE' => 1,
'RENAME' => 1,
'REORGANIZE' => 1,
'REPAIR' => 1,
'COLLATE' => array(6, 'var'),
'COLUMN' => 2,
'CONSTRAINT' => 2,
'DEFAULT' => 2,
'TO' => 2,
'BY' => 2,
'FOREIGN' => 2,
'FULLTEXT' => 2,
'KEY' => 2,
'KEYS' => 2,
'PARTITIONING' => 2,
'PRIMARY KEY' => 2,
'SPATIAL' => 2,
'TABLESPACE' => 2,
'INDEX' => 2,
'DEFAULT CHARACTER SET' => array(3, 'var'),
'DEFAULT CHARSET' => array(3, 'var'),
'COLLATE' => array(4, 'var'),
);
/**
@ -108,6 +116,7 @@ class AlterOperation extends Component
/**
* Counts brackets.
*
* @var int $brackets
*/
$brackets = 0;
@ -123,13 +132,15 @@ class AlterOperation extends Component
*
* 2 -------------------------[ , ]-----------------------> 0
*
* @var int
* @var int $state
*/
$state = 0;
for (; $list->idx < $list->count; ++$list->idx) {
/**
* Token parsed at this moment.
*
* @var Token $token
*/
$token = $list->tokens[$list->idx];
@ -191,7 +202,6 @@ class AlterOperation extends Component
__('Unrecognized alter operation.'),
$list->tokens[$list->idx]
);
return null;
}
--$list->idx;
@ -200,14 +210,15 @@ class AlterOperation extends Component
/**
* @param AlterOperation $component The component to be built.
* @param array $options Parameters for building.
*
* @return string
*/
public static function build($component)
public static function build($component, array $options = array())
{
$ret = OptionsArray::build($component->options) . ' ';
if (!empty($component->field)) {
$ret .= Expression::build($component->field) . ' ';
$ret = $component->options . ' ';
if ((isset($component->field)) && ($component->field !== '')) {
$ret .= $component->field . ' ';
}
$ret .= TokensList::build($component->unknown);
return $ret;

View File

@ -38,7 +38,8 @@ class Array2d extends Component
/**
* The number of values in each set.
* @var int
*
* @var int $count
*/
$count = -1;
@ -47,18 +48,20 @@ class Array2d extends Component
*
* Below are the states of the parser.
*
* 0 ----------------------[ array ]---------------------> 1
* 0 ----------------------[ array ]----------------------> 1
*
* 1 ------------------------[ , ]------------------------> 0
* 1 -----------------------[ else ]----------------------> -1
* 1 -----------------------[ else ]----------------------> (END)
*
* @var int
* @var int $state
*/
$state = 0;
for (; $list->idx < $list->count; ++$list->idx) {
/**
* Token parsed at this moment.
*
* @var Token $token
*/
$token = $list->tokens[$list->idx];
@ -118,4 +121,15 @@ class Array2d extends Component
--$list->idx;
return $ret;
}
/**
* @param ArrayObj[] $component The component to be built.
* @param array $options Parameters for building.
*
* @return string
*/
public static function build($component, array $options = array())
{
return ArrayObj::build($component);
}
}

View File

@ -56,11 +56,11 @@ class ArrayObj extends Component
* @param TokensList $list The list of tokens that are being parsed.
* @param array $options Parameters for parsing.
*
* @return ArrayObj
* @return mixed
*/
public static function parse(Parser $parser, TokensList $list, array $options = array())
{
$ret = new ArrayObj();
$ret = empty($options['type']) ? new ArrayObj() : array();
/**
* The state of the parser.
@ -72,15 +72,17 @@ class ArrayObj extends Component
* 1 ------------------[ array element ]-----------------> 2
*
* 2 ------------------------[ , ]-----------------------> 1
* 2 ------------------------[ ) ]-----------------------> -1
* 2 ------------------------[ ) ]-----------------------> (END)
*
* @var int
* @var int $state
*/
$state = 0;
for (; $list->idx < $list->count; ++$list->idx) {
/**
* Token parsed at this moment.
*
* @var Token $token
*/
$token = $list->tokens[$list->idx];
@ -109,8 +111,16 @@ class ArrayObj extends Component
// Empty array.
break;
}
$ret->values[] = $token->value;
$ret->raw[] = $token->token;
if (empty($options['type'])) {
$ret->values[] = $token->value;
$ret->raw[] = $token->token;
} else {
$ret[] = $options['type']::parse(
$parser,
$list,
empty($options['typeOptions']) ? array() : $options['typeOptions']
);
}
$state = 2;
} elseif ($state === 2) {
if (($token->type !== Token::TYPE_OPERATOR) || (($token->value !== ',') && ($token->value !== ')'))) {
@ -126,27 +136,25 @@ class ArrayObj extends Component
break;
}
}
}
return $ret;
}
/**
* @param ArrayObj $component The component to be built.
* @param ArrayObj|ArrayObj[] $component The component to be built.
* @param array $options Parameters for building.
*
* @return string
*/
public static function build($component)
public static function build($component, array $options = array())
{
$values = array();
if (!empty($component->raw)) {
$values = $component->raw;
if (is_array($component)) {
return implode(', ', $component);
} elseif (!empty($component->raw)) {
return '(' . implode(', ', $component->raw) . ')';
} else {
foreach ($component->values as $value) {
$values[] = $value;
}
return '(' . implode(', ', $component->values) . ')';
}
return '(' . implode(', ', $values) . ')';
}
}

View File

@ -95,6 +95,7 @@ class Condition extends Component
/**
* Counts brackets.
*
* @var int $brackets
*/
$brackets = 0;
@ -104,7 +105,8 @@ class Condition extends Component
* It is required to keep track of them because their structure contains
* the keyword `AND`, which is also an operator that delimits
* expressions.
* @var bool
*
* @var bool $betweenBefore
*/
$betweenBefore = false;
@ -112,6 +114,7 @@ class Condition extends Component
/**
* Token parsed at this moment.
*
* @var Token $token
*/
$token = $list->tokens[$list->idx];
@ -194,15 +197,16 @@ class Condition extends Component
/**
* @param Condition[] $component The component to be built.
* @param array $options Parameters for building.
*
* @return string
*/
public static function build($component)
public static function build($component, array $options = array())
{
$ret = array();
foreach ($component as $c) {
$ret[] = $c->expr;
if (is_array($component)) {
return implode(' ', $component);
} else {
return $component->expr;
}
return implode(' ', $ret);
}
}

View File

@ -173,13 +173,15 @@ class CreateDefinition extends Component
* 5 ------------------------[ , ]-----------------------> 1
* 5 ------------------------[ ) ]-----------------------> 6 (-1)
*
* @var int
* @var int $state
*/
$state = 0;
for (; $list->idx < $list->count; ++$list->idx) {
/**
* Token parsed at this moment.
*
* @var Token $token
*/
$token = $list->tokens[$list->idx];
@ -270,17 +272,14 @@ class CreateDefinition extends Component
/**
* @param CreateDefinition|CreateDefinition[] $component The component to be built.
* @param array $options Parameters for building.
*
* @return string
*/
public static function build($component)
public static function build($component, array $options = array())
{
if (is_array($component)) {
$ret = array();
foreach ($component as $c) {
$ret[] = static::build($c);
}
return "(\n" . implode(",\n", $ret) . "\n)";
return "(\n " . implode(",\n ", $component) . "\n)";
} else {
$tmp = '';
@ -288,23 +287,26 @@ class CreateDefinition extends Component
$tmp .= 'CONSTRAINT ';
}
if (!empty($component->name)) {
if ((isset($component->name)) && ($component->name !== '')) {
$tmp .= Context::escape($component->name) . ' ';
}
if (!empty($component->type)) {
$tmp .= DataType::build($component->type) . ' ';
$tmp .= DataType::build(
$component->type,
array('lowercase' => true)
) . ' ';
}
if (!empty($component->key)) {
$tmp .= Key::build($component->key) . ' ';
$tmp .= $component->key . ' ';
}
if (!empty($component->references)) {
$tmp .= 'REFERENCES ' . Reference::build($component->references) . ' ';
$tmp .= 'REFERENCES ' . $component->references . ' ';
}
$tmp .= OptionsArray::build($component->options);
$tmp .= $component->options;
return trim($tmp);
}

View File

@ -103,13 +103,15 @@ class DataType extends Component
*
* 1 ----------------[ size and options ]----------------> 2
*
* @var int
* @var int $state
*/
$state = 0;
for (; $list->idx < $list->count; ++$list->idx) {
/**
* Token parsed at this moment.
*
* @var Token $token
*/
$token = $list->tokens[$list->idx];
@ -149,18 +151,20 @@ class DataType extends Component
/**
* @param DataType $component The component to be built.
* @param array $options Parameters for building.
*
* @return string
*/
public static function build($component)
public static function build($component, array $options = array())
{
$tmp = '';
$name = (empty($options['lowercase'])) ?
$component->name : strtolower($component->name);
$parameters = '';
if (!empty($component->parameters)) {
$tmp = '(' . implode(', ', $component->parameters) . ')';
$parameters = '(' . implode(',', $component->parameters) . ')';
}
return trim(
$component->name . $tmp . ' '
. OptionsArray::build($component->options)
);
return trim($name . $parameters . ' ' . $component->options);
}
}

View File

@ -122,24 +122,28 @@ class Expression extends Component
/**
* Whether current tokens make an expression or a table reference.
*
* @var bool $isExpr
*/
$isExpr = false;
/**
* Whether a period was previously found.
*
* @var bool $dot
*/
$dot = false;
/**
* Whether an alias is expected. Is 2 if `AS` keyword was found.
*
* @var int $alias
*/
$alias = 0;
/**
* Counts brackets.
*
* @var int $brackets
*/
$brackets = 0;
@ -150,13 +154,16 @@ class Expression extends Component
* string, if function was previously found;
* true, if opening bracket was previously found;
* null, in any other case.
*
* @var string|bool $prev
*/
$prev = null;
for (; $list->idx < $list->count; ++$list->idx) {
/**
* Token parsed at this moment.
*
* @var Token $token
*/
$token = $list->tokens[$list->idx];
@ -343,32 +350,37 @@ class Expression extends Component
}
/**
* @param Expression $component The component to be built.
* @param Expression|Expression[] $component The component to be built.
* @param array $options Parameters for building.
*
* @return string
*/
public static function build($component)
public static function build($component, array $options = array())
{
if (!empty($component->expr)) {
$ret = $component->expr;
if (is_array($component)) {
return implode($component, ', ');
} else {
$fields = array();
if (!empty($component->database)) {
$fields[] = $component->database;
if (!empty($component->expr)) {
$ret = $component->expr;
} else {
$fields = array();
if ((isset($component->database)) && ($component->database !== '')) {
$fields[] = $component->database;
}
if ((isset($component->table)) && ($component->table !== '')) {
$fields[] = $component->table;
}
if ((isset($component->column)) && ($component->column !== '')) {
$fields[] = $component->column;
}
$ret = implode('.', Context::escape($fields));
}
if (!empty($component->table)) {
$fields[] = $component->table;
}
if (!empty($component->column)) {
$fields[] = $component->column;
}
$ret = implode('.', Context::escape($fields));
}
if (!empty($component->alias)) {
$ret .= ' AS ' . Context::escape($component->alias);
}
if (!empty($component->alias)) {
$ret .= ' AS ' . Context::escape($component->alias);
}
return $ret;
return $ret;
}
}
}

View File

@ -1,7 +1,7 @@
<?php
/**
* Parses a a list of expression delimited by a comma.
* Parses a a list of expressions delimited by a comma.
*
* @package SqlParser
* @subpackage Components
@ -14,7 +14,7 @@ use SqlParser\Token;
use SqlParser\TokensList;
/**
* Parses a a list of expression delimited by a comma.
* Parses a a list of expressions delimited by a comma.
*
* @category Keywords
* @package SqlParser
@ -44,15 +44,17 @@ class ExpressionArray extends Component
* 0 ----------------------[ array ]---------------------> 1
*
* 1 ------------------------[ , ]------------------------> 0
* 1 -----------------------[ else ]----------------------> -1
* 1 -----------------------[ else ]----------------------> (END)
*
* @var int
* @var int $state
*/
$state = 0;
for (; $list->idx < $list->count; ++$list->idx) {
/**
* Token parsed at this moment.
*
* @var Token $token
*/
$token = $list->tokens[$list->idx];
@ -104,10 +106,11 @@ class ExpressionArray extends Component
/**
* @param Expression[] $component The component to be built.
* @param array $options Parameters for building.
*
* @return string
*/
public static function build($component)
public static function build($component, array $options = array())
{
$ret = array();
foreach ($component as $frag) {

View File

@ -73,15 +73,17 @@ class FunctionCall extends Component
*
* 0 ----------------------[ name ]-----------------------> 1
*
* 1 --------------------[ parameters ]-------------------> -1
* 1 --------------------[ parameters ]-------------------> (END)
*
* @var int
* @var int $state
*/
$state = 0;
for (; $list->idx < $list->count; ++$list->idx) {
/**
* Token parsed at this moment.
*
* @var Token $token
*/
$token = $list->tokens[$list->idx];
@ -113,11 +115,12 @@ class FunctionCall extends Component
/**
* @param FunctionCall $component The component to be built.
* @param array $options Parameters for building.
*
* @return string
*/
public static function build($component)
public static function build($component, array $options = array())
{
return $component->name . ArrayObj::build($component->parameters);
return $component->name . $component->parameters;
}
}

View File

@ -65,17 +65,19 @@ class IntoKeyword extends Component
* 0 -----------------------[ name ]----------------------> 1
* 0 ---------------------[ OUTFILE ]---------------------> 2
*
* 1 ------------------------[ ( ]------------------------> -1
* 1 ------------------------[ ( ]------------------------> (END)
*
* 2 ---------------------[ filename ]--------------------> 1
*
* @var int
* @var int $state
*/
$state = 0;
for (; $list->idx < $list->count; ++$list->idx) {
/**
* Token parsed at this moment.
*
* @var Token $token
*/
$token = $list->tokens[$list->idx];
@ -128,4 +130,21 @@ class IntoKeyword extends Component
--$list->idx;
return $ret;
}
/**
* @param IntoKeyword $component The component to be built.
* @param array $options Parameters for building.
*
* @return string
*/
public static function build($component, array $options = array())
{
if ($component->dest instanceof Expression) {
$columns = !empty($component->columns) ?
'(' . implode(', ', $component->columns) . ')' : '';
return $component->dest . $columns;
} else {
return 'OUTFILE "' . $component->dest . '"';
}
}
}

View File

@ -71,7 +71,7 @@ class JoinKeyword extends Component
{
$ret = array();
$expr = new JoinKeyword();;
$expr = new JoinKeyword();
/**
* The state of the parser.
@ -86,7 +86,7 @@ class JoinKeyword extends Component
*
* 3 --------------------[ conditions ]-------------------> 0
*
* @var int
* @var int $state
*/
$state = 0;
@ -98,8 +98,10 @@ class JoinKeyword extends Component
}
for (; $list->idx < $list->count; ++$list->idx) {
/**
* Token parsed at this moment.
*
* @var Token $token
*/
$token = $list->tokens[$list->idx];
@ -149,15 +151,16 @@ class JoinKeyword extends Component
/**
* @param JoinKeyword[] $component The component to be built.
* @param array $options Parameters for building.
*
* @return string
*/
public static function build($component)
public static function build($component, array $options = array())
{
$ret = array();
foreach ($component as $c) {
$ret[] = (($c->type === 'JOIN') ? 'JOIN ' : ($c->type . ' JOIN ')) .
Expression::build($c->expr) . ' ON ' . Condition::build($c->on);
$ret[] = (($c->type === 'JOIN') ? 'JOIN ' : ($c->type . ' JOIN '))
. $c->expr . ' ON ' . Condition::build($c->on);
}
return implode(' ', $ret);
}

View File

@ -107,13 +107,15 @@ class Key extends Component
*
* 2 ---------------------[ options ]---------------------> 3
*
* @var int
* @var int $state
*/
$state = 0;
for (; $list->idx < $list->count; ++$list->idx) {
/**
* Token parsed at this moment.
*
* @var Token $token
*/
$token = $list->tokens[$list->idx];
@ -143,7 +145,6 @@ class Key extends Component
++$list->idx;
break;
}
}
--$list->idx;
@ -151,18 +152,19 @@ class Key extends Component
}
/**
* @param Key $component The component to be built.
* @param Key $component The component to be built.
* @param array $options Parameters for building.
*
* @return string
*/
public static function build($component)
public static function build($component, array $options = array())
{
$ret = $component->type . ' ';
if (!empty($component->name)) {
$ret .= Context::escape($component->name) . ' ';
}
$ret .= '(' . implode(', ', Context::escape($component->columns)) . ')';
$ret .= OptionsArray::build($component->options);
$ret .= '(' . implode(',', Context::escape($component->columns)) . ') '
. $component->options;
return trim($ret);
}
}

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