From a2335316edadf993e3ffc9c3c50338c4daed8042 Mon Sep 17 00:00:00 2001 From: Sean Burke Date: Sun, 16 Feb 2014 23:08:30 -0800 Subject: [PATCH] updating phpMyAdmin --- phpMyAdmin/CONTRIBUTING.md | 21 + phpMyAdmin/ChangeLog | 604 +- phpMyAdmin/README | 34 +- phpMyAdmin/RELEASE-DATE-4.1.7 | 1 + phpMyAdmin/browse_foreigners.php | 318 +- phpMyAdmin/changelog.php | 66 +- phpMyAdmin/chk_rel.php | 22 +- phpMyAdmin/composer.json | 27 + phpMyAdmin/config.sample.inc.php | 56 +- phpMyAdmin/db_create.php | 101 +- phpMyAdmin/db_datadict.php | 180 +- phpMyAdmin/db_events.php | 18 +- phpMyAdmin/db_export.php | 58 +- phpMyAdmin/db_import.php | 22 +- phpMyAdmin/db_operations.php | 590 +- phpMyAdmin/db_printview.php | 258 +- phpMyAdmin/db_qbe.php | 962 +- phpMyAdmin/db_routines.php | 25 +- phpMyAdmin/db_search.php | 356 +- phpMyAdmin/db_sql.php | 43 +- phpMyAdmin/db_structure.php | 706 +- phpMyAdmin/db_tracking.php | 150 +- phpMyAdmin/db_triggers.php | 16 +- phpMyAdmin/doc/Makefile | 153 + phpMyAdmin/doc/_ext/configext.py | 189 + phpMyAdmin/doc/_ext/configext.pyc | Bin 0 -> 7773 bytes phpMyAdmin/doc/conf.py | 292 + phpMyAdmin/doc/config.rst | 2813 ++++ phpMyAdmin/doc/copyright.rst | 30 + phpMyAdmin/doc/credits.rst | 626 + phpMyAdmin/doc/developers.rst | 12 + phpMyAdmin/doc/doctrees/config.doctree | Bin 0 -> 802067 bytes phpMyAdmin/doc/doctrees/copyright.doctree | Bin 0 -> 6619 bytes phpMyAdmin/doc/doctrees/credits.doctree | Bin 0 -> 119697 bytes phpMyAdmin/doc/doctrees/developers.doctree | Bin 0 -> 4687 bytes phpMyAdmin/doc/doctrees/environment.pickle | Bin 0 -> 224370 bytes phpMyAdmin/doc/doctrees/faq.doctree | Bin 0 -> 556274 bytes phpMyAdmin/doc/doctrees/glossary.doctree | Bin 0 -> 99314 bytes phpMyAdmin/doc/doctrees/index.doctree | Bin 0 -> 5709 bytes phpMyAdmin/doc/doctrees/intro.doctree | Bin 0 -> 24029 bytes phpMyAdmin/doc/doctrees/other.doctree | Bin 0 -> 5042 bytes phpMyAdmin/doc/doctrees/privileges.doctree | Bin 0 -> 11187 bytes phpMyAdmin/doc/doctrees/require.doctree | Bin 0 -> 14973 bytes phpMyAdmin/doc/doctrees/setup.doctree | Bin 0 -> 134547 bytes .../doc/doctrees/transformations.doctree | Bin 0 -> 31635 bytes phpMyAdmin/doc/doctrees/user.doctree | Bin 0 -> 2834 bytes phpMyAdmin/doc/doctrees/vendors.doctree | Bin 0 -> 7769 bytes phpMyAdmin/doc/faq.rst | 2015 +++ phpMyAdmin/doc/glossary.rst | 406 + phpMyAdmin/doc/html/.buildinfo | 4 + phpMyAdmin/doc/html/_sources/config.txt | 2813 ++++ phpMyAdmin/doc/html/_sources/copyright.txt | 30 + phpMyAdmin/doc/html/_sources/credits.txt | 626 + phpMyAdmin/doc/html/_sources/developers.txt | 12 + phpMyAdmin/doc/html/_sources/faq.txt | 2015 +++ phpMyAdmin/doc/html/_sources/glossary.txt | 406 + phpMyAdmin/doc/html/_sources/index.txt | 32 + phpMyAdmin/doc/html/_sources/intro.txt | 68 + phpMyAdmin/doc/html/_sources/other.txt | 18 + phpMyAdmin/doc/html/_sources/privileges.txt | 50 + phpMyAdmin/doc/html/_sources/require.txt | 53 + phpMyAdmin/doc/html/_sources/setup.txt | 493 + .../doc/html/_sources/transformations.txt | 138 + phpMyAdmin/doc/html/_sources/user.txt | 9 + phpMyAdmin/doc/html/_sources/vendors.txt | 34 + phpMyAdmin/doc/html/_static/ajax-loader.gif | Bin 0 -> 673 bytes phpMyAdmin/doc/html/_static/basic.css | 540 + .../doc/html/_static/comment-bright.png | Bin 0 -> 3500 bytes phpMyAdmin/doc/html/_static/comment-close.png | Bin 0 -> 3578 bytes phpMyAdmin/doc/html/_static/comment.png | Bin 0 -> 3445 bytes phpMyAdmin/doc/html/_static/default.css | 256 + phpMyAdmin/doc/html/_static/doctools.js | 247 + phpMyAdmin/doc/html/_static/down-pressed.png | Bin 0 -> 368 bytes phpMyAdmin/doc/html/_static/down.png | Bin 0 -> 363 bytes phpMyAdmin/doc/html/_static/file.png | Bin 0 -> 392 bytes phpMyAdmin/doc/html/_static/jquery.js | 9404 +++++++++++++ phpMyAdmin/doc/html/_static/minus.png | Bin 0 -> 199 bytes phpMyAdmin/doc/html/_static/plus.png | Bin 0 -> 199 bytes phpMyAdmin/doc/html/_static/pygments.css | 62 + phpMyAdmin/doc/html/_static/searchtools.js | 560 + phpMyAdmin/doc/html/_static/sidebar.js | 151 + phpMyAdmin/doc/html/_static/underscore.js | 807 ++ phpMyAdmin/doc/html/_static/up-pressed.png | Bin 0 -> 372 bytes phpMyAdmin/doc/html/_static/up.png | Bin 0 -> 363 bytes phpMyAdmin/doc/html/_static/websupport.js | 808 ++ phpMyAdmin/doc/html/config.html | 5015 +++++++ phpMyAdmin/doc/html/copyright.html | 134 + phpMyAdmin/doc/html/credits.html | 684 + phpMyAdmin/doc/html/developers.html | 118 + phpMyAdmin/doc/html/faq.html | 1791 +++ phpMyAdmin/doc/html/genindex.html | 3847 +++++ phpMyAdmin/doc/html/glossary.html | 627 + phpMyAdmin/doc/html/index.html | 207 + phpMyAdmin/doc/html/intro.html | 182 + phpMyAdmin/doc/html/objects.inv | Bin 0 -> 9663 bytes phpMyAdmin/doc/html/other.html | 135 + phpMyAdmin/doc/html/privileges.html | 169 + phpMyAdmin/doc/html/require.html | 168 + phpMyAdmin/doc/html/search.html | 100 + phpMyAdmin/doc/html/searchindex.js | 1 + phpMyAdmin/doc/html/setup.html | 549 + phpMyAdmin/doc/html/transformations.html | 240 + phpMyAdmin/doc/html/user.html | 135 + phpMyAdmin/doc/html/vendors.html | 147 + phpMyAdmin/doc/index.rst | 32 + phpMyAdmin/doc/intro.rst | 68 + phpMyAdmin/doc/make.bat | 190 + phpMyAdmin/doc/other.rst | 18 + phpMyAdmin/doc/privileges.rst | 50 + phpMyAdmin/doc/require.rst | 53 + phpMyAdmin/doc/setup.rst | 493 + phpMyAdmin/doc/transformations.rst | 138 + phpMyAdmin/doc/user.rst | 9 + phpMyAdmin/doc/vendors.rst | 34 + phpMyAdmin/error_report.php | 95 + phpMyAdmin/examples/config.manyhosts.inc.php | 94 +- phpMyAdmin/examples/create_tables.sql | 120 +- phpMyAdmin/examples/create_tables_drizzle.sql | 119 +- phpMyAdmin/examples/openid.php | 48 +- phpMyAdmin/examples/signon-script.php | 5 +- phpMyAdmin/examples/signon.php | 48 +- .../examples/upgrade_tables_mysql_4_1_2+.sql | 84 +- phpMyAdmin/export.php | 1386 +- phpMyAdmin/file_echo.php | 17 +- phpMyAdmin/gis_data_editor.php | 607 +- phpMyAdmin/import.php | 520 +- phpMyAdmin/import_status.php | 74 +- phpMyAdmin/index.php | 753 +- phpMyAdmin/js/OpenStreetMap.js | 130 +- phpMyAdmin/js/ajax.js | 860 ++ phpMyAdmin/js/canvg/canvg.js | 2605 +++- phpMyAdmin/js/canvg/flashcanvas.js | 25 - phpMyAdmin/js/canvg/flashcanvas.swf | Bin 21235 -> 0 bytes phpMyAdmin/js/chart.js | 546 + phpMyAdmin/js/codemirror/LICENSE | 6 +- .../js/codemirror/addon/runmode/runmode.js | 56 + phpMyAdmin/js/codemirror/lib/codemirror.js | 5893 +++++++- phpMyAdmin/js/codemirror/mode/mysql/mysql.js | 7 - phpMyAdmin/js/codemirror/mode/sql/sql.js | 349 + phpMyAdmin/js/common.js | 312 +- phpMyAdmin/js/config.js | 822 +- phpMyAdmin/js/cross_framing_protection.js | 10 +- phpMyAdmin/js/date.js | 9 - phpMyAdmin/js/db_operations.js | 118 +- phpMyAdmin/js/db_search.js | 235 +- phpMyAdmin/js/db_structure.js | 398 +- phpMyAdmin/js/doclinks.js | 365 + phpMyAdmin/js/dom-drag.js | 6 - phpMyAdmin/js/error_report.js | 310 + phpMyAdmin/js/export.js | 295 +- phpMyAdmin/js/functions.js | 4200 +++++- phpMyAdmin/js/get_image.js.php | 13 +- phpMyAdmin/js/get_scripts.js.php | 45 + phpMyAdmin/js/gis_data_editor.js | 409 +- phpMyAdmin/js/import.js | 106 +- phpMyAdmin/js/indexes.js | 211 +- phpMyAdmin/js/jqplot/excanvas.js | 1474 +- phpMyAdmin/js/jqplot/jquery.jqplot.js | 11683 +++++++++++++++- .../js/jqplot/plugins/jqplot.barRenderer.js | 820 +- .../js/jqplot/plugins/jqplot.byteFormatter.js | 46 + .../plugins/jqplot.canvasAxisLabelRenderer.js | 208 +- .../plugins/jqplot.canvasTextRenderer.js | 480 +- .../plugins/jqplot.categoryAxisRenderer.js | 690 +- phpMyAdmin/js/jqplot/plugins/jqplot.cursor.js | 1143 +- .../jqplot/plugins/jqplot.dateAxisRenderer.js | 755 +- .../js/jqplot/plugins/jqplot.highlighter.js | 479 +- .../js/jqplot/plugins/jqplot.pieRenderer.js | 929 +- .../js/jqplot/plugins/jqplot.pointLabels.js | 388 +- phpMyAdmin/js/jquery/MIT-LICENSE.txt | 21 + phpMyAdmin/js/jquery/jquery-1.6.2.js | 180 - phpMyAdmin/js/jquery/jquery-1.8.3.min.js | 2 + .../js/jquery/jquery-ui-1.8.16.custom.js | 405 - .../js/jquery/jquery-ui-1.9.2.custom.min.js | 6 + .../js/jquery/jquery-ui-timepicker-addon.js | 2128 +++ .../js/jquery/jquery.ba-hashchange-1.3.js | 390 + phpMyAdmin/js/jquery/jquery.cookie.js | 93 +- phpMyAdmin/js/jquery/jquery.debounce-1.0.5.js | 71 + phpMyAdmin/js/jquery/jquery.event.drag-2.0.js | 10 - phpMyAdmin/js/jquery/jquery.event.drag-2.2.js | 402 + phpMyAdmin/js/jquery/jquery.fullscreen.js | 60 + phpMyAdmin/js/jquery/jquery.json-2.2.js | 4 - phpMyAdmin/js/jquery/jquery.json-2.4.js | 199 + .../js/jquery/jquery.menuResizer-1.0.js | 181 + phpMyAdmin/js/jquery/jquery.mousewheel.js | 86 +- phpMyAdmin/js/jquery/jquery.qtip-1.0.0-rc3.js | 73 - phpMyAdmin/js/jquery/jquery.sortableTable.js | 279 +- phpMyAdmin/js/jquery/jquery.sprintf.js | 74 +- phpMyAdmin/js/jquery/jquery.svg.js | 1430 +- phpMyAdmin/js/jquery/jquery.tablesorter.js | 1056 +- phpMyAdmin/js/jquery/src/README | 9 + .../src/jquery-ui/jquery.ui.accordion.js | 731 + .../src/jquery-ui/jquery.ui.autocomplete.js | 602 + .../jquery/src/jquery-ui/jquery.ui.button.js | 418 + .../js/jquery/src/jquery-ui/jquery.ui.core.js | 356 + .../src/jquery-ui/jquery.ui.datepicker.js | 1846 +++ .../jquery/src/jquery-ui/jquery.ui.dialog.js | 858 ++ .../src/jquery-ui/jquery.ui.draggable.js | 836 ++ .../src/jquery-ui/jquery.ui.droppable.js | 294 + .../src/jquery-ui/jquery.ui.effect-blind.js | 82 + .../src/jquery-ui/jquery.ui.effect-bounce.js | 113 + .../src/jquery-ui/jquery.ui.effect-clip.js | 67 + .../src/jquery-ui/jquery.ui.effect-drop.js | 65 + .../src/jquery-ui/jquery.ui.effect-explode.js | 97 + .../src/jquery-ui/jquery.ui.effect-fade.js | 30 + .../src/jquery-ui/jquery.ui.effect-fold.js | 76 + .../jquery-ui/jquery.ui.effect-highlight.js | 50 + .../src/jquery-ui/jquery.ui.effect-pulsate.js | 63 + .../src/jquery-ui/jquery.ui.effect-scale.js | 318 + .../src/jquery-ui/jquery.ui.effect-shake.js | 74 + .../src/jquery-ui/jquery.ui.effect-slide.js | 64 + .../jquery-ui/jquery.ui.effect-transfer.js | 47 + .../jquery/src/jquery-ui/jquery.ui.effect.js | 1276 ++ .../js/jquery/src/jquery-ui/jquery.ui.menu.js | 610 + .../jquery/src/jquery-ui/jquery.ui.mouse.js | 169 + .../src/jquery-ui/jquery.ui.position.js | 517 + .../src/jquery-ui/jquery.ui.progressbar.js | 105 + .../src/jquery-ui/jquery.ui.resizable.js | 801 ++ .../src/jquery-ui/jquery.ui.selectable.js | 261 + .../jquery/src/jquery-ui/jquery.ui.slider.js | 644 + .../src/jquery-ui/jquery.ui.sortable.js | 1096 ++ .../jquery/src/jquery-ui/jquery.ui.spinner.js | 478 + .../js/jquery/src/jquery-ui/jquery.ui.tabs.js | 1366 ++ .../jquery/src/jquery-ui/jquery.ui.tooltip.js | 398 + .../jquery/src/jquery-ui/jquery.ui.widget.js | 528 + phpMyAdmin/js/jquery/src/jquery/ajax.js | 855 ++ phpMyAdmin/js/jquery/src/jquery/ajax/jsonp.js | 80 + .../js/jquery/src/jquery/ajax/script.js | 57 + phpMyAdmin/js/jquery/src/jquery/ajax/xhr.js | 111 + phpMyAdmin/js/jquery/src/jquery/attributes.js | 502 + phpMyAdmin/js/jquery/src/jquery/callbacks.js | 197 + phpMyAdmin/js/jquery/src/jquery/core.js | 846 ++ phpMyAdmin/js/jquery/src/jquery/css.js | 563 + phpMyAdmin/js/jquery/src/jquery/data.js | 356 + phpMyAdmin/js/jquery/src/jquery/deferred.js | 141 + phpMyAdmin/js/jquery/src/jquery/deprecated.js | 11 + phpMyAdmin/js/jquery/src/jquery/dimensions.js | 41 + phpMyAdmin/js/jquery/src/jquery/effects.js | 730 + .../js/jquery/src/jquery/event-alias.js | 32 + phpMyAdmin/js/jquery/src/jquery/event.js | 829 ++ phpMyAdmin/js/jquery/src/jquery/intro.js | 54 + .../js/jquery/src/jquery/manipulation.js | 577 + phpMyAdmin/js/jquery/src/jquery/offset.js | 167 + phpMyAdmin/js/jquery/src/jquery/outro.js | 6 + phpMyAdmin/js/jquery/src/jquery/queue.js | 145 + .../js/jquery/src/jquery/selector-native.js | 164 + phpMyAdmin/js/jquery/src/jquery/serialize.js | 99 + .../js/jquery/src/jquery/sizzle-jquery.js | 7 + phpMyAdmin/js/jquery/src/jquery/support.js | 113 + phpMyAdmin/js/jquery/src/jquery/traversing.js | 283 + phpMyAdmin/js/jquery/src/jquery/wrap.js | 69 + phpMyAdmin/js/jquery/timepicker.js | 43 - phpMyAdmin/js/keyhandler.js | 105 +- phpMyAdmin/js/line_counts.php | 154 + phpMyAdmin/js/makegrid.js | 1949 ++- phpMyAdmin/js/messages.php | 193 +- phpMyAdmin/js/navigation.js | 1211 +- phpMyAdmin/js/openlayers/OpenLayers.js | 4289 +++--- phpMyAdmin/js/pmd/ajax.js | 67 +- phpMyAdmin/js/pmd/history.js | 820 +- phpMyAdmin/js/pmd/iecanvas.js | 156 +- phpMyAdmin/js/pmd/init.js | 31 + phpMyAdmin/js/pmd/move.js | 1332 +- phpMyAdmin/js/querywindow.js | 27 +- phpMyAdmin/js/replication.js | 76 +- phpMyAdmin/js/rte.js | 903 ++ phpMyAdmin/js/rte/common.js | 9 - phpMyAdmin/js/rte/events.js | 1 - phpMyAdmin/js/rte/routines.js | 15 - phpMyAdmin/js/rte/triggers.js | 1 - phpMyAdmin/js/server_databases.js | 130 + phpMyAdmin/js/server_plugins.js | 31 +- phpMyAdmin/js/server_privileges.js | 703 +- phpMyAdmin/js/server_status.js | 26 - phpMyAdmin/js/server_status_advisor.js | 93 + phpMyAdmin/js/server_status_monitor.js | 2203 ++- phpMyAdmin/js/server_status_queries.js | 40 + phpMyAdmin/js/server_status_sorter.js | 99 + phpMyAdmin/js/server_status_variables.js | 110 + phpMyAdmin/js/server_synchronize.js | 13 - phpMyAdmin/js/server_user_groups.js | 42 + phpMyAdmin/js/server_variables.js | 165 +- phpMyAdmin/js/sql.js | 510 +- phpMyAdmin/js/tbl_change.js | 544 +- phpMyAdmin/js/tbl_chart.js | 336 +- phpMyAdmin/js/tbl_find_replace.js | 47 + phpMyAdmin/js/tbl_gis_visualization.js | 363 +- phpMyAdmin/js/tbl_relation.js | 136 +- phpMyAdmin/js/tbl_select.js | 233 +- phpMyAdmin/js/tbl_structure.js | 528 +- phpMyAdmin/js/tbl_zoom_plot_jqplot.js | 636 +- phpMyAdmin/js/tracekit/tracekit.js | 1114 ++ phpMyAdmin/js/update-location.js | 2 - phpMyAdmin/libraries/.htaccess | 3 - phpMyAdmin/libraries/Advisor.class.php | 318 +- phpMyAdmin/libraries/Config.class.php | 874 +- phpMyAdmin/libraries/DBQbe.class.php | 1374 ++ .../libraries/DatabaseInterface.class.php | 2353 ++++ phpMyAdmin/libraries/DbSearch.class.php | 499 + phpMyAdmin/libraries/DisplayResults.class.php | 6036 ++++++++ phpMyAdmin/libraries/Error.class.php | 214 +- phpMyAdmin/libraries/Error_Handler.class.php | 262 +- phpMyAdmin/libraries/File.class.php | 604 +- phpMyAdmin/libraries/Footer.class.php | 319 + phpMyAdmin/libraries/Header.class.php | 698 + phpMyAdmin/libraries/Index.class.php | 394 +- phpMyAdmin/libraries/List.class.php | 45 +- phpMyAdmin/libraries/List_Database.class.php | 380 +- phpMyAdmin/libraries/Menu.class.php | 588 + phpMyAdmin/libraries/Message.class.php | 304 +- .../libraries/OutputBuffering.class.php | 142 + phpMyAdmin/libraries/PDF.class.php | 75 +- phpMyAdmin/libraries/PMA.php | 56 +- phpMyAdmin/libraries/Partition.class.php | 41 +- phpMyAdmin/libraries/RecentTable.class.php | 97 +- phpMyAdmin/libraries/Response.class.php | 380 + phpMyAdmin/libraries/Scripts.class.php | 248 + .../libraries/ServerStatusData.class.php | 407 + phpMyAdmin/libraries/StorageEngine.class.php | 98 +- phpMyAdmin/libraries/String.class.php | 261 + .../libraries/StringAbstractType.class.php | 35 + phpMyAdmin/libraries/StringByte.int.php | 60 + phpMyAdmin/libraries/StringCType.class.php | 110 + phpMyAdmin/libraries/StringMB.class.php | 92 + phpMyAdmin/libraries/StringNative.class.php | 87 + .../libraries/StringNativeType.class.php | 138 + phpMyAdmin/libraries/StringType.int.php | 85 + phpMyAdmin/libraries/Table.class.php | 1023 +- phpMyAdmin/libraries/TableSearch.class.php | 1469 ++ phpMyAdmin/libraries/Theme.class.php | 364 +- phpMyAdmin/libraries/Theme_Manager.class.php | 217 +- phpMyAdmin/libraries/Tracker.class.php | 340 +- phpMyAdmin/libraries/Types.class.php | 986 ++ phpMyAdmin/libraries/Util.class.php | 4366 ++++++ phpMyAdmin/libraries/advisory_rules.txt | 117 +- phpMyAdmin/libraries/auth/config.auth.lib.php | 134 - phpMyAdmin/libraries/auth/cookie.auth.lib.php | 600 - phpMyAdmin/libraries/auth/http.auth.lib.php | 237 - phpMyAdmin/libraries/auth/signon.auth.lib.php | 249 - .../libraries/bfShapeFiles/ShapeFile.lib.php | 35 +- phpMyAdmin/libraries/blobstreaming.lib.php | 582 - phpMyAdmin/libraries/blowfish.php | 535 - phpMyAdmin/libraries/bookmark.lib.php | 135 +- .../libraries/browse_foreigners.lib.php | 415 + .../libraries/build_html_for_db.lib.php | 105 +- .../libraries/charset_conversion.lib.php | 65 +- .../libraries/check_user_privileges.lib.php | 109 +- phpMyAdmin/libraries/cleanup.lib.php | 14 +- phpMyAdmin/libraries/common.inc.php | 476 +- phpMyAdmin/libraries/common.lib.php | 3840 ----- phpMyAdmin/libraries/config.default.php | 791 +- phpMyAdmin/libraries/config.values.php | 247 +- .../libraries/config/ConfigFile.class.php | 287 +- phpMyAdmin/libraries/config/Form.class.php | 64 +- .../libraries/config/FormDisplay.class.php | 594 +- .../libraries/config/FormDisplay.tpl.php | 429 +- .../libraries/config/Validator.class.php | 598 + .../libraries/config/config_functions.lib.php | 20 +- phpMyAdmin/libraries/config/messages.inc.php | 241 +- phpMyAdmin/libraries/config/setup.forms.php | 130 +- .../config/user_preferences.forms.php | 90 +- phpMyAdmin/libraries/config/validate.lib.php | 481 - phpMyAdmin/libraries/core.lib.php | 480 +- phpMyAdmin/libraries/create_addfield.lib.php | 325 + .../data_dictionary_relations.lib.php | 6 +- phpMyAdmin/libraries/data_drizzle.inc.php | 225 - phpMyAdmin/libraries/data_mysql.inc.php | 286 - .../libraries/database_interface.inc.php | 87 + .../libraries/database_interface.lib.php | 1855 --- phpMyAdmin/libraries/db_common.inc.php | 54 +- phpMyAdmin/libraries/db_info.inc.php | 260 +- phpMyAdmin/libraries/db_links.inc.php | 158 - phpMyAdmin/libraries/db_structure.lib.php | 125 - phpMyAdmin/libraries/db_table_exists.lib.php | 70 +- phpMyAdmin/libraries/dbi/DBIDrizzle.class.php | 712 + phpMyAdmin/libraries/dbi/DBIDummy.class.php | 869 ++ phpMyAdmin/libraries/dbi/DBIExtension.int.php | 248 + phpMyAdmin/libraries/dbi/DBIMysql.class.php | 570 + phpMyAdmin/libraries/dbi/DBIMysqli.class.php | 764 + .../libraries/dbi/drizzle-wrappers.lib.php | 345 +- phpMyAdmin/libraries/dbi/drizzle.dbi.lib.php | 603 - phpMyAdmin/libraries/dbi/mysql.dbi.lib.php | 476 - phpMyAdmin/libraries/dbi/mysqli.dbi.lib.php | 679 - .../libraries/display_change_password.lib.php | 142 +- .../libraries/display_create_database.lib.php | 60 +- .../libraries/display_create_table.lib.php | 66 +- phpMyAdmin/libraries/display_export.inc.php | 72 + phpMyAdmin/libraries/display_export.lib.php | 972 +- .../libraries/display_git_revision.lib.php | 83 + phpMyAdmin/libraries/display_import.inc.php | 54 + phpMyAdmin/libraries/display_import.lib.php | 807 +- .../libraries/display_import_ajax.lib.php | 80 +- .../libraries/display_select_lang.lib.php | 133 +- .../libraries/display_structure.inc.php | 267 + phpMyAdmin/libraries/display_tbl.lib.php | 3032 ---- phpMyAdmin/libraries/engines/bdb.lib.php | 18 +- .../libraries/engines/berkeleydb.lib.php | 8 +- phpMyAdmin/libraries/engines/binlog.lib.php | 7 +- phpMyAdmin/libraries/engines/innobase.lib.php | 5 + phpMyAdmin/libraries/engines/innodb.lib.php | 327 +- phpMyAdmin/libraries/engines/memory.lib.php | 12 +- phpMyAdmin/libraries/engines/merge.lib.php | 6 + .../libraries/engines/mrg_myisam.lib.php | 9 +- phpMyAdmin/libraries/engines/myisam.lib.php | 12 +- .../libraries/engines/ndbcluster.lib.php | 21 +- phpMyAdmin/libraries/engines/pbms.lib.php | 106 - phpMyAdmin/libraries/engines/pbxt.lib.php | 50 +- .../engines/performance_schema.lib.php | 28 + phpMyAdmin/libraries/error.inc.php | 12 +- phpMyAdmin/libraries/error_report.lib.php | 358 + phpMyAdmin/libraries/export/codegen.php | 334 - phpMyAdmin/libraries/export/csv.php | 222 - phpMyAdmin/libraries/export/excel.php | 43 - phpMyAdmin/libraries/export/htmlword.php | 330 - phpMyAdmin/libraries/export/json.php | 173 - phpMyAdmin/libraries/export/latex.php | 509 - phpMyAdmin/libraries/export/mediawiki.php | 159 - phpMyAdmin/libraries/export/ods.php | 221 - phpMyAdmin/libraries/export/odt.php | 405 - phpMyAdmin/libraries/export/pdf.php | 454 - phpMyAdmin/libraries/export/php_array.php | 175 - phpMyAdmin/libraries/export/sql.php | 1290 -- phpMyAdmin/libraries/export/texytext.php | 309 - phpMyAdmin/libraries/export/xml.php | 386 - phpMyAdmin/libraries/export/yaml.php | 169 - ...{file_listing.php => file_listing.lib.php} | 16 +- phpMyAdmin/libraries/footer.inc.php | 193 - phpMyAdmin/libraries/gis/pma_gis_factory.php | 21 +- phpMyAdmin/libraries/gis/pma_gis_geometry.php | 269 +- .../gis/pma_gis_geometrycollection.php | 103 +- .../libraries/gis/pma_gis_linestring.php | 78 +- .../libraries/gis/pma_gis_multilinestring.php | 108 +- .../libraries/gis/pma_gis_multipoint.php | 119 +- .../libraries/gis/pma_gis_multipolygon.php | 125 +- phpMyAdmin/libraries/gis/pma_gis_point.php | 94 +- phpMyAdmin/libraries/gis/pma_gis_polygon.php | 90 +- .../libraries/gis/pma_gis_visualization.php | 109 +- phpMyAdmin/libraries/grab_globals.lib.php | 118 - phpMyAdmin/libraries/header.inc.php | 218 - phpMyAdmin/libraries/header_http.inc.php | 37 - .../libraries/header_meta_style.inc.php | 51 - phpMyAdmin/libraries/header_printview.inc.php | 76 - phpMyAdmin/libraries/header_scripts.inc.php | 82 - phpMyAdmin/libraries/iconv_wrapper.lib.php | 78 +- phpMyAdmin/libraries/import.lib.php | 683 +- phpMyAdmin/libraries/import/README | 41 - phpMyAdmin/libraries/import/csv.php | 455 - phpMyAdmin/libraries/import/docsql.php | 96 - phpMyAdmin/libraries/import/ldi.php | 110 - phpMyAdmin/libraries/import/ods.php | 306 - phpMyAdmin/libraries/import/shp.php | 426 - phpMyAdmin/libraries/import/sql.php | 321 - phpMyAdmin/libraries/import/upload/apc.php | 66 - .../libraries/import/upload/noplugin.php | 44 - .../import/upload/uploadprogress.php | 75 - phpMyAdmin/libraries/import/xml.php | 317 - phpMyAdmin/libraries/index.lib.php | 49 + .../information_schema_relations.lib.php | 197 + phpMyAdmin/libraries/insert_edit.lib.php | 2920 ++++ phpMyAdmin/libraries/ip_allow_deny.lib.php | 236 +- phpMyAdmin/libraries/js_escape.lib.php | 51 +- phpMyAdmin/libraries/kanji-encoding.lib.php | 121 +- phpMyAdmin/libraries/language_stats.inc.php | 114 +- phpMyAdmin/libraries/logging.lib.php | 10 +- phpMyAdmin/libraries/mime.lib.php | 6 +- phpMyAdmin/libraries/mult_submits.inc.php | 547 +- phpMyAdmin/libraries/mult_submits.lib.php | 627 + phpMyAdmin/libraries/mysql_charsets.inc.php | 143 + phpMyAdmin/libraries/mysql_charsets.lib.php | 142 +- .../libraries/navigation/Navigation.class.php | 211 + .../navigation/NavigationHeader.class.php | 310 + .../navigation/NavigationTree.class.php | 1166 ++ .../navigation/NodeFactory.class.php | 97 + .../libraries/navigation/Nodes/Node.class.php | 441 + .../navigation/Nodes/Node_Column.class.php | 46 + .../Nodes/Node_Column_Container.class.php | 57 + .../navigation/Nodes/Node_Database.class.php | 327 + .../Nodes/Node_DatabaseChild.class.php | 52 + .../Nodes/Node_Database_Container.class.php | 47 + .../navigation/Nodes/Node_Event.class.php | 57 + .../Nodes/Node_Event_Container.class.php | 54 + .../navigation/Nodes/Node_Function.class.php | 57 + .../Nodes/Node_Function_Container.class.php | 53 + .../navigation/Nodes/Node_Index.class.php | 45 + .../Nodes/Node_Index_Container.class.php | 55 + .../navigation/Nodes/Node_Procedure.class.php | 57 + .../Nodes/Node_Procedure_Container.class.php | 55 + .../navigation/Nodes/Node_Table.class.php | 186 + .../Nodes/Node_Table_Container.class.php | 60 + .../navigation/Nodes/Node_Trigger.class.php | 45 + .../Nodes/Node_Trigger_Container.class.php | 55 + .../navigation/Nodes/Node_View.class.php | 57 + .../Nodes/Node_View_Container.class.php | 60 + .../libraries/navigation_header.inc.php | 134 - phpMyAdmin/libraries/ob.lib.php | 96 - phpMyAdmin/libraries/opendocument.lib.php | 205 +- phpMyAdmin/libraries/operations.lib.php | 1619 +++ phpMyAdmin/libraries/parse_analyze.inc.php | 144 + phpMyAdmin/libraries/parse_analyze.lib.php | 59 - phpMyAdmin/libraries/php-gettext/gettext.inc | 13 +- phpMyAdmin/libraries/phpseclib/Crypt/AES.php | 612 + .../libraries/phpseclib/Crypt/Rijndael.php | 1479 ++ phpMyAdmin/libraries/plugin_interface.lib.php | 539 +- .../plugins/AuthenticationPlugin.class.php | 51 + .../libraries/plugins/ExportPlugin.class.php | 206 + .../libraries/plugins/ImportPlugin.class.php | 59 + .../libraries/plugins/PluginManager.class.php | 132 + .../plugins/PluginObserver.class.php | 91 + .../plugins/TransformationsInterface.int.php | 49 + .../plugins/TransformationsPlugin.class.php | 51 + .../libraries/plugins/UploadInterface.int.php | 36 + .../auth/AuthenticationConfig.class.php | 174 + .../auth/AuthenticationCookie.class.php | 807 ++ .../plugins/auth/AuthenticationHttp.class.php | 261 + .../auth/AuthenticationSignon.class.php | 299 + .../libraries/plugins/auth/recaptchalib.php | 277 + .../auth/swekey/authentication.inc.php | 0 .../{ => plugins}/auth/swekey/musbe-ca.crt | 0 .../auth/swekey/swekey.auth.lib.php | 148 +- .../{ => plugins}/auth/swekey/swekey.php | 199 +- .../plugins/export/ExportCodegen.class.php | 423 + .../plugins/export/ExportCsv.class.php | 321 + .../plugins/export/ExportExcel.class.php | 105 + .../plugins/export/ExportHtmlword.class.php | 647 + .../plugins/export/ExportJson.class.php | 210 + .../plugins/export/ExportLatex.class.php | 657 + .../plugins/export/ExportMediawiki.class.php | 366 + .../plugins/export/ExportOds.class.php | 336 + .../plugins/export/ExportOdt.class.php | 734 + .../plugins/export/ExportPdf.class.php | 268 + .../plugins/export/ExportPhparray.class.php | 229 + .../plugins/export/ExportSql.class.php | 2017 +++ .../plugins/export/ExportTexytext.class.php | 576 + .../plugins/export/ExportXml.class.php | 546 + .../plugins/export/ExportYaml.class.php | 216 + .../plugins/export/PMA_ExportPdf.class.php | 426 + phpMyAdmin/libraries/plugins/export/README | 276 + .../plugins/export/TableProperty.class.php | 286 + .../import/AbstractImportCsv.class.php | 91 + .../plugins/import/ImportCsv.class.php | 608 + .../plugins/import/ImportLdi.class.php | 174 + .../plugins/import/ImportMediawiki.class.php | 573 + .../plugins/import/ImportOds.class.php | 415 + .../plugins/import/ImportShp.class.php | 335 + .../plugins/import/ImportSql.class.php | 447 + .../plugins/import/ImportXml.class.php | 379 + phpMyAdmin/libraries/plugins/import/README | 172 + .../plugins/import/ShapeFile.class.php | 102 + .../plugins/import/ShapeRecord.class.php | 161 + .../plugins/import/upload/UploadApc.class.php | 84 + .../import/upload/UploadNoplugin.class.php | 64 + .../import/upload/UploadProgress.class.php | 94 + .../import/upload/UploadSession.class.php | 96 + ...Application_Octetstream_Download.class.php | 43 + .../Application_Octetstream_Hex.class.php | 44 + .../Image_JPEG_Inline.class.php | 44 + .../transformations/Image_JPEG_Link.class.php | 44 + .../Image_PNG_Inline.class.php | 44 + .../libraries/plugins/transformations/README | 4 + .../plugins/transformations/TEMPLATE | 46 + .../plugins/transformations/TEMPLATE_ABSTRACT | 89 + .../Text_Plain_Append.class.php | 45 + .../Text_Plain_Dateformat.class.php | 44 + .../Text_Plain_External.class.php | 44 + .../Text_Plain_Formatted.class.php | 44 + .../Text_Plain_Imagelink.class.php | 44 + .../transformations/Text_Plain_Link.class.php | 44 + .../Text_Plain_Longtoipv4.class.php | 44 + .../transformations/Text_Plain_Sql.class.php | 44 + .../Text_Plain_Substring.class.php | 44 + .../AppendTransformationsPlugin.class.php | 84 + .../DateFormatTransformationsPlugin.class.php | 178 + .../DownloadTransformationsPlugin.class.php | 110 + .../ExternalTransformationsPlugin.class.php | 182 + .../FormattedTransformationsPlugin.class.php | 80 + .../HexTransformationsPlugin.class.php | 91 + .../ImageLinkTransformationsPlugin.class.php | 87 + .../InlineTransformationsPlugin.class.php | 101 + .../LongToIPv4TransformationsPlugin.class.php | 83 + .../SQLTransformationsPlugin.class.php | 82 + .../SubstringTransformationsPlugin.class.php | 118 + ...xtImageLinkTransformationsPlugin.class.php | 96 + .../TextLinkTransformationsPlugin.class.php | 98 + .../transformations/generator_main_class.sh | 16 + .../transformations/generator_plugin.sh | 64 + phpMyAdmin/libraries/pmd_common.php | 205 +- .../properties/PropertyItem.class.php | 49 + .../options/OptionsPropertyGroup.class.php | 102 + .../options/OptionsPropertyItem.class.php | 127 + .../options/OptionsPropertyOneItem.class.php | 172 + .../groups/OptionsPropertyMainGroup.class.php | 35 + .../groups/OptionsPropertyRootGroup.class.php | 35 + .../groups/OptionsPropertySubgroup.class.php | 68 + .../options/items/BoolPropertyItem.class.php | 35 + .../options/items/DocPropertyItem.class.php | 35 + .../items/HiddenPropertyItem.class.php | 35 + .../items/MessageOnlyPropertyItem.class.php | 35 + .../items/NumberPropertyItem.class.php | 35 + .../options/items/RadioPropertyItem.class.php | 35 + .../items/SelectPropertyItem.class.php | 35 + .../options/items/TextPropertyItem.class.php | 35 + .../plugins/ExportPluginProperties.class.php | 214 + .../plugins/ImportPluginProperties.class.php | 184 + .../plugins/PluginPropertyItem.class.php | 36 + phpMyAdmin/libraries/relation.lib.php | 1051 +- phpMyAdmin/libraries/relation_cleanup.lib.php | 184 +- phpMyAdmin/libraries/replication.inc.php | 271 +- phpMyAdmin/libraries/replication_gui.lib.php | 1041 +- phpMyAdmin/libraries/rte/rte_events.lib.php | 169 +- phpMyAdmin/libraries/rte/rte_export.lib.php | 40 +- phpMyAdmin/libraries/rte/rte_footer.lib.php | 28 +- phpMyAdmin/libraries/rte/rte_list.lib.php | 182 +- phpMyAdmin/libraries/rte/rte_main.inc.php | 52 +- phpMyAdmin/libraries/rte/rte_routines.lib.php | 768 +- phpMyAdmin/libraries/rte/rte_triggers.lib.php | 158 +- phpMyAdmin/libraries/rte/rte_words.lib.php | 13 +- phpMyAdmin/libraries/sanitizing.lib.php | 87 +- .../schema/Dia_Relation_Schema.class.php | 281 +- .../schema/Eps_Relation_Schema.class.php | 160 +- .../schema/Export_Relation_Schema.class.php | 46 +- .../schema/Pdf_Relation_Schema.class.php | 428 +- .../schema/Svg_Relation_Schema.class.php | 279 +- .../libraries/schema/User_Schema.class.php | 754 +- .../schema/Visio_Relation_Schema.class.php | 645 - phpMyAdmin/libraries/select_lang.lib.php | 137 +- phpMyAdmin/libraries/select_server.lib.php | 64 +- phpMyAdmin/libraries/server_bin_log.lib.php | 245 + .../libraries/server_collations.lib.php | 110 + phpMyAdmin/libraries/server_common.inc.php | 33 +- phpMyAdmin/libraries/server_common.lib.php | 67 + phpMyAdmin/libraries/server_databases.lib.php | 509 + phpMyAdmin/libraries/server_engines.lib.php | 146 + phpMyAdmin/libraries/server_links.inc.php | 120 - phpMyAdmin/libraries/server_plugins.lib.php | 205 + .../libraries/server_privileges.lib.php | 4235 ++++++ phpMyAdmin/libraries/server_status.lib.php | 546 + .../libraries/server_status_advisor.lib.php | 70 + .../libraries/server_status_monitor.lib.php | 798 ++ .../libraries/server_status_queries.lib.php | 153 + .../libraries/server_status_variables.lib.php | 765 + .../libraries/server_synchronize.lib.php | 1389 -- .../libraries/server_user_groups.lib.php | 355 + phpMyAdmin/libraries/server_users.lib.php | 55 + phpMyAdmin/libraries/server_variables.lib.php | 1684 +++ phpMyAdmin/libraries/server_variables_doc.php | 1396 -- phpMyAdmin/libraries/session.inc.php | 27 +- .../libraries/special_schema_links.lib.php | 406 + phpMyAdmin/libraries/sql.lib.php | 2386 ++++ phpMyAdmin/libraries/sql_query_form.lib.php | 498 +- phpMyAdmin/libraries/sqlparser.data.php | 737 +- phpMyAdmin/libraries/sqlparser.lib.php | 4926 +++---- phpMyAdmin/libraries/sqlvalidator.class.php | 140 +- phpMyAdmin/libraries/sqlvalidator.lib.php | 21 +- phpMyAdmin/libraries/string.inc.php | 18 + phpMyAdmin/libraries/string.lib.php | 101 - phpMyAdmin/libraries/string_mb.lib.php | 66 - phpMyAdmin/libraries/string_native.lib.php | 66 - .../libraries/string_type_ctype.lib.php | 96 - .../libraries/string_type_native.lib.php | 125 - phpMyAdmin/libraries/structure.lib.php | 2673 ++++ phpMyAdmin/libraries/sysinfo.lib.php | 291 +- phpMyAdmin/libraries/tbl_chart.lib.php | 295 + .../tbl_columns_definition_form.inc.php | 159 + .../tbl_columns_definition_form.lib.php | 1283 ++ phpMyAdmin/libraries/tbl_common.inc.php | 63 + phpMyAdmin/libraries/tbl_common.php | 43 - ....lib.php => tbl_gis_visualization.lib.php} | 189 +- phpMyAdmin/libraries/tbl_indexes.lib.php | 406 + phpMyAdmin/libraries/tbl_info.inc.php | 45 +- phpMyAdmin/libraries/tbl_links.inc.php | 138 - phpMyAdmin/libraries/tbl_printview.lib.php | 600 + phpMyAdmin/libraries/tbl_properties.inc.php | 718 - phpMyAdmin/libraries/tbl_relation.lib.php | 1036 ++ .../libraries/tbl_replace_fields.inc.php | 111 - phpMyAdmin/libraries/tbl_select.lib.php | 385 - phpMyAdmin/libraries/tbl_tracking.lib.php | 1210 ++ phpMyAdmin/libraries/tbl_views.lib.php | 159 + phpMyAdmin/libraries/tcpdf/README.TXT | 50 +- .../libraries/tcpdf/config/tcpdf_config.php | 387 +- phpMyAdmin/libraries/tcpdf/encodings_maps.php | 846 -- .../libraries/tcpdf/fonts/dejavusans.ctg.z | Bin 10183 -> 10120 bytes .../libraries/tcpdf/fonts/dejavusans.php | 2 +- .../libraries/tcpdf/fonts/dejavusansb.ctg.z | Bin 9908 -> 9854 bytes .../libraries/tcpdf/fonts/dejavusansb.php | 2 +- phpMyAdmin/libraries/tcpdf/htmlcolors.php | 199 - .../libraries/tcpdf/include/tcpdf_colors.php | 462 + .../tcpdf_font_data.php} | 138 +- .../libraries/tcpdf/include/tcpdf_fonts.php | 2562 ++++ .../libraries/tcpdf/include/tcpdf_images.php | 355 + .../libraries/tcpdf/include/tcpdf_static.php | 2837 ++++ phpMyAdmin/libraries/tcpdf/tcpdf.php | 9862 ++++--------- .../libraries/tcpdf/tcpdf_autoconfig.php | 233 + phpMyAdmin/libraries/transformations.lib.php | 324 +- phpMyAdmin/libraries/transformations/README | 4 - phpMyAdmin/libraries/transformations/TEMPLATE | 35 - .../transformations/TEMPLATE_MIMETYPE | 12 - .../application_octetstream__download.inc.php | 51 - .../application_octetstream__hex.inc.php | 35 - .../libraries/transformations/generator.sh | 23 - .../libraries/transformations/global.inc.php | 53 - .../image_jpeg__inline.inc.php | 31 - .../transformations/image_jpeg__link.inc.php | 27 - .../transformations/image_png__inline.inc.php | 31 - .../transformations/template_generator.sh | 24 - .../template_generator_mimetype.sh | 19 - .../text_plain__dateformat.inc.php | 103 - .../text_plain__external.inc.php | 105 - .../text_plain__formatted.inc.php | 22 - .../text_plain__imagelink.inc.php | 26 - .../transformations/text_plain__link.inc.php | 31 - .../text_plain__longToIpv4.inc.php | 28 - .../transformations/text_plain__sql.inc.php | 25 - .../text_plain__substr.inc.php | 57 - phpMyAdmin/libraries/url_generating.lib.php | 51 +- phpMyAdmin/libraries/user_preferences.inc.php | 23 +- phpMyAdmin/libraries/user_preferences.lib.php | 177 +- phpMyAdmin/libraries/vendor_config.php | 15 + phpMyAdmin/libraries/zip.lib.php | 53 +- phpMyAdmin/libraries/zip_extension.lib.php | 31 +- phpMyAdmin/license.php | 2 +- .../locale/ar/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 111324 bytes .../locale/bg/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 222546 bytes .../locale/bn/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 398314 bytes .../locale/ca/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 291704 bytes .../locale/cs/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 307561 bytes .../locale/da/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 302042 bytes .../locale/de/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 316078 bytes .../locale/el/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 424358 bytes .../locale/en_GB/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 290452 bytes .../locale/es/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 320281 bytes .../locale/et/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 297377 bytes .../locale/fi/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 195174 bytes .../locale/fr/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 318927 bytes .../locale/gl/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 306061 bytes .../locale/hi/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 167057 bytes .../locale/hu/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 314365 bytes .../locale/ia/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 101559 bytes .../locale/id/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 205341 bytes .../locale/it/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 279428 bytes .../locale/ja/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 307755 bytes .../locale/ko/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 200518 bytes .../locale/lt/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 148485 bytes .../locale/nb/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 176008 bytes .../locale/nl/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 310490 bytes .../locale/pl/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 292528 bytes .../locale/pt/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 169071 bytes .../locale/pt_BR/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 313681 bytes .../locale/ro/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 160369 bytes .../locale/ru/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 394719 bytes .../locale/si/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 296932 bytes .../locale/sk/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 224659 bytes .../locale/sl/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 305099 bytes .../locale/sr@latin/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 155730 bytes .../locale/sv/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 295122 bytes .../locale/th/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 132620 bytes .../locale/tr/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 314131 bytes .../locale/uk/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 365703 bytes .../locale/uz/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 174395 bytes .../locale/uz@latin/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 133098 bytes .../locale/zh_CN/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 260101 bytes .../locale/zh_TW/LC_MESSAGES/phpmyadmin.mo | Bin 0 -> 285327 bytes phpMyAdmin/navigation.php | 648 +- phpMyAdmin/phpinfo.php | 5 +- phpMyAdmin/phpmyadmin.css.php | 18 +- phpMyAdmin/phpunit.xml.nocoverage | 13 +- phpMyAdmin/pmd_display_field.php | 50 +- phpMyAdmin/pmd_general.php | 599 +- phpMyAdmin/pmd_pdf.php | 134 +- phpMyAdmin/pmd_relation_new.php | 100 +- phpMyAdmin/pmd_relation_upd.php | 50 +- phpMyAdmin/pmd_save_pos.php | 84 +- phpMyAdmin/prefs_forms.php | 51 +- phpMyAdmin/prefs_manage.php | 205 +- phpMyAdmin/print.css | 49 +- phpMyAdmin/querywindow.php | 143 +- phpMyAdmin/schema_edit.php | 65 +- phpMyAdmin/schema_export.php | 64 +- phpMyAdmin/server_binlog.php | 212 +- phpMyAdmin/server_collations.php | 93 +- phpMyAdmin/server_databases.php | 275 +- phpMyAdmin/server_engines.php | 148 +- phpMyAdmin/server_export.php | 58 +- phpMyAdmin/server_import.php | 24 +- phpMyAdmin/server_plugins.php | 185 +- phpMyAdmin/server_privileges.php | 2496 +--- phpMyAdmin/server_replication.php | 371 +- phpMyAdmin/server_sql.php | 30 +- phpMyAdmin/server_status.php | 1827 +-- phpMyAdmin/server_status_advisor.php | 39 + phpMyAdmin/server_status_monitor.php | 116 + phpMyAdmin/server_status_queries.php | 53 + phpMyAdmin/server_status_variables.php | 56 + phpMyAdmin/server_user_groups.php | 64 + phpMyAdmin/server_variables.php | 164 +- phpMyAdmin/setup/ajax.js | 11 + phpMyAdmin/setup/config.php | 19 +- phpMyAdmin/setup/frames/.htaccess | 3 - phpMyAdmin/setup/frames/config.inc.php | 53 +- phpMyAdmin/setup/frames/form.inc.php | 6 +- phpMyAdmin/setup/frames/index.inc.php | 345 +- phpMyAdmin/setup/frames/menu.inc.php | 30 +- phpMyAdmin/setup/frames/servers.inc.php | 10 +- phpMyAdmin/setup/index.php | 26 +- phpMyAdmin/setup/lib/.htaccess | 3 - .../setup/lib/ConfigGenerator.class.php | 46 +- phpMyAdmin/setup/lib/common.inc.php | 39 +- phpMyAdmin/setup/lib/form_processing.lib.php | 17 +- phpMyAdmin/setup/lib/index.lib.php | 420 +- phpMyAdmin/setup/scripts.js | 169 +- phpMyAdmin/setup/styles.css | 378 +- phpMyAdmin/setup/validate.php | 8 +- phpMyAdmin/show_config_errors.php | 29 +- phpMyAdmin/sql.php | 1023 +- phpMyAdmin/tbl_addfield.php | 198 +- phpMyAdmin/tbl_change.php | 1118 +- phpMyAdmin/tbl_chart.php | 219 +- phpMyAdmin/tbl_create.php | 351 +- phpMyAdmin/tbl_export.php | 57 +- phpMyAdmin/tbl_find_replace.php | 63 + phpMyAdmin/tbl_get_field.php | 37 +- phpMyAdmin/tbl_gis_visualization.php | 188 +- phpMyAdmin/tbl_import.php | 22 +- phpMyAdmin/tbl_indexes.php | 294 +- phpMyAdmin/tbl_move_copy.php | 52 +- phpMyAdmin/tbl_operations.php | 883 +- phpMyAdmin/tbl_printview.php | 414 +- phpMyAdmin/tbl_relation.php | 563 +- phpMyAdmin/tbl_replace.php | 556 +- phpMyAdmin/tbl_row_action.php | 206 +- phpMyAdmin/tbl_select.php | 304 +- phpMyAdmin/tbl_sql.php | 37 +- phpMyAdmin/tbl_structure.php | 978 +- phpMyAdmin/tbl_tracking.php | 706 +- phpMyAdmin/tbl_zoom_select.php | 505 +- phpMyAdmin/themes.php | 35 +- .../{theme_right.css.php => common.css.php} | 1664 +-- .../themes/original/css/navigation.css.php | 296 + .../themes/original/css/theme_left.css.php | 254 - .../themes/original/css/theme_print.css.php | 42 - .../themes/original/img/b_column_add.png | Bin 0 -> 534 bytes .../themes/original/img/b_find_replace.png | Bin 0 -> 1209 bytes phpMyAdmin/themes/original/img/b_group.png | Bin 0 -> 796 bytes .../themes/original/img/b_index_add.png | Bin 0 -> 429 bytes phpMyAdmin/themes/original/img/b_move.png | Bin 0 -> 168 bytes .../themes/original/img/b_table_add.png | Bin 0 -> 368 bytes phpMyAdmin/themes/original/img/b_undo.png | Bin 0 -> 1306 bytes phpMyAdmin/themes/original/img/b_view_add.png | Bin 0 -> 726 bytes .../themes/original/img/docs_menu_bg.png | Bin 76 -> 0 bytes phpMyAdmin/themes/original/img/item_ltr.png | Bin 112 -> 0 bytes phpMyAdmin/themes/original/img/item_rtl.png | Bin 112 -> 0 bytes phpMyAdmin/themes/original/img/lightbulb.png | Bin 0 -> 782 bytes .../themes/original/img/lightbulb_off.png | Bin 0 -> 700 bytes phpMyAdmin/themes/original/img/pmd/1.png | Bin 101 -> 0 bytes phpMyAdmin/themes/original/img/pmd/2.png | Bin 169 -> 0 bytes .../themes/original/img/pmd/2leftarrow.png | Bin 702 -> 0 bytes .../themes/original/img/pmd/2leftarrow_m.png | Bin 666 -> 0 bytes .../themes/original/img/pmd/2rightarrow.png | Bin 737 -> 0 bytes .../themes/original/img/pmd/2rightarrow_m.png | Bin 699 -> 0 bytes phpMyAdmin/themes/original/img/pmd/3.png | Bin 175 -> 0 bytes phpMyAdmin/themes/original/img/pmd/4.png | Bin 181 -> 0 bytes phpMyAdmin/themes/original/img/pmd/5.png | Bin 90 -> 0 bytes phpMyAdmin/themes/original/img/pmd/6.png | Bin 98 -> 0 bytes phpMyAdmin/themes/original/img/pmd/7.png | Bin 105 -> 0 bytes phpMyAdmin/themes/original/img/pmd/8.png | Bin 88 -> 0 bytes .../original/img/pmd/FieldKey_small.png | Bin 229 -> 0 bytes .../themes/original/img/pmd/Field_small.png | Bin 275 -> 0 bytes .../original/img/pmd/Field_small_char.png | Bin 154 -> 0 bytes .../original/img/pmd/Field_small_date.png | Bin 156 -> 0 bytes .../original/img/pmd/Field_small_int.png | Bin 145 -> 0 bytes phpMyAdmin/themes/original/img/pmd/Header.png | Bin 125 -> 0 bytes .../themes/original/img/pmd/Header_Linked.png | Bin 108 -> 0 bytes .../themes/original/img/pmd/and_icon.png | Bin 792 -> 0 bytes .../themes/original/img/pmd/ang_direct.png | Bin 679 -> 0 bytes phpMyAdmin/themes/original/img/pmd/bord.png | Bin 87 -> 0 bytes phpMyAdmin/themes/original/img/pmd/bottom.png | Bin 734 -> 0 bytes phpMyAdmin/themes/original/img/pmd/def.png | Bin 670 -> 0 bytes .../themes/original/img/pmd/display_field.png | Bin 685 -> 0 bytes .../themes/original/img/pmd/downarrow1.png | Bin 758 -> 0 bytes .../themes/original/img/pmd/downarrow2.png | Bin 772 -> 0 bytes .../themes/original/img/pmd/downarrow2_m.png | Bin 711 -> 0 bytes phpMyAdmin/themes/original/img/pmd/exec.png | Bin 796 -> 0 bytes .../themes/original/img/pmd/exec_small.png | Bin 161 -> 0 bytes .../themes/original/img/pmd/favicon.ico | Bin 1150 -> 0 bytes phpMyAdmin/themes/original/img/pmd/grid.png | Bin 688 -> 0 bytes phpMyAdmin/themes/original/img/pmd/help.png | Bin 714 -> 0 bytes .../themes/original/img/pmd/help_relation.png | Bin 920 -> 0 bytes .../original/img/pmd/left_panel_butt.png | Bin 129 -> 0 bytes .../original/img/pmd/left_panel_tab.png | Bin 133 -> 0 bytes phpMyAdmin/themes/original/img/pmd/minus.png | Bin 1004 -> 0 bytes .../themes/original/img/pmd/or_icon.png | Bin 611 -> 0 bytes phpMyAdmin/themes/original/img/pmd/pdf.png | Bin 905 -> 0 bytes phpMyAdmin/themes/original/img/pmd/plus.png | Bin 969 -> 0 bytes .../themes/original/img/pmd/query_builder.png | Bin 685 -> 0 bytes .../themes/original/img/pmd/relation.png | Bin 295 -> 0 bytes phpMyAdmin/themes/original/img/pmd/reload.png | Bin 874 -> 0 bytes phpMyAdmin/themes/original/img/pmd/resize.png | Bin 121 -> 0 bytes .../themes/original/img/pmd/rightarrow1.png | Bin 746 -> 0 bytes .../themes/original/img/pmd/rightarrow2.png | Bin 757 -> 0 bytes phpMyAdmin/themes/original/img/pmd/save.png | Bin 409 -> 0 bytes .../themes/original/img/pmd/small_tab.png | Bin 180 -> 0 bytes phpMyAdmin/themes/original/img/pmd/table.png | Bin 163 -> 0 bytes .../themes/original/img/pmd/toggle_lines.png | Bin 630 -> 0 bytes .../themes/original/img/pmd/top_panel.png | Bin 173 -> 0 bytes .../themes/original/img/pmd/uparrow2_m.png | Bin 729 -> 0 bytes .../themes/original/img/s_attention.png | Bin 629 -> 0 bytes phpMyAdmin/themes/original/img/s_info.png | Bin 740 -> 147 bytes phpMyAdmin/themes/original/img/s_okay.png | Bin 772 -> 0 bytes phpMyAdmin/themes/original/img/s_process.png | Bin 475 -> 0 bytes phpMyAdmin/themes/original/img/s_top.png | Bin 0 -> 443 bytes phpMyAdmin/themes/original/img/sprites.png | Bin 16796 -> 20509 bytes phpMyAdmin/themes/original/info.inc.php | 2 +- .../images/ui-bg_glass_75_dadada_1x400.png | Bin 111 -> 159 bytes .../jquery/jquery-ui-1.9.2.custom.css} | 517 +- phpMyAdmin/themes/original/layout.inc.php | 35 +- phpMyAdmin/themes/original/sprites.lib.php | 380 +- .../themes/pmahomme/css/codemirror.css.php | 303 + phpMyAdmin/themes/pmahomme/css/common.css.php | 2795 ++++ .../themes/pmahomme/css/enum_editor.css.php | 80 + phpMyAdmin/themes/pmahomme/css/gis.css.php | 65 + phpMyAdmin/themes/pmahomme/css/jqplot.css.php | 277 + .../themes/pmahomme/css/navigation.css.php | 285 + phpMyAdmin/themes/pmahomme/css/pmd.css.php | 530 + .../pmahomme/css/resizable-menu.css.php | 57 + phpMyAdmin/themes/pmahomme/css/rte.css.php | 43 + .../themes/pmahomme/css/theme_left.css.php | 312 - .../themes/pmahomme/css/theme_print.css.php | 42 - .../themes/pmahomme/css/theme_right.css.php | 3736 ----- .../themes/pmahomme/img/b_column_add.png | Bin 0 -> 534 bytes .../themes/pmahomme/img/b_find_replace.png | Bin 0 -> 883 bytes phpMyAdmin/themes/pmahomme/img/b_group.png | Bin 0 -> 796 bytes .../themes/pmahomme/img/b_index_add.png | Bin 0 -> 839 bytes phpMyAdmin/themes/pmahomme/img/b_minus.png | Bin 187 -> 224 bytes phpMyAdmin/themes/pmahomme/img/b_move.png | Bin 0 -> 520 bytes phpMyAdmin/themes/pmahomme/img/b_plus.png | Bin 189 -> 237 bytes .../themes/pmahomme/img/b_table_add.png | Bin 0 -> 676 bytes phpMyAdmin/themes/pmahomme/img/b_undo.png | Bin 0 -> 1306 bytes phpMyAdmin/themes/pmahomme/img/b_view_add.png | Bin 0 -> 766 bytes phpMyAdmin/themes/pmahomme/img/body_bg.png | Bin 649 -> 0 bytes .../pmahomme/img/database_list_li_hover.png | Bin 108 -> 0 bytes .../themes/pmahomme/img/docs_menu_bg.png | Bin 76 -> 0 bytes phpMyAdmin/themes/pmahomme/img/input_bg.gif | Bin 170 -> 0 bytes phpMyAdmin/themes/pmahomme/img/item_ltr.png | Bin 112 -> 0 bytes phpMyAdmin/themes/pmahomme/img/item_rtl.png | Bin 112 -> 0 bytes .../themes/pmahomme/img/left_nav_bg.png | Bin 236 -> 297 bytes phpMyAdmin/themes/pmahomme/img/lightbulb.png | Bin 0 -> 782 bytes .../themes/pmahomme/img/lightbulb_off.png | Bin 0 -> 700 bytes phpMyAdmin/themes/pmahomme/img/marked_bg.png | Bin 172 -> 0 bytes .../pmahomme/img/pmd/exitFullscreen.png | Bin 0 -> 444 bytes .../pmahomme/img/pmd/viewInFullscreen.png | Bin 0 -> 472 bytes phpMyAdmin/themes/pmahomme/img/s_top.png | Bin 0 -> 443 bytes phpMyAdmin/themes/pmahomme/img/sprites.png | Bin 38291 -> 41626 bytes phpMyAdmin/themes/pmahomme/img/tab_bg.png | Bin 127 -> 0 bytes .../themes/pmahomme/img/tab_hover_bg.png | Bin 502 -> 0 bytes .../themes/pmahomme/img/tabactive_bg.png | Bin 106 -> 0 bytes phpMyAdmin/themes/pmahomme/info.inc.php | 36 +- .../images/ui-bg_glass_75_dadada_1x400.png | Bin 111 -> 159 bytes .../jquery/jquery-ui-1.9.2.custom.css} | 517 +- phpMyAdmin/themes/pmahomme/layout.inc.php | 64 +- phpMyAdmin/themes/pmahomme/sprites.lib.php | 365 +- phpMyAdmin/themes/sprites.css.php | 113 +- phpMyAdmin/themes/svg_gradient.php | 33 +- phpMyAdmin/transformation_overview.php | 25 +- phpMyAdmin/transformation_wrapper.php | 94 +- phpMyAdmin/url.php | 8 +- phpMyAdmin/user_password.php | 278 +- phpMyAdmin/version_check.php | 24 +- phpMyAdmin/view_create.php | 325 +- phpMyAdmin/view_operations.php | 66 +- phpMyAdmin/webapp.php | 7 +- 968 files changed, 243347 insertions(+), 81113 deletions(-) create mode 100644 phpMyAdmin/CONTRIBUTING.md create mode 100644 phpMyAdmin/RELEASE-DATE-4.1.7 create mode 100644 phpMyAdmin/composer.json create mode 100644 phpMyAdmin/doc/Makefile create mode 100644 phpMyAdmin/doc/_ext/configext.py create mode 100644 phpMyAdmin/doc/_ext/configext.pyc create mode 100644 phpMyAdmin/doc/conf.py create mode 100644 phpMyAdmin/doc/config.rst create mode 100644 phpMyAdmin/doc/copyright.rst create mode 100644 phpMyAdmin/doc/credits.rst create mode 100644 phpMyAdmin/doc/developers.rst create mode 100644 phpMyAdmin/doc/doctrees/config.doctree create mode 100644 phpMyAdmin/doc/doctrees/copyright.doctree create mode 100644 phpMyAdmin/doc/doctrees/credits.doctree create mode 100644 phpMyAdmin/doc/doctrees/developers.doctree create mode 100644 phpMyAdmin/doc/doctrees/environment.pickle create mode 100644 phpMyAdmin/doc/doctrees/faq.doctree create mode 100644 phpMyAdmin/doc/doctrees/glossary.doctree create mode 100644 phpMyAdmin/doc/doctrees/index.doctree create mode 100644 phpMyAdmin/doc/doctrees/intro.doctree create mode 100644 phpMyAdmin/doc/doctrees/other.doctree create mode 100644 phpMyAdmin/doc/doctrees/privileges.doctree create mode 100644 phpMyAdmin/doc/doctrees/require.doctree create mode 100644 phpMyAdmin/doc/doctrees/setup.doctree create mode 100644 phpMyAdmin/doc/doctrees/transformations.doctree create mode 100644 phpMyAdmin/doc/doctrees/user.doctree create mode 100644 phpMyAdmin/doc/doctrees/vendors.doctree create mode 100644 phpMyAdmin/doc/faq.rst create mode 100644 phpMyAdmin/doc/glossary.rst create mode 100644 phpMyAdmin/doc/html/.buildinfo create mode 100644 phpMyAdmin/doc/html/_sources/config.txt create mode 100644 phpMyAdmin/doc/html/_sources/copyright.txt create mode 100644 phpMyAdmin/doc/html/_sources/credits.txt create mode 100644 phpMyAdmin/doc/html/_sources/developers.txt create mode 100644 phpMyAdmin/doc/html/_sources/faq.txt create mode 100644 phpMyAdmin/doc/html/_sources/glossary.txt create mode 100644 phpMyAdmin/doc/html/_sources/index.txt create mode 100644 phpMyAdmin/doc/html/_sources/intro.txt create mode 100644 phpMyAdmin/doc/html/_sources/other.txt create mode 100644 phpMyAdmin/doc/html/_sources/privileges.txt create mode 100644 phpMyAdmin/doc/html/_sources/require.txt create mode 100644 phpMyAdmin/doc/html/_sources/setup.txt create mode 100644 phpMyAdmin/doc/html/_sources/transformations.txt create mode 100644 phpMyAdmin/doc/html/_sources/user.txt create mode 100644 phpMyAdmin/doc/html/_sources/vendors.txt create mode 100644 phpMyAdmin/doc/html/_static/ajax-loader.gif create mode 100644 phpMyAdmin/doc/html/_static/basic.css create mode 100644 phpMyAdmin/doc/html/_static/comment-bright.png create mode 100644 phpMyAdmin/doc/html/_static/comment-close.png create mode 100644 phpMyAdmin/doc/html/_static/comment.png create mode 100644 phpMyAdmin/doc/html/_static/default.css create mode 100644 phpMyAdmin/doc/html/_static/doctools.js create mode 100644 phpMyAdmin/doc/html/_static/down-pressed.png create mode 100644 phpMyAdmin/doc/html/_static/down.png create mode 100644 phpMyAdmin/doc/html/_static/file.png create mode 100644 phpMyAdmin/doc/html/_static/jquery.js create mode 100644 phpMyAdmin/doc/html/_static/minus.png create mode 100644 phpMyAdmin/doc/html/_static/plus.png create mode 100644 phpMyAdmin/doc/html/_static/pygments.css create mode 100644 phpMyAdmin/doc/html/_static/searchtools.js create mode 100644 phpMyAdmin/doc/html/_static/sidebar.js create mode 100644 phpMyAdmin/doc/html/_static/underscore.js create mode 100644 phpMyAdmin/doc/html/_static/up-pressed.png create mode 100644 phpMyAdmin/doc/html/_static/up.png create mode 100644 phpMyAdmin/doc/html/_static/websupport.js create mode 100644 phpMyAdmin/doc/html/config.html create mode 100644 phpMyAdmin/doc/html/copyright.html create mode 100644 phpMyAdmin/doc/html/credits.html create mode 100644 phpMyAdmin/doc/html/developers.html create mode 100644 phpMyAdmin/doc/html/faq.html create mode 100644 phpMyAdmin/doc/html/genindex.html create mode 100644 phpMyAdmin/doc/html/glossary.html create mode 100644 phpMyAdmin/doc/html/index.html create mode 100644 phpMyAdmin/doc/html/intro.html create mode 100644 phpMyAdmin/doc/html/objects.inv create mode 100644 phpMyAdmin/doc/html/other.html create mode 100644 phpMyAdmin/doc/html/privileges.html create mode 100644 phpMyAdmin/doc/html/require.html create mode 100644 phpMyAdmin/doc/html/search.html create mode 100644 phpMyAdmin/doc/html/searchindex.js create mode 100644 phpMyAdmin/doc/html/setup.html create mode 100644 phpMyAdmin/doc/html/transformations.html create mode 100644 phpMyAdmin/doc/html/user.html create mode 100644 phpMyAdmin/doc/html/vendors.html create mode 100644 phpMyAdmin/doc/index.rst create mode 100644 phpMyAdmin/doc/intro.rst create mode 100644 phpMyAdmin/doc/make.bat create mode 100644 phpMyAdmin/doc/other.rst create mode 100644 phpMyAdmin/doc/privileges.rst create mode 100644 phpMyAdmin/doc/require.rst create mode 100644 phpMyAdmin/doc/setup.rst create mode 100644 phpMyAdmin/doc/transformations.rst create mode 100644 phpMyAdmin/doc/user.rst create mode 100644 phpMyAdmin/doc/vendors.rst create mode 100644 phpMyAdmin/error_report.php create mode 100644 phpMyAdmin/js/ajax.js delete mode 100644 phpMyAdmin/js/canvg/flashcanvas.js delete mode 100644 phpMyAdmin/js/canvg/flashcanvas.swf create mode 100644 phpMyAdmin/js/chart.js create mode 100644 phpMyAdmin/js/codemirror/addon/runmode/runmode.js delete mode 100644 phpMyAdmin/js/codemirror/mode/mysql/mysql.js create mode 100644 phpMyAdmin/js/codemirror/mode/sql/sql.js delete mode 100644 phpMyAdmin/js/date.js create mode 100644 phpMyAdmin/js/doclinks.js delete mode 100644 phpMyAdmin/js/dom-drag.js create mode 100644 phpMyAdmin/js/error_report.js create mode 100644 phpMyAdmin/js/get_scripts.js.php create mode 100644 phpMyAdmin/js/jqplot/plugins/jqplot.byteFormatter.js create mode 100644 phpMyAdmin/js/jquery/MIT-LICENSE.txt delete mode 100644 phpMyAdmin/js/jquery/jquery-1.6.2.js create mode 100644 phpMyAdmin/js/jquery/jquery-1.8.3.min.js delete mode 100644 phpMyAdmin/js/jquery/jquery-ui-1.8.16.custom.js create mode 100644 phpMyAdmin/js/jquery/jquery-ui-1.9.2.custom.min.js create mode 100644 phpMyAdmin/js/jquery/jquery-ui-timepicker-addon.js create mode 100644 phpMyAdmin/js/jquery/jquery.ba-hashchange-1.3.js create mode 100644 phpMyAdmin/js/jquery/jquery.debounce-1.0.5.js delete mode 100644 phpMyAdmin/js/jquery/jquery.event.drag-2.0.js create mode 100644 phpMyAdmin/js/jquery/jquery.event.drag-2.2.js create mode 100644 phpMyAdmin/js/jquery/jquery.fullscreen.js delete mode 100644 phpMyAdmin/js/jquery/jquery.json-2.2.js create mode 100644 phpMyAdmin/js/jquery/jquery.json-2.4.js create mode 100644 phpMyAdmin/js/jquery/jquery.menuResizer-1.0.js delete mode 100644 phpMyAdmin/js/jquery/jquery.qtip-1.0.0-rc3.js create mode 100644 phpMyAdmin/js/jquery/src/README create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.accordion.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.autocomplete.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.button.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.core.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.datepicker.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.dialog.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.draggable.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.droppable.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.effect-blind.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.effect-bounce.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.effect-clip.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.effect-drop.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.effect-explode.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.effect-fade.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.effect-fold.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.effect-highlight.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.effect-pulsate.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.effect-scale.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.effect-shake.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.effect-slide.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.effect-transfer.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.effect.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.menu.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.mouse.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.position.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.progressbar.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.resizable.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.selectable.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.slider.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.sortable.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.spinner.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.tabs.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.tooltip.js create mode 100644 phpMyAdmin/js/jquery/src/jquery-ui/jquery.ui.widget.js create mode 100644 phpMyAdmin/js/jquery/src/jquery/ajax.js create mode 100644 phpMyAdmin/js/jquery/src/jquery/ajax/jsonp.js create mode 100644 phpMyAdmin/js/jquery/src/jquery/ajax/script.js create mode 100644 phpMyAdmin/js/jquery/src/jquery/ajax/xhr.js create mode 100644 phpMyAdmin/js/jquery/src/jquery/attributes.js create mode 100644 phpMyAdmin/js/jquery/src/jquery/callbacks.js create mode 100644 phpMyAdmin/js/jquery/src/jquery/core.js create mode 100644 phpMyAdmin/js/jquery/src/jquery/css.js create mode 100644 phpMyAdmin/js/jquery/src/jquery/data.js create mode 100644 phpMyAdmin/js/jquery/src/jquery/deferred.js create mode 100644 phpMyAdmin/js/jquery/src/jquery/deprecated.js create mode 100644 phpMyAdmin/js/jquery/src/jquery/dimensions.js create mode 100644 phpMyAdmin/js/jquery/src/jquery/effects.js create mode 100644 phpMyAdmin/js/jquery/src/jquery/event-alias.js create mode 100644 phpMyAdmin/js/jquery/src/jquery/event.js create mode 100644 phpMyAdmin/js/jquery/src/jquery/intro.js create mode 100644 phpMyAdmin/js/jquery/src/jquery/manipulation.js create mode 100644 phpMyAdmin/js/jquery/src/jquery/offset.js create mode 100644 phpMyAdmin/js/jquery/src/jquery/outro.js create mode 100644 phpMyAdmin/js/jquery/src/jquery/queue.js create mode 100644 phpMyAdmin/js/jquery/src/jquery/selector-native.js create mode 100644 phpMyAdmin/js/jquery/src/jquery/serialize.js create mode 100644 phpMyAdmin/js/jquery/src/jquery/sizzle-jquery.js create mode 100644 phpMyAdmin/js/jquery/src/jquery/support.js create mode 100644 phpMyAdmin/js/jquery/src/jquery/traversing.js create mode 100644 phpMyAdmin/js/jquery/src/jquery/wrap.js delete mode 100644 phpMyAdmin/js/jquery/timepicker.js create mode 100644 phpMyAdmin/js/line_counts.php create mode 100644 phpMyAdmin/js/pmd/init.js create mode 100644 phpMyAdmin/js/rte.js delete mode 100644 phpMyAdmin/js/rte/common.js delete mode 100644 phpMyAdmin/js/rte/events.js delete mode 100644 phpMyAdmin/js/rte/routines.js delete mode 100644 phpMyAdmin/js/rte/triggers.js create mode 100644 phpMyAdmin/js/server_databases.js delete mode 100644 phpMyAdmin/js/server_status.js create mode 100644 phpMyAdmin/js/server_status_advisor.js create mode 100644 phpMyAdmin/js/server_status_queries.js create mode 100644 phpMyAdmin/js/server_status_sorter.js create mode 100644 phpMyAdmin/js/server_status_variables.js delete mode 100644 phpMyAdmin/js/server_synchronize.js create mode 100644 phpMyAdmin/js/server_user_groups.js create mode 100644 phpMyAdmin/js/tbl_find_replace.js create mode 100644 phpMyAdmin/js/tracekit/tracekit.js delete mode 100644 phpMyAdmin/js/update-location.js delete mode 100644 phpMyAdmin/libraries/.htaccess create mode 100644 phpMyAdmin/libraries/DBQbe.class.php create mode 100644 phpMyAdmin/libraries/DatabaseInterface.class.php create mode 100644 phpMyAdmin/libraries/DbSearch.class.php create mode 100644 phpMyAdmin/libraries/DisplayResults.class.php create mode 100644 phpMyAdmin/libraries/Footer.class.php create mode 100644 phpMyAdmin/libraries/Header.class.php create mode 100644 phpMyAdmin/libraries/Menu.class.php create mode 100644 phpMyAdmin/libraries/OutputBuffering.class.php create mode 100644 phpMyAdmin/libraries/Response.class.php create mode 100644 phpMyAdmin/libraries/Scripts.class.php create mode 100644 phpMyAdmin/libraries/ServerStatusData.class.php create mode 100644 phpMyAdmin/libraries/String.class.php create mode 100644 phpMyAdmin/libraries/StringAbstractType.class.php create mode 100644 phpMyAdmin/libraries/StringByte.int.php create mode 100644 phpMyAdmin/libraries/StringCType.class.php create mode 100644 phpMyAdmin/libraries/StringMB.class.php create mode 100644 phpMyAdmin/libraries/StringNative.class.php create mode 100644 phpMyAdmin/libraries/StringNativeType.class.php create mode 100644 phpMyAdmin/libraries/StringType.int.php create mode 100644 phpMyAdmin/libraries/TableSearch.class.php create mode 100644 phpMyAdmin/libraries/Types.class.php create mode 100644 phpMyAdmin/libraries/Util.class.php delete mode 100644 phpMyAdmin/libraries/auth/config.auth.lib.php delete mode 100644 phpMyAdmin/libraries/auth/cookie.auth.lib.php delete mode 100644 phpMyAdmin/libraries/auth/http.auth.lib.php delete mode 100644 phpMyAdmin/libraries/auth/signon.auth.lib.php delete mode 100644 phpMyAdmin/libraries/blobstreaming.lib.php delete mode 100644 phpMyAdmin/libraries/blowfish.php create mode 100644 phpMyAdmin/libraries/browse_foreigners.lib.php delete mode 100644 phpMyAdmin/libraries/common.lib.php create mode 100644 phpMyAdmin/libraries/config/Validator.class.php delete mode 100644 phpMyAdmin/libraries/config/validate.lib.php create mode 100644 phpMyAdmin/libraries/create_addfield.lib.php delete mode 100644 phpMyAdmin/libraries/data_drizzle.inc.php delete mode 100644 phpMyAdmin/libraries/data_mysql.inc.php create mode 100644 phpMyAdmin/libraries/database_interface.inc.php delete mode 100644 phpMyAdmin/libraries/database_interface.lib.php delete mode 100644 phpMyAdmin/libraries/db_links.inc.php delete mode 100644 phpMyAdmin/libraries/db_structure.lib.php create mode 100644 phpMyAdmin/libraries/dbi/DBIDrizzle.class.php create mode 100644 phpMyAdmin/libraries/dbi/DBIDummy.class.php create mode 100644 phpMyAdmin/libraries/dbi/DBIExtension.int.php create mode 100644 phpMyAdmin/libraries/dbi/DBIMysql.class.php create mode 100644 phpMyAdmin/libraries/dbi/DBIMysqli.class.php delete mode 100644 phpMyAdmin/libraries/dbi/drizzle.dbi.lib.php delete mode 100644 phpMyAdmin/libraries/dbi/mysql.dbi.lib.php delete mode 100644 phpMyAdmin/libraries/dbi/mysqli.dbi.lib.php create mode 100644 phpMyAdmin/libraries/display_export.inc.php create mode 100644 phpMyAdmin/libraries/display_git_revision.lib.php create mode 100644 phpMyAdmin/libraries/display_import.inc.php create mode 100644 phpMyAdmin/libraries/display_structure.inc.php delete mode 100644 phpMyAdmin/libraries/display_tbl.lib.php delete mode 100644 phpMyAdmin/libraries/engines/pbms.lib.php create mode 100644 phpMyAdmin/libraries/engines/performance_schema.lib.php create mode 100644 phpMyAdmin/libraries/error_report.lib.php delete mode 100644 phpMyAdmin/libraries/export/codegen.php delete mode 100644 phpMyAdmin/libraries/export/csv.php delete mode 100644 phpMyAdmin/libraries/export/excel.php delete mode 100644 phpMyAdmin/libraries/export/htmlword.php delete mode 100644 phpMyAdmin/libraries/export/json.php delete mode 100644 phpMyAdmin/libraries/export/latex.php delete mode 100644 phpMyAdmin/libraries/export/mediawiki.php delete mode 100644 phpMyAdmin/libraries/export/ods.php delete mode 100644 phpMyAdmin/libraries/export/odt.php delete mode 100644 phpMyAdmin/libraries/export/pdf.php delete mode 100644 phpMyAdmin/libraries/export/php_array.php delete mode 100644 phpMyAdmin/libraries/export/sql.php delete mode 100644 phpMyAdmin/libraries/export/texytext.php delete mode 100644 phpMyAdmin/libraries/export/xml.php delete mode 100644 phpMyAdmin/libraries/export/yaml.php rename phpMyAdmin/libraries/{file_listing.php => file_listing.lib.php} (84%) delete mode 100644 phpMyAdmin/libraries/footer.inc.php delete mode 100644 phpMyAdmin/libraries/grab_globals.lib.php delete mode 100644 phpMyAdmin/libraries/header.inc.php delete mode 100644 phpMyAdmin/libraries/header_http.inc.php delete mode 100644 phpMyAdmin/libraries/header_meta_style.inc.php delete mode 100644 phpMyAdmin/libraries/header_printview.inc.php delete mode 100644 phpMyAdmin/libraries/header_scripts.inc.php delete mode 100644 phpMyAdmin/libraries/import/README delete mode 100644 phpMyAdmin/libraries/import/csv.php delete mode 100644 phpMyAdmin/libraries/import/docsql.php delete mode 100644 phpMyAdmin/libraries/import/ldi.php delete mode 100644 phpMyAdmin/libraries/import/ods.php delete mode 100644 phpMyAdmin/libraries/import/shp.php delete mode 100644 phpMyAdmin/libraries/import/sql.php delete mode 100644 phpMyAdmin/libraries/import/upload/apc.php delete mode 100644 phpMyAdmin/libraries/import/upload/noplugin.php delete mode 100644 phpMyAdmin/libraries/import/upload/uploadprogress.php delete mode 100644 phpMyAdmin/libraries/import/xml.php create mode 100644 phpMyAdmin/libraries/index.lib.php create mode 100644 phpMyAdmin/libraries/insert_edit.lib.php create mode 100644 phpMyAdmin/libraries/mult_submits.lib.php create mode 100644 phpMyAdmin/libraries/mysql_charsets.inc.php create mode 100644 phpMyAdmin/libraries/navigation/Navigation.class.php create mode 100644 phpMyAdmin/libraries/navigation/NavigationHeader.class.php create mode 100644 phpMyAdmin/libraries/navigation/NavigationTree.class.php create mode 100644 phpMyAdmin/libraries/navigation/NodeFactory.class.php create mode 100644 phpMyAdmin/libraries/navigation/Nodes/Node.class.php create mode 100644 phpMyAdmin/libraries/navigation/Nodes/Node_Column.class.php create mode 100644 phpMyAdmin/libraries/navigation/Nodes/Node_Column_Container.class.php create mode 100644 phpMyAdmin/libraries/navigation/Nodes/Node_Database.class.php create mode 100644 phpMyAdmin/libraries/navigation/Nodes/Node_DatabaseChild.class.php create mode 100644 phpMyAdmin/libraries/navigation/Nodes/Node_Database_Container.class.php create mode 100644 phpMyAdmin/libraries/navigation/Nodes/Node_Event.class.php create mode 100644 phpMyAdmin/libraries/navigation/Nodes/Node_Event_Container.class.php create mode 100644 phpMyAdmin/libraries/navigation/Nodes/Node_Function.class.php create mode 100644 phpMyAdmin/libraries/navigation/Nodes/Node_Function_Container.class.php create mode 100644 phpMyAdmin/libraries/navigation/Nodes/Node_Index.class.php create mode 100644 phpMyAdmin/libraries/navigation/Nodes/Node_Index_Container.class.php create mode 100644 phpMyAdmin/libraries/navigation/Nodes/Node_Procedure.class.php create mode 100644 phpMyAdmin/libraries/navigation/Nodes/Node_Procedure_Container.class.php create mode 100644 phpMyAdmin/libraries/navigation/Nodes/Node_Table.class.php create mode 100644 phpMyAdmin/libraries/navigation/Nodes/Node_Table_Container.class.php create mode 100644 phpMyAdmin/libraries/navigation/Nodes/Node_Trigger.class.php create mode 100644 phpMyAdmin/libraries/navigation/Nodes/Node_Trigger_Container.class.php create mode 100644 phpMyAdmin/libraries/navigation/Nodes/Node_View.class.php create mode 100644 phpMyAdmin/libraries/navigation/Nodes/Node_View_Container.class.php delete mode 100644 phpMyAdmin/libraries/navigation_header.inc.php delete mode 100644 phpMyAdmin/libraries/ob.lib.php create mode 100644 phpMyAdmin/libraries/operations.lib.php create mode 100644 phpMyAdmin/libraries/parse_analyze.inc.php delete mode 100644 phpMyAdmin/libraries/parse_analyze.lib.php create mode 100644 phpMyAdmin/libraries/phpseclib/Crypt/AES.php create mode 100644 phpMyAdmin/libraries/phpseclib/Crypt/Rijndael.php create mode 100644 phpMyAdmin/libraries/plugins/AuthenticationPlugin.class.php create mode 100644 phpMyAdmin/libraries/plugins/ExportPlugin.class.php create mode 100644 phpMyAdmin/libraries/plugins/ImportPlugin.class.php create mode 100644 phpMyAdmin/libraries/plugins/PluginManager.class.php create mode 100644 phpMyAdmin/libraries/plugins/PluginObserver.class.php create mode 100644 phpMyAdmin/libraries/plugins/TransformationsInterface.int.php create mode 100644 phpMyAdmin/libraries/plugins/TransformationsPlugin.class.php create mode 100644 phpMyAdmin/libraries/plugins/UploadInterface.int.php create mode 100644 phpMyAdmin/libraries/plugins/auth/AuthenticationConfig.class.php create mode 100644 phpMyAdmin/libraries/plugins/auth/AuthenticationCookie.class.php create mode 100644 phpMyAdmin/libraries/plugins/auth/AuthenticationHttp.class.php create mode 100644 phpMyAdmin/libraries/plugins/auth/AuthenticationSignon.class.php create mode 100644 phpMyAdmin/libraries/plugins/auth/recaptchalib.php rename phpMyAdmin/libraries/{ => plugins}/auth/swekey/authentication.inc.php (100%) rename phpMyAdmin/libraries/{ => plugins}/auth/swekey/musbe-ca.crt (100%) rename phpMyAdmin/libraries/{ => plugins}/auth/swekey/swekey.auth.lib.php (66%) rename phpMyAdmin/libraries/{ => plugins}/auth/swekey/swekey.php (72%) create mode 100644 phpMyAdmin/libraries/plugins/export/ExportCodegen.class.php create mode 100644 phpMyAdmin/libraries/plugins/export/ExportCsv.class.php create mode 100644 phpMyAdmin/libraries/plugins/export/ExportExcel.class.php create mode 100644 phpMyAdmin/libraries/plugins/export/ExportHtmlword.class.php create mode 100644 phpMyAdmin/libraries/plugins/export/ExportJson.class.php create mode 100644 phpMyAdmin/libraries/plugins/export/ExportLatex.class.php create mode 100644 phpMyAdmin/libraries/plugins/export/ExportMediawiki.class.php create mode 100644 phpMyAdmin/libraries/plugins/export/ExportOds.class.php create mode 100644 phpMyAdmin/libraries/plugins/export/ExportOdt.class.php create mode 100644 phpMyAdmin/libraries/plugins/export/ExportPdf.class.php create mode 100644 phpMyAdmin/libraries/plugins/export/ExportPhparray.class.php create mode 100644 phpMyAdmin/libraries/plugins/export/ExportSql.class.php create mode 100644 phpMyAdmin/libraries/plugins/export/ExportTexytext.class.php create mode 100644 phpMyAdmin/libraries/plugins/export/ExportXml.class.php create mode 100644 phpMyAdmin/libraries/plugins/export/ExportYaml.class.php create mode 100644 phpMyAdmin/libraries/plugins/export/PMA_ExportPdf.class.php create mode 100644 phpMyAdmin/libraries/plugins/export/README create mode 100644 phpMyAdmin/libraries/plugins/export/TableProperty.class.php create mode 100644 phpMyAdmin/libraries/plugins/import/AbstractImportCsv.class.php create mode 100644 phpMyAdmin/libraries/plugins/import/ImportCsv.class.php create mode 100644 phpMyAdmin/libraries/plugins/import/ImportLdi.class.php create mode 100644 phpMyAdmin/libraries/plugins/import/ImportMediawiki.class.php create mode 100644 phpMyAdmin/libraries/plugins/import/ImportOds.class.php create mode 100644 phpMyAdmin/libraries/plugins/import/ImportShp.class.php create mode 100644 phpMyAdmin/libraries/plugins/import/ImportSql.class.php create mode 100644 phpMyAdmin/libraries/plugins/import/ImportXml.class.php create mode 100644 phpMyAdmin/libraries/plugins/import/README create mode 100644 phpMyAdmin/libraries/plugins/import/ShapeFile.class.php create mode 100644 phpMyAdmin/libraries/plugins/import/ShapeRecord.class.php create mode 100644 phpMyAdmin/libraries/plugins/import/upload/UploadApc.class.php create mode 100644 phpMyAdmin/libraries/plugins/import/upload/UploadNoplugin.class.php create mode 100644 phpMyAdmin/libraries/plugins/import/upload/UploadProgress.class.php create mode 100644 phpMyAdmin/libraries/plugins/import/upload/UploadSession.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/Application_Octetstream_Download.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/Application_Octetstream_Hex.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/Image_JPEG_Inline.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/Image_JPEG_Link.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/Image_PNG_Inline.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/README create mode 100644 phpMyAdmin/libraries/plugins/transformations/TEMPLATE create mode 100644 phpMyAdmin/libraries/plugins/transformations/TEMPLATE_ABSTRACT create mode 100644 phpMyAdmin/libraries/plugins/transformations/Text_Plain_Append.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/Text_Plain_Dateformat.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/Text_Plain_External.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/Text_Plain_Formatted.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/Text_Plain_Imagelink.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/Text_Plain_Link.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/Text_Plain_Longtoipv4.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/Text_Plain_Sql.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/Text_Plain_Substring.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/abstract/AppendTransformationsPlugin.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/abstract/DateFormatTransformationsPlugin.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/abstract/DownloadTransformationsPlugin.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/abstract/ExternalTransformationsPlugin.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/abstract/FormattedTransformationsPlugin.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/abstract/HexTransformationsPlugin.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/abstract/ImageLinkTransformationsPlugin.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/abstract/InlineTransformationsPlugin.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/abstract/LongToIPv4TransformationsPlugin.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/abstract/SQLTransformationsPlugin.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/abstract/SubstringTransformationsPlugin.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/abstract/TextImageLinkTransformationsPlugin.class.php create mode 100644 phpMyAdmin/libraries/plugins/transformations/abstract/TextLinkTransformationsPlugin.class.php create mode 100755 phpMyAdmin/libraries/plugins/transformations/generator_main_class.sh create mode 100755 phpMyAdmin/libraries/plugins/transformations/generator_plugin.sh create mode 100644 phpMyAdmin/libraries/properties/PropertyItem.class.php create mode 100644 phpMyAdmin/libraries/properties/options/OptionsPropertyGroup.class.php create mode 100644 phpMyAdmin/libraries/properties/options/OptionsPropertyItem.class.php create mode 100644 phpMyAdmin/libraries/properties/options/OptionsPropertyOneItem.class.php create mode 100644 phpMyAdmin/libraries/properties/options/groups/OptionsPropertyMainGroup.class.php create mode 100644 phpMyAdmin/libraries/properties/options/groups/OptionsPropertyRootGroup.class.php create mode 100644 phpMyAdmin/libraries/properties/options/groups/OptionsPropertySubgroup.class.php create mode 100644 phpMyAdmin/libraries/properties/options/items/BoolPropertyItem.class.php create mode 100644 phpMyAdmin/libraries/properties/options/items/DocPropertyItem.class.php create mode 100644 phpMyAdmin/libraries/properties/options/items/HiddenPropertyItem.class.php create mode 100644 phpMyAdmin/libraries/properties/options/items/MessageOnlyPropertyItem.class.php create mode 100644 phpMyAdmin/libraries/properties/options/items/NumberPropertyItem.class.php create mode 100644 phpMyAdmin/libraries/properties/options/items/RadioPropertyItem.class.php create mode 100644 phpMyAdmin/libraries/properties/options/items/SelectPropertyItem.class.php create mode 100644 phpMyAdmin/libraries/properties/options/items/TextPropertyItem.class.php create mode 100644 phpMyAdmin/libraries/properties/plugins/ExportPluginProperties.class.php create mode 100644 phpMyAdmin/libraries/properties/plugins/ImportPluginProperties.class.php create mode 100644 phpMyAdmin/libraries/properties/plugins/PluginPropertyItem.class.php delete mode 100644 phpMyAdmin/libraries/schema/Visio_Relation_Schema.class.php create mode 100644 phpMyAdmin/libraries/server_bin_log.lib.php create mode 100644 phpMyAdmin/libraries/server_collations.lib.php create mode 100644 phpMyAdmin/libraries/server_common.lib.php create mode 100644 phpMyAdmin/libraries/server_databases.lib.php create mode 100644 phpMyAdmin/libraries/server_engines.lib.php delete mode 100644 phpMyAdmin/libraries/server_links.inc.php create mode 100644 phpMyAdmin/libraries/server_plugins.lib.php create mode 100644 phpMyAdmin/libraries/server_privileges.lib.php create mode 100644 phpMyAdmin/libraries/server_status.lib.php create mode 100644 phpMyAdmin/libraries/server_status_advisor.lib.php create mode 100644 phpMyAdmin/libraries/server_status_monitor.lib.php create mode 100644 phpMyAdmin/libraries/server_status_queries.lib.php create mode 100644 phpMyAdmin/libraries/server_status_variables.lib.php delete mode 100644 phpMyAdmin/libraries/server_synchronize.lib.php create mode 100644 phpMyAdmin/libraries/server_user_groups.lib.php create mode 100644 phpMyAdmin/libraries/server_users.lib.php create mode 100644 phpMyAdmin/libraries/server_variables.lib.php delete mode 100644 phpMyAdmin/libraries/server_variables_doc.php create mode 100644 phpMyAdmin/libraries/special_schema_links.lib.php create mode 100644 phpMyAdmin/libraries/sql.lib.php create mode 100644 phpMyAdmin/libraries/string.inc.php delete mode 100644 phpMyAdmin/libraries/string.lib.php delete mode 100644 phpMyAdmin/libraries/string_mb.lib.php delete mode 100644 phpMyAdmin/libraries/string_native.lib.php delete mode 100644 phpMyAdmin/libraries/string_type_ctype.lib.php delete mode 100644 phpMyAdmin/libraries/string_type_native.lib.php create mode 100644 phpMyAdmin/libraries/structure.lib.php create mode 100644 phpMyAdmin/libraries/tbl_chart.lib.php create mode 100644 phpMyAdmin/libraries/tbl_columns_definition_form.inc.php create mode 100644 phpMyAdmin/libraries/tbl_columns_definition_form.lib.php create mode 100644 phpMyAdmin/libraries/tbl_common.inc.php delete mode 100644 phpMyAdmin/libraries/tbl_common.php rename phpMyAdmin/libraries/{gis_visualization.lib.php => tbl_gis_visualization.lib.php} (50%) create mode 100644 phpMyAdmin/libraries/tbl_indexes.lib.php delete mode 100644 phpMyAdmin/libraries/tbl_links.inc.php create mode 100644 phpMyAdmin/libraries/tbl_printview.lib.php delete mode 100644 phpMyAdmin/libraries/tbl_properties.inc.php create mode 100644 phpMyAdmin/libraries/tbl_relation.lib.php delete mode 100644 phpMyAdmin/libraries/tbl_replace_fields.inc.php delete mode 100644 phpMyAdmin/libraries/tbl_select.lib.php create mode 100644 phpMyAdmin/libraries/tbl_tracking.lib.php create mode 100644 phpMyAdmin/libraries/tbl_views.lib.php delete mode 100644 phpMyAdmin/libraries/tcpdf/encodings_maps.php delete mode 100644 phpMyAdmin/libraries/tcpdf/htmlcolors.php create mode 100644 phpMyAdmin/libraries/tcpdf/include/tcpdf_colors.php rename phpMyAdmin/libraries/tcpdf/{unicode_data.php => include/tcpdf_font_data.php} (72%) create mode 100644 phpMyAdmin/libraries/tcpdf/include/tcpdf_fonts.php create mode 100644 phpMyAdmin/libraries/tcpdf/include/tcpdf_images.php create mode 100644 phpMyAdmin/libraries/tcpdf/include/tcpdf_static.php create mode 100644 phpMyAdmin/libraries/tcpdf/tcpdf_autoconfig.php delete mode 100644 phpMyAdmin/libraries/transformations/README delete mode 100644 phpMyAdmin/libraries/transformations/TEMPLATE delete mode 100644 phpMyAdmin/libraries/transformations/TEMPLATE_MIMETYPE delete mode 100644 phpMyAdmin/libraries/transformations/application_octetstream__download.inc.php delete mode 100644 phpMyAdmin/libraries/transformations/application_octetstream__hex.inc.php delete mode 100644 phpMyAdmin/libraries/transformations/generator.sh delete mode 100644 phpMyAdmin/libraries/transformations/global.inc.php delete mode 100644 phpMyAdmin/libraries/transformations/image_jpeg__inline.inc.php delete mode 100644 phpMyAdmin/libraries/transformations/image_jpeg__link.inc.php delete mode 100644 phpMyAdmin/libraries/transformations/image_png__inline.inc.php delete mode 100644 phpMyAdmin/libraries/transformations/template_generator.sh delete mode 100644 phpMyAdmin/libraries/transformations/template_generator_mimetype.sh delete mode 100644 phpMyAdmin/libraries/transformations/text_plain__dateformat.inc.php delete mode 100644 phpMyAdmin/libraries/transformations/text_plain__external.inc.php delete mode 100644 phpMyAdmin/libraries/transformations/text_plain__formatted.inc.php delete mode 100644 phpMyAdmin/libraries/transformations/text_plain__imagelink.inc.php delete mode 100644 phpMyAdmin/libraries/transformations/text_plain__link.inc.php delete mode 100644 phpMyAdmin/libraries/transformations/text_plain__longToIpv4.inc.php delete mode 100644 phpMyAdmin/libraries/transformations/text_plain__sql.inc.php delete mode 100644 phpMyAdmin/libraries/transformations/text_plain__substr.inc.php create mode 100644 phpMyAdmin/locale/ar/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/bg/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/bn/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/ca/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/cs/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/da/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/de/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/el/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/en_GB/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/es/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/et/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/fi/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/fr/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/gl/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/hi/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/hu/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/ia/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/id/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/it/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/ja/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/ko/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/lt/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/nb/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/nl/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/pl/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/pt/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/pt_BR/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/ro/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/ru/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/si/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/sk/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/sl/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/sr@latin/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/sv/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/th/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/tr/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/uk/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/uz/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/uz@latin/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/zh_CN/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/locale/zh_TW/LC_MESSAGES/phpmyadmin.mo create mode 100644 phpMyAdmin/server_status_advisor.php create mode 100644 phpMyAdmin/server_status_monitor.php create mode 100644 phpMyAdmin/server_status_queries.php create mode 100644 phpMyAdmin/server_status_variables.php create mode 100644 phpMyAdmin/server_user_groups.php create mode 100644 phpMyAdmin/setup/ajax.js delete mode 100644 phpMyAdmin/setup/frames/.htaccess delete mode 100644 phpMyAdmin/setup/lib/.htaccess create mode 100644 phpMyAdmin/tbl_find_replace.php rename phpMyAdmin/themes/original/css/{theme_right.css.php => common.css.php} (63%) create mode 100644 phpMyAdmin/themes/original/css/navigation.css.php delete mode 100644 phpMyAdmin/themes/original/css/theme_left.css.php delete mode 100644 phpMyAdmin/themes/original/css/theme_print.css.php create mode 100644 phpMyAdmin/themes/original/img/b_column_add.png create mode 100644 phpMyAdmin/themes/original/img/b_find_replace.png create mode 100644 phpMyAdmin/themes/original/img/b_group.png create mode 100644 phpMyAdmin/themes/original/img/b_index_add.png create mode 100644 phpMyAdmin/themes/original/img/b_move.png create mode 100644 phpMyAdmin/themes/original/img/b_table_add.png create mode 100644 phpMyAdmin/themes/original/img/b_undo.png create mode 100644 phpMyAdmin/themes/original/img/b_view_add.png delete mode 100644 phpMyAdmin/themes/original/img/docs_menu_bg.png delete mode 100644 phpMyAdmin/themes/original/img/item_ltr.png delete mode 100644 phpMyAdmin/themes/original/img/item_rtl.png create mode 100644 phpMyAdmin/themes/original/img/lightbulb.png create mode 100644 phpMyAdmin/themes/original/img/lightbulb_off.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/1.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/2.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/2leftarrow.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/2leftarrow_m.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/2rightarrow.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/2rightarrow_m.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/3.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/4.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/5.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/6.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/7.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/8.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/FieldKey_small.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/Field_small.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/Field_small_char.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/Field_small_date.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/Field_small_int.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/Header.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/Header_Linked.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/and_icon.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/ang_direct.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/bord.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/bottom.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/def.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/display_field.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/downarrow1.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/downarrow2.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/downarrow2_m.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/exec.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/exec_small.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/favicon.ico delete mode 100644 phpMyAdmin/themes/original/img/pmd/grid.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/help.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/help_relation.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/left_panel_butt.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/left_panel_tab.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/minus.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/or_icon.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/pdf.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/plus.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/query_builder.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/relation.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/reload.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/resize.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/rightarrow1.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/rightarrow2.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/save.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/small_tab.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/table.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/toggle_lines.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/top_panel.png delete mode 100644 phpMyAdmin/themes/original/img/pmd/uparrow2_m.png delete mode 100644 phpMyAdmin/themes/original/img/s_attention.png delete mode 100644 phpMyAdmin/themes/original/img/s_okay.png delete mode 100644 phpMyAdmin/themes/original/img/s_process.png create mode 100644 phpMyAdmin/themes/original/img/s_top.png rename phpMyAdmin/themes/{pmahomme/jquery/jquery-ui-1.8.16.custom.css => original/jquery/jquery-ui-1.9.2.custom.css} (75%) create mode 100644 phpMyAdmin/themes/pmahomme/css/codemirror.css.php create mode 100644 phpMyAdmin/themes/pmahomme/css/common.css.php create mode 100644 phpMyAdmin/themes/pmahomme/css/enum_editor.css.php create mode 100644 phpMyAdmin/themes/pmahomme/css/gis.css.php create mode 100644 phpMyAdmin/themes/pmahomme/css/jqplot.css.php create mode 100644 phpMyAdmin/themes/pmahomme/css/navigation.css.php create mode 100644 phpMyAdmin/themes/pmahomme/css/pmd.css.php create mode 100644 phpMyAdmin/themes/pmahomme/css/resizable-menu.css.php create mode 100644 phpMyAdmin/themes/pmahomme/css/rte.css.php delete mode 100644 phpMyAdmin/themes/pmahomme/css/theme_left.css.php delete mode 100644 phpMyAdmin/themes/pmahomme/css/theme_print.css.php delete mode 100644 phpMyAdmin/themes/pmahomme/css/theme_right.css.php create mode 100644 phpMyAdmin/themes/pmahomme/img/b_column_add.png create mode 100644 phpMyAdmin/themes/pmahomme/img/b_find_replace.png create mode 100644 phpMyAdmin/themes/pmahomme/img/b_group.png create mode 100644 phpMyAdmin/themes/pmahomme/img/b_index_add.png create mode 100644 phpMyAdmin/themes/pmahomme/img/b_move.png create mode 100644 phpMyAdmin/themes/pmahomme/img/b_table_add.png create mode 100644 phpMyAdmin/themes/pmahomme/img/b_undo.png create mode 100644 phpMyAdmin/themes/pmahomme/img/b_view_add.png delete mode 100644 phpMyAdmin/themes/pmahomme/img/body_bg.png delete mode 100644 phpMyAdmin/themes/pmahomme/img/database_list_li_hover.png delete mode 100644 phpMyAdmin/themes/pmahomme/img/docs_menu_bg.png delete mode 100644 phpMyAdmin/themes/pmahomme/img/input_bg.gif delete mode 100644 phpMyAdmin/themes/pmahomme/img/item_ltr.png delete mode 100644 phpMyAdmin/themes/pmahomme/img/item_rtl.png create mode 100644 phpMyAdmin/themes/pmahomme/img/lightbulb.png create mode 100644 phpMyAdmin/themes/pmahomme/img/lightbulb_off.png delete mode 100644 phpMyAdmin/themes/pmahomme/img/marked_bg.png create mode 100644 phpMyAdmin/themes/pmahomme/img/pmd/exitFullscreen.png create mode 100644 phpMyAdmin/themes/pmahomme/img/pmd/viewInFullscreen.png create mode 100644 phpMyAdmin/themes/pmahomme/img/s_top.png delete mode 100644 phpMyAdmin/themes/pmahomme/img/tab_bg.png delete mode 100644 phpMyAdmin/themes/pmahomme/img/tab_hover_bg.png delete mode 100644 phpMyAdmin/themes/pmahomme/img/tabactive_bg.png rename phpMyAdmin/themes/{original/jquery/jquery-ui-1.8.16.custom.css => pmahomme/jquery/jquery-ui-1.9.2.custom.css} (75%) diff --git a/phpMyAdmin/CONTRIBUTING.md b/phpMyAdmin/CONTRIBUTING.md new file mode 100644 index 0000000..62c9798 --- /dev/null +++ b/phpMyAdmin/CONTRIBUTING.md @@ -0,0 +1,21 @@ +# Contributing to phpMyAdmin + +As an open source project, phpMyAdmin welcomes contributions of many forms. + +## Bug reporting + +Please report [bugs on SourceForge.net][1]. + +[1]: https://sourceforge.net/p/phpmyadmin/bugs/new/ + +## Patches submission + +Patches are welcome either as [pull requests on GitHub][2]. + +[2]: https://github.com/phpmyadmin/phpmyadmin/pulls + +## More information + +You can find more information on our website: + +http://www.phpmyadmin.net/home_page/improve.php diff --git a/phpMyAdmin/ChangeLog b/phpMyAdmin/ChangeLog index 0ec6062..619fb44 100644 --- a/phpMyAdmin/ChangeLog +++ b/phpMyAdmin/ChangeLog @@ -1,555 +1,61 @@ phpMyAdmin - ChangeLog ====================== -3.5.7.0 (2013-02-15) -- bug #3779 [core] Problem with backslash in enum fields -- bug #3816 Missing server_processlist.php -- bug #3821 Safari: white page -- Correct detection of the Chrome browser - -3.5.6.0 (2013-01-28) -- bug #3593604 [status] Erroneous advisor rule -- bug #3596070 [status] localStorage broken in server status monitor -- bug #3598736 [routines] Editing a procedure with special characters -- bug #3600322 [core] Visualize GIS data throws Fatal Error -- bug #3599362 [core] Double-escaped error message -- bug #3776 [cookies] Login without auth on second server - -3.5.5.0 (2012-12-21) -- bug #3563824 [export] Support Apache's mod_deflate -- bug #3585523 [interface] Inline query editing broken after row update -- bug #3586389 [setup] Cannot switch language in /setup -- bug #3585695 [CSS] Font size in inline query editor is way too big -- bug #3588354 [l10n] Portuguese Language not displaying correctly -- bug #3591412 [status] Live charts don't work for non-default server -- bug [core] Proxy ajax calls to pma.net to avoid browser notices -- bug #3593534 [tracking] Structure Snapshot on tracked view renders invalid -SQL -- bug #3544366 [events] Event comments not saved - -3.5.4.0 (2012-11-16) -- bug #3570212 [edit] uuid_short() is a no-arguments function -- bug #3569577 [edit] Add routine parameter headers not valid for "function" -- bug #3575799 [search] Various search operators not working as expected -- bug #3576322 [search] Invalid select query generated for tables with ENUM fields -- bug #3577468 [display] Incorrect imagejpeg Syntax Breaks Image Transformation -- bug #3578776 [search] Editing SQL not possible when no records found -- bug #3571970 [interface] Display chart and number of rows to plot -- bug #3582631 [core] Wrong redirect url caused cookies error with ForceSSL - -3.5.3.0 (2012-10-08) -- bug #3539044 [interface] Browse mode "Show" button gives blank page if no results anymore -- bug #3534979 [interface] Copy Database Ajax feedback vanishes long before copying is done -- bug #3527531 [interface] GC-maxlifetime warning incorrectly displayed -- bug #3526916 [interface] Search fails with JS error when tooltips disabled -- bug #3544366 [interface] Event comments not saved -- bug #3549084 [edit] Can't enter date directly when editing inline -- bug #3548491 [interface] Inline query editor doesn't work from search results -- bug #3547825 [edit] BLOB download no longer works -- bug #3541966 [config] Error in generated configuration arrray -- bug #3553551 [GUI] Invalid HTML code in multi submits confirmation form -- [interface] Designer sometimes places tables on the top menu -- bug #3546277 [core] Call to undefined function __() when config file has wrong permissions -- bug #3540922 [edit] Error searching table with many fields -- bug #3555104 [edit] Cannot copy a DB with table & views -- bug #3559925 [privileges] Incorrect updating of the list of users -- bug #3561224 [edit] cell edit date field with empty date fills in current date -- bug #3559955 [edit] current_date from function drop down fails on update -- bug #3562472 add support for Solaris and FreeBSD system load and memory display in server status -- bug #3553068 [import] Table import from XML file fails -- replace Highcharts with jqplot for Display chart -- bug #3567684 [edit] Pasting value doesn't clear null checkbox -- bug #3570786 [edit] Datepicker for date and datetime fields is broken - -3.5.2.2 (2012-08-12) -- [security] Fixed XSS vulnerabilities, see PMASA-2012-4 - -3.5.2.1 (2012-08-03) -- [security] Fixed local path disclosure vulnerability, see PMASA-2012-3 - -3.5.2.0 (2012-07-07) -- bug #3521416 [interface] JS error when editing index -- bug #3521313 [core] Call to undefined function __() -- bug #3521016 [edit] NOW() function incorrectly selected -- bug [GUI] Invalid HTML code on transformation_overview.php -- bug #3522930 [browse] Missing validation in Ajax mode -- bug Fix popup message on build SQL of import -- bug #3523499 [core] Make X-WebKit-CSP work better -- replace Highcharts with jqplot for query profiling, zoom search -- bug #3531584 [interface] No form validation in change password dialog -- bug #3531585 [interface] Broken password validation in copy user form -- bug #3531586 [unterface] Add user form prints JSON when user presses enter -- bug #3534121 [config] duplicate line in config.sample.inc.php -- bug #3534311 [interface] Grid editing incorrectly parses ENUM/SET values -- bug #3510196 [core] More clever URL rewriting with ForceSSL - -3.5.1.0 (2012-05-03) -- bug #3510784 [edit] Limit clause ignored when sort order is remembered -- bug #3511471 [interface] View name not seen in navi panel (MySQL 5.1) -- bug #3512916 [display] Right frame reloads after displaying SQL result(zero rows) -- bug [interface] Fixed missing Codemirror for inline query edit when exporting a result set -- bug #3514490 [auth] Multiple Navigation panels bug still present -- bug #3515181 [users] Error in create user + underscore + create database -- bug #3515666 [display] Profiling chart shows wrong data -- bug #3516037 [auth] JS includes missing in auth config error page -- bug #3516183 [display] Missing image extension -- bug [display] Added missing icons in original theme -- bug #3516761 [edit] Query error after search -- bug #3516405 [display] Chart title is getting wrong within chart export -- bug #3517021 [interface] Header links except 'More' hide after closing dialog -- bug #3516817 [interface] "More" actions in table structure -- bug #3518484 [privileges] PMA_sqlAddSlashes() does not quote the table names correctly -- bug #3518983 [designer] Error messages do not appear in the Designer -- bug #3519747 [interface] Suhosin patch warning incorrectly displayed -- bug #3520107 [interface] Server status page: Incorrect dialog box titles -- bug #3516089 [structure] DROP does not work on defective VIEWs - -3.5.0.0 (2012-04-07) -+ rfe #2021981 [interface] Add support for mass prefix change. -+ "up to date" message on main page when current version is up to date -+ Update to jQuery 1.6.2 -+ Patch #3256122 [search] Show/hide db search results -+ Patch #3302354 Add gettext wrappers around a message -+ Remove deprecated function PMA_DBI_get_fields -+ rfe #2098927 Remember recent tables -+ rfe #3078542 Remember the last sort order for each table -+ AJAX for Create table in navigation panel -+ rfe #3310562 Wording about Column -+ AJAX for Add a user in Database privileges -+ Patch #3271804 for rfe #3177495, new DisableMultiTableMaintenance directive -+ [interface] Reorganised server status page. -+ [interface] Changed way of generating charts. -+ rfe #939233 [interface] Flexible column width -+ [interface] Mouse-based column reordering in query results -+ AJAX for Insert to a table from database Structure page -- Patch #3316969 PMA_ajaxShowMessage() does not respect timeout -+ AJAX for Change on multiple rows in table Browse -+ [interface] Improved support for stored routines -+ [display] More options for browsing GIS data -+ [interface] Support for spatial indexes -+ [display] GIS data visualization -+ AJAX for table structure multiple-column change -+ AJAX for table structure index edit -+ Show/hide indexes in table Structure -+ More compact navigation bar -+ Display direction (horizontal/vertical) no longer displayed by default -+ Shift/click support in database Structure -+ Show/hide column in table Browse -- bug #3353856 [AJAX] AJAX dialogs use wrong font-size -- bug #3354356 [interface] Timepicker does not work in AJAX dialogs -+ AJAX for table Structure Indexes Edit -+ AJAX for table Structure column Change -+ [interface] Improved support for events -+ [interface] Improved support for triggers -+ [interface] Improved server monitoring -+ AJAX for table Structure column Add -+ AJAX for table Operations copy table -- bug #3380946 [export] no uid Query result export (Suhosin limit) -+ Grid editing in browse mode (replaces row inline edit) -+ Zoom-search in table Search -+ [interface] Editor for GIS data -+ [import] Import GIS data from ESRI Shapefiles -+ [interface] 'Function based search' for GIS data -+ Support Drizzle database -- bug #3356456 [interface] Interface problems for queries having LIMIT clauses -+ [interface] Remove DefaultPropDisplay feature -- bug #3299486 [prettyprint] Order By in a query containing comment character -+ [interface] Improved ENUM/SET editor -+ patch #3428376 [pmadb] pmadb on a different MySQL server -+ patch #3410688 [interface] Improving field size for character columns -- [usability] Removed an unnecessary AJAX request from database search -- bug #3302419 [navi] Tabs break when squeezing page -+ rfe #3406797 [navi] Stick table tools to top of page on scroll -+ rfe #1632106 [interface] Improved error handling -+ patch #3432835 [interface] Add useful intermediate pages to pageselector -+ [interface] Improved index editor -+ View editing via a generated ALTER VIEW -- bug #3408377 [interface] Deleting table from the DB does not change the table counter -+ rfe #3438266 [designer] Toggle for relation lines -- bug #3442069 [AJAX] database list not updated after adding/deleting a user + database -- bug #3461750 [edit] Sort by key generates wrong sql with limit clause -- bug #3340842 [structure] Error dropping index of non-existing column -- bug #3093145 [display] Page through rows returned from a view -+ patch #3303195 [interface] Checkbox to have SQL input remain -- patch #3472899 [export] Fixed CSV escape for the export -- patch #3475424 [import] Fixed CSV escape for the import -- bug #3482734 [interface] No warning on syntax error in search form -- bug #3423717 [core] Improved detection of SSL connection -+ FULLTEXT support for InnoDB, starting with MySQL 5.6.4 -- bug #3497151 [interface] Duplicate inline query edit box -- bug #3504567 [mime] Description of the transformation missing in the tooltip - -3.4.11.1 (2012-08-12) -- [security] Fixed XSS vulnerabilities, see PMASA-2012-4 - -3.4.11.0 (2012-04-14) -- bug #3486970 [import] Exception on XML import -- bug #3488777 [navi] $cfg['ShowTooltipAliasTB'] and blank names in navigation - -3.4.10.2 (2012-03-28) -- [security] Fixed local path disclosure vulnerability, see PMASA-2012-2 - -3.4.10.1 (2012-02-18) -- [security] XSS in replication setup, see PMASA-2012-1 - -3.4.10.0 (2012-02-14) -- bug #3460090 [interface] TextareaAutoSelect feature broken -- patch #3375984 [export] PHP Array export might generate invalid php code -- bug #3049209 [import] Import from ODS ignores cell that is the same as cell before -- bug #3463933 [display] SELECT DISTINCT displays wrong total records found -- patch #3458944 [operations] copy table data missing SET SQL_MODE='NO_AUTO_VALUE_ON_ZERO' -- bug #3469254 [edit] Setting data to NULL and drop-downs -- bug #3477063 [edit] Missing set fields and values in generated INSERT query -- bug #3460867 [libraries] license issue with TCPDF (updated to 5.9.145) - -3.4.9.0 (2011-12-21) -- bug #3442028 [edit] Inline editing enum fields with null shows no dropdown -- bug #3442004 [interface] DB suggestion not correct for user with underscore -- bug #3438420 [core] Magic quotes removed in PHP 5.4 -- bug #3398788 [session] No feedback when result is empty (signon auth_type) -- bug #3384035 [display] Problems regarding ShowTooltipAliasTB -- bug #3306875 [edit] Can't rename a database that contains views -- bug #3452506 [edit] Unable to move tables with triggers -- bug #3449659 [navi] Fast filter broken with table tree -- bug #3448485 [GUI] Firefox favicon frameset regression -- [core] Better compatibility with mysql extension -- [security] Self-XSS on export options (export server/database/table), see PMASA-2011-20 -- [security] Self-XSS in setup (host parameter), see PMASA-2011-19 - -3.4.8.0 (2011-12-01) -- bug #3425230 [interface] enum data split at space char (more space to edit) -- bug #3426840 [interface] ENUM/SET editor can't handle commas in values -- bug #3427256 [interface] no links to browse/empty views and tables -- bug #3430377 [interface] Deleted search results remain visible -- bug #3428627 [import] ODS import ignores memory limits -- bug #3426836 [interface] Visual column separation -- bug #3428065 [parser] TRUE not recognized by parser -+ patch #3433770 [config] Make location of php-gettext configurable -- patch #3430291 [import] Handle conflicts in some open_basedir situations -- bug #3431427 [display] Dropdown results - setting NULL does not work -- patch #3428764 [edit] Inline edit on multi-server configuration -- patch #3437354 [core] Notice: Array to string conversion in PHP 5.4 -- [interface] When ShowTooltipAliasTB is true, VIEW is wrongly shown as the - view name in main panel db Structure page -- bug #3439292 [core] Fail to synchronize column with name of keyword -- bug #3425156 [interface] Add column after drop -- [interface] Avoid showing the password in phpinfo()'s output -- bug #3441572 [GUI] 'newer version of phpMyAdmin' message not shown in IE8 -- bug #3407235 [interface] Entering the key through a lookup window does not reset NULL -- [security] Self-XSS on database names (Synchronize), see PMASA-2011-18 -- [security] Self-XSS on database names (Operations/rename), see PMASA-2011-18 -- [security] Self-XSS on column type (Create index), see PMASA-2011-18 -- [security] Self-XSS on column type (table Search), see PMASA-2011-18 -- [security] Self-XSS on invalid query (table overview), see PMASA-2011-18 - -3.4.7.1 (2011-11-10) -- [security] Fixed possible local file inclusion in XML import -(CVE-2011-4107). - -3.4.7.0 (2011-10-23) -- bug #3418610 [interface] Links in navigation when $cfg['MainPageIconic'] = false -- bug #3418849 [interface] Inline edit shows dropdowns even after closing -- bug [view] View renaming did not work -- bug [navi] Wrong icon for view (MySQL 5.5) -- bug #3420229 [doc] Missing documentation section -- bug #3423725 [pdf] Broken PDF file when exporting database to PDF -- [core] Allow to set language in URL -- bug #3425184 [doc] Fix links to PHP documentation -- bug #3426031 [export] Export to bzip2 is not working - -3.4.6.0 (2011-10-16) -- patch #3404173 InnoDB comment display with tooltips/aliases -- bug #3404886 [navi] Edit SQL statement after error -- bug #3403165 [interface] Collation not displayed for long enum fields -- bug #3399951 [export] Config for export compression not used -- bug #3400690 [privileges] DB-specific privileges won't submit -- bug #3410604 [config] Configuration storage incorrect suggested table name -- bug #3383572 [interface] Cannot execute saved query -- bug #3411535 [display] Full text button unchecks results display options -- bug #3411224 [display] Broken binary column when 'Show binary contents' is not set -- bug #3411633 [core] Call to undefined function PMA_isSuperuser() -- bug #3413743 [interface] Display options link missing after search -- bug #3324161 [core] CSP policy causing designer JS buttons to fail -- bug #3412862 [relation] Relations/constraints are dropped/created on every change -- bug #3390832 [display] Delete records from last page breaks search -- bug #3392150 [schema] PMA_User_Schema::processUserChoice() is broken -- bug #3414744 [core] External link fails in 3.4.5 -- patch #3314626 [display] CharTextareaRows is not respected -- bug #3417089 [synchronize] Extraneous db choices -- [security] Fixed local path disclosure vulnerability, see PMASA-2011-15 -- [security] Fixed XSS in setup (host/verbose parameter), see PMASA-2011-16 - -3.4.5.0 (2011-09-14) -- bug #3375325 [interface] Page list in navigation frame looks odd -- bug #3313235 [interface] Error div misplaced -- bug #3374802 [interface] Comment on a column breaks inline editing -- patch #3383711 [display] Order by a column in a view doesn't work in some cases -- bug #3386434 [interface] Add missing space to server status -- [core] Remove library PHPExcel, due to license issues -- [export] Remove native Excel export modules (xls and xlsx formats) -- [import] Remove native Excel import modules (xls and xlsx formats) -- bug #3392920 [edit] BLOB emptied after editing another column -- [security] Fixed XSS in Inline Edit on save action, see PMASA-2011-14 -- [security] Fixed XSS with db/table/column names, see PMASA-2011-14 - -3.4.4.0 (2011-08-24) -- bug #3323060 [parser] SQL parser breaks AJAX requests if query has unclosed quotes -- bug #3323101 [parser] Invalid escape sequence in SQL parser -- bug #3348995 [config] $cfg['Export']['asfile'] set to false does not select asText option -- bug #3340151 [export] Working SQL query exports error page -- bug #3353649 [interface] "Create an index on X columns" form not validated -- bug #3350790 [interface] JS error in Table->Structure->Index->Edit -- bug #3353811 [interface] Info message has "error" class -- bug #3357837 [interface] TABbing through a NULL field in the inline mode resets NULL -- remove version number in /setup -- bug #3367993 [usability] Missing "Generate Password" button -- bug #3363221 [display] Missing Server Parameter on inline sql query -- bug #3367986 [navi] Drop field -> lost active table -- remove misleading comment on the "Rename database" interface -- bug #3374374 [interface] Fix footnote for inexact count while browsing -- bug #3372807 [interface] Fix security warning link in setup -- bug #3374347 [display] Backquotes in normal text on import page -- bug #3358750 [core] With Suhosin, urls are too long in edit links -- [security] Missing sanitization on the table, column and index names leads to XSS vulnerabilities, see PMASA-2011-13 - -3.4.3.2 (2011-07-23) -- [security] Fixed XSS vulnerability, see PMASA-2011-9 -- [security] Fixed local file inclusion vulnerability, see PMASA-2011-10 -- [security] Fixed local file inclusion vulnerability and code execution, see PMASA-2011-11 -- [security] Fixed possible session manipulation in swekey authentication, see PMASA-2011-12 - -3.4.3.1 (2011-07-02) -- [security] Fixed possible session manipulation in swekey authentication, see PMASA-2011-5 -- [security] Fixed possible code injection incase session variables are compromised, see PMASA-2011-6 -- [security] Fixed regexp quoting issue in Synchronize code, see PMASA-2011-7 -- [security] Fixed filtering of a file path, which allowed for directory traversal, see PMASA-2011-8 - -3.4.3.0 (2011-06-27) -- bug #3311170 [sync] Missing helper icons in Synchronize -- patch #3304473 [setup] Redefine a lable that was wrong -- bug #3304544 [parser] master is not a reserved word -- bug #3307616 [edit] Inline edit updates multiple duplicate rows -- patch #3311539 [edit] Inline edit does not escape backslashes -- bug #3313210 [interface] Columns class sometimes changed for nothing -- patch #3313326 [interface] Some tooltips do not disappear -- bug #3315720 [search] Fix search in non unicode tables -- bug #3315741 [display] Inline query edit broken -- patch #3317206 [privileges] Generate password option missing on new accounts -- bug #3317293 [edit] Inline edit places HTML line breaks in edit area -- bug #3319466 [interface] Inline query edit does not escape special characters -- minor XSS (require a valid token) - -3.4.2.0 (2011-06-07) -- bug #3301249 [interface] Iconic table operations does not remove inline edit label -- bug #3303869 [interface] Unnecessary scrolling on Databases page -- patch #3303813 [setup] Define a label that was missing -- bug #3305606 [interface] Show all button wraps on privileges page -- bug #3305517 [config] Config for export compression not used -- bug #3305883 [interface] Table is dropped regardless of confirmation -- [auth] Fixed error handling for signon auth method. -- bug #3276001 [core] Avoid caching of index.php. -- bug #3306958 [interface] Unnecessary Details slider -- bug #3308476 [interface] "Show all" not persistent after a sort -- bug #3308072 [auth] Version disclosure to anonymous visitors -- bug #3306981 [interface] pmahomme and table statistics - -3.4.1.0 (2011-05-20) -- bug #3301108 [interface] Synchronize and already configured host -- bug #3302457 Inline edit and $cfg['PropertiesIconic'] -- Patch #3302313 Show a translated label -- bug #3300981 [navi] Table filter is case sensitive -- bug #3285929 [privileges] Revert temporary fix -- bug #3302872 [synchronize] Synchronize and user name -- bug #3302733 [core] Some browsers report an insecure https connection -- [security] Make redirector require valid token - -3.4.0.0 (2011-05-11) -+ rfe #2890226 [view] Enable VIEW rename -+ rfe #838637 [privileges] Export a user's privileges -- [core] Updated mootools to fix some glitches with Safari. -+ rfe #2816943 [interface] Add REGEXP ^...$ to select dialog. -+ rfe #2924956 [interface] Add insert ignore option to editing row. -+ rfe #2838080 [interface] Show warning when javascript is disabled. -+ rfe #2823707 [edit] Call UUID function separately to show it in insert. -+ rfe #2420684 [export] Allow export of timestamps in UTC. -+ [core] Remove config data from session as it brings chicken-egg problem. -+ [core] Cookie path now honors PmaAbsoluteUri. -+ rfe #2393597 [core] phpMyAdmin honors https in PmaAbsoluteUri. -+ rfe #1778337 [core] Try moving tables by RENAME and fail to CREATE/INSERT if that fails. -+ rfe #1721189 [core] Force reload js on code change. -+ rfe #1954161 [interface] Do not display long numbers in server status. -+ rfe #2033616 [edit] Add option to just display insert query. -+ rfe #1435032 [interface] Move SSL status to the end, it is usually empty. -+ rfe #1340812 [interface] Show numbers of columns in table structure. -+ rfe #1186511 [inrerface] Add link to reload navigation frame. -+ rfe #2936156 [auth] Signon authentication forwards error message through session data. -+ rfe #2835109 [interface] Move ^1 to the end of message. -+ rfe #854911 [interface] Grey out non applicable actions in structure -+ [interface] Allow to create new table from navigation frame (in light mode). -+ rfe #1025696 [browse] Add direct download of binary fields. -- [browse] Properly display NULL value for BLOB. -- rfe #1516803 [edit] Allow to set BLOB to/from NULL with ProtectBinary. -- [edit] Do not default to UNHEX when using file upload. -- rfe #1379201 [core] Add option to configure session_save_path. -+ [interface] Provide links to documentation in highlighted SQL. -+ [interface] It is now possible to bookmark most pages in JS capable browser. -- bug #2936482 [core] Fix SSL detection. -+ rfe #2937850 [doc] Add some hints to chk_rel.php for quick setup. -+ rfe #2938579 [interface] Add class to some elements for easier theming. -+ rfe #2937840 [doc] Add some interesting configs to config.sample.inc.php. -+ rfe #2792992 [doc] Added advice to re-login after changing pmadb settings -+ patch #2952353 [interface] Prefill "Copy table to" in tbl_operations.php, thanks to iinl -+ [lang] Add English (United Kingdom) translation, thanks to Robert Readman. -+ patch #2948421 [auth] HTTP Basic auth realm name, - thanks to Harald Jenny - haraldj -- bug #2954916 [interface] Do not insert doc links to not formatted SQL. -+ [lang] Chinese Simplified update, thanks to Shanyan Baishui - rimyxp -+ [lang] Turkish update, thanks to Burak Yavuz -+ rfe #2963310 [interface] Focus TEXTAREA "sql_query" on click on "SQL" link -+ [lang] Uzbek update, thanks to Orzu Samarqandiy -+ rfe #2958013 [import] After import, also list uploaded filename, thanks - to Pavel Konnikov and Herman van Rink -+ patch #2974341 [structure] Clicking on table name in db Structure should - Browse the table if possible, thanks to bhdouglass - dougboybhd -+ patch #2975533 [search] New search operators, thanks to - Martynas MickeviÄius -+ patch #2967320 [designer] Colored relations based on the primary key, - thanks to GreenRover - greenrover -- [core] Provide way for vendors to easily change paths to config files. -+ patch #2979922, rfe #2804874 [interface] Add inline query editing, thanks to Muhammd Adnan. -- bug #2966752 [setup] Allow to configure changes tracking in setup script. -+ patch #2981165 [edit] Optionally disable the Type column, - thanks to Brian Douglass - bhdouglass -+ patch #2984058 [edit] Buttons for quicky creating common SQL queries, thanks - to sutharshan. -+ patch #2984337 [interface] Convert loading of export/import to jQuery ready - event, thanks to sutharshan. -- [edit] CURRENT_TIMESTAMP is also valid for datetime fields. -- patch #2985068 [engines] Fix parsing of PBXT status, thanks to Madhura Jayaratne. -- patch #2986073 [interface] Convert upload progress bar to jQuery, thanks to - Philip Frank. -- patch #2983960 [interface] Add javascript validation of datetime input, - thanks to Sutharshan Balachandren. -- rfe #2981999 [interface] Default sort order is now SMART. -- rfe #2972969 [interface] Fix flipping of headers in non-IE browsers. -+ rfe #2964518 [interface] Allow to choose servers from configuration for - synchronisation. -+ rfe #2988633 [relation] Improve ON DELETE/ON UPDATE drop-downs -+ rfe #2988629 [relation] Improve labels in relation view -+ rfe #2983207, patch #2988715 [interface] Use jQuery calendar dialog, thanks - to Muhammad Adnan. -+ [doc] Incorporate synchronisation docs into main document. -+ [core] Include Content Security Policy HTTP headers. -- bug #3004216 [CSS] Field attributes use inline CSS -- patch #2999595, rfe #2998130 [interface] Cleanup navigation frame. -- patch #3025161 [core] Prevent sending of unnecessary cookies, - thanks to Piotr Przybylski - crackpl -- bug [password] Generate password only available if JS is enabled - (fixed for Privileges and Change password) -- [core] RecodingEngine now accepts none as valid option. -+ [core] Dropped AllowAnywhereRecoding configuration variable. -- rfe #3016457 [interface] Define tab order in SQL form to allow easier tab - navigation. -+ [core] Centralized format string expansion, @VARIABLES@ are recommended way - now, used by file name templates, default queries, export and title - generating. -+ [validator] SQL validator works also with SOAP PHP extension. -- [interface] Better formatting for SQL validator results. -- [doc] The linked-tables infrastructure is now called phpMyAdmin - configuration storage. -- [interface] Move drop/empty links from being tabs to Operations tab. -- [interface] Fixed rendering of error/notice/info titles background. -- patch #3038293 [doc] Language and grammar fixes, - thanks to Isaac Bennetch - ibennetch -- patch #3038312 [export] JSON export, - thanks to Hauke Henningsen - blubberkeks152 -- rfe #1494550 [interface] Editor for SET/ENUM fields. -- rfe #2649375 [interface] Simplified interface to backup/restore. -- rfe #2973909 Users preferences -- [relations] Dropped WYSIWYG-PDF configuration variable. -- rfe #806035, #686260 [relations] Export relations to Dia, SVG and others -+ [interface] Added charts to status tab, profiling page and query results -+ [interface] AJAXification on various pages -- [core] Remove last remaining parts of profiling code which was removed in 2006. -- bug #3042665 [parser] Add workaround for MySQL way of handling backtick. -- bug #3056610 [interface] Removed modification options for information_schema -+ patch #3055886 [config] Add Left frame table filter visibility config option, thanks to eesau -- [core] Force generating of new session on login -+ rfe #1105678 [interface] Drop page-break-before as it is useless for smaller - tables. -+ rfe #2956556 [interface] Allow to wrap enum values. -- bug #1669459 [interface] Do not automatically mark PDF schema rows to delete -- bug #3087682 [interface] Do not apply LeftFrameDBSeparator on first character. -+ rfe #3111455 [interface] Column highlighting and marking in table view -+ Visual query builder -- bug #3115519 [interface] Prevent long queries from being shown in confirmation popup -- patch #3112792 [navi] Left panel table grouping incorrect, - thanks to garas - garas -- bug #3123433 [interface] Avoid double escaping of MySQL errors. -- [interface] Use less noisy message and remove disable link on server charts and database statistics. -+ rfe #3141330 [relation] When displaying results, show a link to the foreign - table even when phpMyAdmin configuration storage is not active -- bug #3141327 [relation] Foreign key input options -- [export] Better handling of export to PHP array. -- rfe #3158867 [privileges] No DROP DATABASE warning if you delete a user -- [interface] Add link to documentation for status variables. -- [security] Redirect external links to avoid Referer leakage. -- [interface] Default to not count tables in database. -- patch #3172172 [interface] Shortcut for copying table row. -- bug #3175227 [auth] Reset user cache on login. -- rfe #3148361 [interface] Replace hard coded limit with $cfg['LimitChars']. -- bug #3177136 [interface] Indicate that bookmark is being used on browse. -- [interface] Indicate shared bookmarks in interface. -- patch #3176420 [Search] Ajaxify browse and delete criteria in DB Search, - thanks to Thilanka Kaushalya -- [interface] New default theme pmahomme, dropped darkblue_orange theme. -- rfe #2936155 [auth] Allow to pass additional parameters using signon method. -- rfe #1640812 [auth] Add example for OpenID authentication using signon method. -- rfe #1312657 [dbi] Default to mysqli extension. -- rfe #1168350 [interface] Add clear button to SQL edit box. -- [core] Update library PHPExcel to version 1.7.6 -- bug #3206876 [core] Work without mbstring installed. -- rfe #3196075, patch #3212068 [interface] Add links to variables documentation. -- bug #3208723 [import] Fix import of utf-8 XML files. -- bug #3039384 [auth] Force signon auth on signon URL change. -- bug #3168733 [core] Synchronization does not honor AllowArbitraryServer -- bug #3134495 [synchronization] Data containing single quotes prevents sync, - thanks to jviewer -- Remove the custom color picker feature -- bug #3285929 [privileges] Don't fail silently on missing priviledge to execute REVOKE ALL PRIVILEGES - -3.3.11.0 (not yet released) - -3.3.10.1 (2011-05-20) -- [security] XSS on Tracking page - -3.3.10.0 (2011-03-19) -- patch #3147400 [structure] Aria table size printed as unknown, - thanks to erickoh75 - erickoh75 -- patch #3150164 [structure] Ordering by size gives incorrect results, - thanks to Madhura Jayaratne - madhuracj -- bug #3153409 [core] 0 row(s) affected -- bug #3155842 [core] Edit relational page and page number -- [security] Minor security fixes, see PMASA-2010-9 and PMASA-2010-10 -- [lang] German update, thanks to to jannicars@users.sourceforge.net. - -3.3.9.2 (2011-02-11) -- [security] SQL injection, see PMASA-2011-2 - -3.3.9.1 (2011-02-08) -- [security] Path disclosure, see PMASA-2011-1 - -3.3.9.0 (2011-01-03) -- bug [doc] Fix references to MySQL doc -- patch #3101490 Default function for TIMESTAMP, thanks to jirand - jirand -- bug #3103853 [js] Double quotes were not escaped in generated js -- bug #3077463 [core] Events were not copied when copying/renaming database -- bug #1762306 [core] Copy database with view of a view -- patch #3117535 [replication] Add quotes to database in initial statement, - thanks to Craig Duncan - duncan3dc -- bug #3112614 [pdf schema] Scratchboard for PDF pages not working -- bug #3125606 [parser] Query for table "level" causes strange display -- bug #3127904 [parser] Close all opened round brackets indents +4.1.7.0 (2014-02-09) +- bug #4245 initial Browse query does not match sorting order +- bug #4250 Notice on export page +- bug #4253 "New" text in navigation frame acts like a database +- bug #4262 Cannot define a column with fractional seconds +- bug #4265 Missing datepicker icon for DATETIME(length) +- bug #4257 Hide fractional seconds when applicable +- bug #4264 Uncheck "Ignore" while inserting, upon leaving a textarea +- bug #4260 reCaptcha is ignoring language settings +- bug #4259 reCaptcha sound session expired problem +- bug #4263 Japanese character encoding not working properly when exporting +- bug #4269 Notice on table relation page +- bug #4270 Bad text-color for table comments +- bug #4278 reCaptcha re-login requires double effort +- bug #4272 Incorrect tabindex +- bug #4271 Query by example and the second criteria line +- bug #4242 Wildcard-containing only_db failure in sidebar + +4.1.6.0 (2014-01-26) +- bug #4232 User not found after creating the user +- bug #4241 Confusing dialog when trying to create an already existing user +- bug #4239 Missing LIMIT clause for some queries +- rfe #1489 Do not show create icon when user has no privileges +- bug #4218 Chrome behavior with date fields +- bug #3579 NOW() function incorrectly selected (regression) +- bug #4244 Advisor complaints about MariaDB 10.x is version less than 5.1 +- bug #3889 When login fails and error display is active, login data is +displayed (regression) +- bug #4247 open_basedir warnings on export page +- bug #4013 AJAX request waiting until version info is retrieved +- bug #4248 js error when changing number of columns in status monitor + +4.1.5.0 (2014-01-17) +- bug #3780 Allow aborting loading pages +- bug #4223 Database list: Create database misses collation column +- bug #4224 Empty table names when a table is "inuse" +- bug #4225 Partition maintenance broken +- bug #4219 Table list (left panel) does not reload when table renamed +- bug #4230 "in use" displayed for all views in database print view +- bug #4226 Notice: Undefined index: pma_config_loading +- bug #4221 Bzip2 export cannot be directly imported (so withdraw bz2 export) +- bug #4204 Reloading user privileges hides user groups submenu +- bug #4231 DATE columns quick edit decrement by one day + +4.1.4.0 (2014-01-07) +- bug #3840 (additional fix) When exporting to gzip format, the data is compressed 2 times +- bug #4209 Missing compression in one case +- bug #4208 Can't browse tables after sorting on columns with fieldnames that have a '-' +- bug #4184 Switch to wrong page after adding an index +- bug #3885 Additional fix for this bug +- bug #4212 Table "disappears" if it has the same name as its tablegroup +- bug #4213 Datetime Quick Edit decrements by one day +- bug #4217 Current value not highlighted when browsing foreign values +- bug #4220 Incorrect key values in foreign key browser +- bug #4215 MariaDB 5.5: error in Drizzle detection --- Older ChangeLogs can be found on our project website --- http://www.phpmyadmin.net/old-stuff/ChangeLogs/ diff --git a/phpMyAdmin/README b/phpMyAdmin/README index 19a9c73..1aaff94 100644 --- a/phpMyAdmin/README +++ b/phpMyAdmin/README @@ -1,7 +1,7 @@ phpMyAdmin - Readme =================== -Version 3.5.7 +Version 4.1.7 A set of PHP-scripts to manage MySQL over the web. @@ -13,7 +13,7 @@ Copyright Copyright (C) 1998-2000 Tobias Ratschiller -Copyright (C) 2001-2013 +Copyright (C) 2001-2014 Marc Delisle Olivier Müller Robin Johnson @@ -22,7 +22,7 @@ Copyright (C) 2001-2013 Garvin Hicking Michael Keck Sebastian Mendel - [check Documentation.txt/.html file for more details] + [check documentation for more details] License ------- @@ -39,10 +39,30 @@ details. You should have received a copy of the GNU General Public License along with this program. If not, see . +Third party licenses +-------------------- + +phpMyAdmin includes several third party libraries which come under their +respective licenses. + +jQuery's license, which is where we got the files under js/jquery/ is +(MIT|GPL), a copy of each license is available in this repository (GPL +is available as LICENSE, MIT as js/jquery/MIT-LICENSE.txt). + +TCPDF which is located under libraries/tcpdf is released under GPL +version 3 and the license is available as libraries/tcpdf/LICENSE.TXT. + +DejaVu fonts which are located under libraries/tcpdf/fonts/ and their +license is documented in +libraries/tcpdf/fonts/dejavu-fonts-ttf-2.33/LICENSE. + +PHP-gettext which is located under libraries/php-gettext/ is released +under GPL version 2 license which is available in the LICENSE file. + Requirements ------------ -* PHP 5.2 or later +* PHP 5.3 or later * MySQL 5.0 or later * a web-browser (doh!) @@ -50,7 +70,7 @@ Summary ------- phpMyAdmin is intended to handle the administration of MySQL over the web. -For a summary of features, please see the Documentation.txt/.html file. +For a summary of features, please see the documentation in the doc folder. Download -------- @@ -60,7 +80,7 @@ You can get the newest version at http://www.phpmyadmin.net/. More Information ---------------- -Please see the Documentation.txt/.html file. +Please see the documentation in the doc folder. Support ------- @@ -80,5 +100,5 @@ Please, don't send us emails with question like "How do I compile PHP with MySQL-support". We just don't have the time to be your free help desk. Please send your questions to the appropriate mailing lists / forums. Before -contacting us, please read the Documentation.html (esp. the FAQ part). +contacting us, please read the documentation (especially the FAQ part). diff --git a/phpMyAdmin/RELEASE-DATE-4.1.7 b/phpMyAdmin/RELEASE-DATE-4.1.7 new file mode 100644 index 0000000..7cdc65f --- /dev/null +++ b/phpMyAdmin/RELEASE-DATE-4.1.7 @@ -0,0 +1 @@ +Sun Feb 9 12:39:08 UTC 2014 diff --git a/phpMyAdmin/browse_foreigners.php b/phpMyAdmin/browse_foreigners.php index 3eff09f..0384350 100644 --- a/phpMyAdmin/browse_foreigners.php +++ b/phpMyAdmin/browse_foreigners.php @@ -6,297 +6,61 @@ * @package PhpMyAdmin */ +require_once 'libraries/common.inc.php'; +require_once 'libraries/transformations.lib.php'; +require_once 'libraries/browse_foreigners.lib.php'; + /** - * Gets a core script and starts output buffering work + * Sets globals from $_REQUEST */ -require_once './libraries/common.inc.php'; - -PMA_checkParameters(array('db', 'table', 'field')); +$request_params = array( + 'data', + 'field' +); + +foreach ($request_params as $one_request_param) { + if (isset($_REQUEST[$one_request_param])) { + $GLOBALS[$one_request_param] = $_REQUEST[$one_request_param]; + } +} -require_once './libraries/ob.lib.php'; -PMA_outBufferPre(); +PMA_Util::checkParameters(array('db', 'table', 'field')); -require_once './libraries/header_http.inc.php'; +$response = PMA_Response::getInstance(); +$response->getFooter()->setMinimal(); +$header = $response->getHeader(); +$header->disableMenu(); +$header->setBodyId('body_browse_foreigners'); /** * Displays the frame */ -require_once './libraries/transformations.lib.php'; // Transformations + $cfgRelation = PMA_getRelationsParam(); $foreigners = ($cfgRelation['relwork'] ? PMA_getForeigners($db, $table) : false); +$foreign_limit = PMA_getForeignLimit( + isset($foreign_navig) ? $foreign_navig : null +); -$override_total = true; - -if (! isset($pos)) { - $pos = 0; -} - -$foreign_limit = 'LIMIT ' . $pos . ', ' . $GLOBALS['cfg']['MaxRows'] . ' '; -if (isset($foreign_navig) && $foreign_navig == __('Show all')) { - unset($foreign_limit); -} +$foreignData = PMA_getForeignData( + $foreigners, $_REQUEST['field'], true, + isset($_REQUEST['foreign_filter']) + ? $_REQUEST['foreign_filter'] + : '', + isset($foreign_limit) ? $foreign_limit : null +); -$foreignData = PMA_getForeignData($foreigners, $field, $override_total, isset($foreign_filter) ? $foreign_filter : '', $foreign_limit); -if (isset($rownumber)) { - $rownumber_param = '&rownumber=' . urlencode($rownumber); -} else { - $rownumber_param = ''; -} - -$gotopage = ''; -$showall = ''; +$code = PMA_getJsScriptToHandleSelectRelationalFields(); -if (is_array($foreignData['disp_row'])) { +$header->getScripts()->addCode($code); - if ($cfg['ShowAll'] && ($foreignData['the_total'] > $GLOBALS['cfg']['MaxRows'])) { - $showall = ''; - } +// HTML output +$html = PMA_getHtmlForRelationalFieldSelection( + $db, $table, $_REQUEST['field'], $foreignData, + isset($fieldkey) ? $fieldkey : null, + isset($data) ? $data : null +); - $session_max_rows = $GLOBALS['cfg']['MaxRows']; - $pageNow = @floor($pos / $session_max_rows) + 1; - $nbTotalPage = @ceil($foreignData['the_total'] / $session_max_rows); - - if ($foreignData['the_total'] > $GLOBALS['cfg']['MaxRows']) { - $gotopage = PMA_pageselector( - $session_max_rows, - $pageNow, - $nbTotalPage, - 200, - 5, - 5, - 20, - 10, - __('Page number:') - ); - } -} -?> - - - - - phpMyAdmin - - -addHtml($html); ?> - - - - - -
-
- - - - - - - - - - - - - - - - - -
-
- - - - - - - - - '; - - echo '' . $header . '' . "\n" - .'' . $header . '' . "\n" - .'' . "\n"; - - $values = array(); - $keys = array(); - foreach ($foreignData['disp_row'] as $relrow) { - if ($foreignData['foreign_display'] != false) { - $values[] = $relrow[$foreignData['foreign_display']]; - } else { - $values[] = ''; - } - - $keys[] = $relrow[$foreignData['foreign_field']]; - } - - asort($keys); - - $hcount = 0; - $odd_row = true; - $val_ordered_current_row = 0; - $val_ordered_current_equals_data = false; - $key_ordered_current_equals_data = false; - foreach ($keys as $key_ordered_current_row => $value) { - //for ($i = 0; $i < $count; $i++) { - $hcount++; - - if ($cfg['RepeatCells'] > 0 && $hcount > $cfg['RepeatCells']) { - echo $header; - $hcount = 0; - $odd_row = true; - } - - $key_ordered_current_key = $keys[$key_ordered_current_row]; - $key_ordered_current_val = $values[$key_ordered_current_row]; - - $val_ordered_current_key = $keys[$val_ordered_current_row]; - $val_ordered_current_val = $values[$val_ordered_current_row]; - - $val_ordered_current_row++; - - if (PMA_strlen($val_ordered_current_val) <= $cfg['LimitChars']) { - $val_ordered_current_val = htmlspecialchars($val_ordered_current_val); - $val_ordered_current_val_title = ''; - } else { - $val_ordered_current_val_title - = htmlspecialchars($val_ordered_current_val); - $val_ordered_current_val = htmlspecialchars( - PMA_substr($val_ordered_current_val, 0, $cfg['LimitChars']) - . '...' - ); - } - if (PMA_strlen($key_ordered_current_val) <= $cfg['LimitChars']) { - $key_ordered_current_val = htmlspecialchars($key_ordered_current_val); - $key_ordered_current_val_title = ''; - } else { - $key_ordered_current_val_title - = htmlspecialchars($key_ordered_current_val); - $key_ordered_current_val - = htmlspecialchars( - PMA_substr($key_ordered_current_val, 0, $cfg['LimitChars']) . '...' - ); - } - - if (! empty($data)) { - $val_ordered_current_equals_data = $val_ordered_current_key == $data; - $key_ordered_current_equals_data = $key_ordered_current_key == $data; - } - - ?> - - - - - - - - - - -
' . __('Keyname') . '' . __('Description') . '' . __('Description') . '' . __('Keyname') . '
- ' : '') - .'' - .htmlspecialchars($key_ordered_current_key) . '' . ($key_ordered_current_equals_data ? '' : ''); - ?> - ' : '') - . '' - . $key_ordered_current_val . '' . ($key_ordered_current_equals_data ? '' : ''); - ?> - - ' : '') - . '' - . $val_ordered_current_val . '' . ($val_ordered_current_equals_data ? '' : ''); - ?> - ' : '') . '' . htmlspecialchars($val_ordered_current_key) - . '' . ($val_ordered_current_equals_data ? '' : ''); - ?>
- - - diff --git a/phpMyAdmin/changelog.php b/phpMyAdmin/changelog.php index fcd727f..5066ffe 100644 --- a/phpMyAdmin/changelog.php +++ b/phpMyAdmin/changelog.php @@ -9,7 +9,10 @@ /** * Gets core libraries and defines some variables */ -require './libraries/common.inc.php'; +require 'libraries/common.inc.php'; + +$response = PMA_Response::getInstance(); +$response->disable(); $filename = CHANGELOG_FILE; @@ -29,7 +32,10 @@ $changelog = file_get_contents($filename); } } else { - printf(__('The %s file is not available on this system, please visit www.phpmyadmin.net for more information.'), $filename); + printf( + __('The %s file is not available on this system, please visit www.phpmyadmin.net for more information.'), + $filename + ); exit; } @@ -38,6 +44,13 @@ */ $changelog = htmlspecialchars($changelog); +$tracker_url = 'https://sourceforge.net/support/tracker.php?aid=\\1'; +$tracker_url_bug = 'https://sourceforge.net/p/phpmyadmin/bugs/\\1/'; +$tracker_url_rfe = 'https://sourceforge.net/p/phpmyadmin/feature-requests/\\1/'; +$tracker_url_patch = 'https://sourceforge.net/p/phpmyadmin/patches/\\1/'; +$github_url = 'https://github.com/phpmyadmin/phpmyadmin/'; +$faq_url = 'http://docs.phpmyadmin.net/en/latest/faq.html'; + $replaces = array( '@(http://[./a-zA-Z0-9.-_-]*[/a-zA-Z0-9_])@' => '\\1', @@ -50,13 +63,13 @@ '/thanks to ([^\(\r\n]+) -\s+([-\w]+)/i' => 'thanks to \\1', - // mail adresse + // mail address '/([0-9]{4}-[0-9]{2}-[0-9]{2}) (.+[^ ]) +<(.*@.*)>/i' => '\\1 \\2', // linking patches '/patch\s*#?([0-9]{6,})/i' - => 'patch #\\1', + => 'patch #\\1', // linking RFE '/(?:rfe|feature)\s*#?([0-9]{6,})/i' @@ -64,11 +77,11 @@ // linking files '/(\s+)([\\/a-z_0-9\.]+\.(?:php3?|html|pl|js|sh))/i' - => '\\1\\2', + => '\\1\\2', // FAQ entries '/FAQ ([0-9]+)\.([0-9a-z]+)/i' - => 'FAQ \\1.\\2', + => 'FAQ \\1.\\2', // linking bugs '/bug\s*#?([0-9]{6,})/i' @@ -76,7 +89,18 @@ // all other 6+ digit numbers are treated as bugs '/(? ' bug #\\1', + => 'bug #\\1', + + // transitioned SF.net project bug/rfe/patch links + // by the time we reach 6-digit numbers, we can probably retire the above links + '/patch\s*#?([0-9]{4,5}) /i' + => 'patch #\\1 ', + '/(?:rfe|feature)\s*#?([0-9]{4,5}) /i' + => 'RFE #\\1 ', + '/bug\s*#?([0-9]{4,5}) /i' + => 'bug #\\1 ', + '/(? 'bug #\\1 ', // CVE/CAN entries '/((CAN|CVE)-[0-9]+-[0-9]+)/' @@ -88,9 +112,13 @@ // Highlight releases (with links) '/([0-9]+)\.([0-9]+)\.([0-9]+)\.0 (\([0-9-]+\))/' - => '\\1.\\2.\\3.0 \\4', + => '' + . '' + . '\\1.\\2.\\3.0 \\4', '/([0-9]+)\.([0-9]+)\.([0-9]+)\.([1-9][0-9]*) (\([0-9-]+\))/' - => '\\1.\\2.\\3.\\4 \\5', + => '' + . '' + . '\\1.\\2.\\3.\\4 \\5', // Highlight releases (not linkable) '/( ### )(.*)/' @@ -99,16 +127,14 @@ ); header('Content-type: text/html; charset=utf-8'); -echo ''; ?> - - + + - - -phpMyAdmin - ChangeLog - + + + phpMyAdmin - ChangeLog +

phpMyAdmin - ChangeLog

@@ -117,5 +143,11 @@ echo preg_replace(array_keys($replaces), $replaces, $changelog); echo ''; ?> + diff --git a/phpMyAdmin/chk_rel.php b/phpMyAdmin/chk_rel.php index e838d2e..915e8b2 100644 --- a/phpMyAdmin/chk_rel.php +++ b/phpMyAdmin/chk_rel.php @@ -1,25 +1,15 @@ addHTML( + PMA_getRelationsParamDiagnostic(PMA_getRelationsParam()) +); -/** - * Gets the relation settings - */ -$cfgRelation = PMA_getRelationsParam(true); - - -/** - * Displays the footer - */ -require './libraries/footer.inc.php'; ?> diff --git a/phpMyAdmin/composer.json b/phpMyAdmin/composer.json new file mode 100644 index 0000000..7b58ed7 --- /dev/null +++ b/phpMyAdmin/composer.json @@ -0,0 +1,27 @@ +{ + "name": "phpmyadmin/phpmyadmin", + "type": "application", + "description": "MySQL web administration tool", + "keywords": ["phpmyadmin","mysql","web"], + "homepage": "http://www.phpmyadmin.net/", + "license": "GPL-2.0+", + "authors": [ + { + "name": "The phpMyAdmin Team", + "email": "phpmyadmin-devel@lists.sourceforge.net", + "homepage": "http://www.phpmyadmin.net/home_page/team.php" + } + ], + "support": { + "forum": "https://sourceforge.net/p/phpmyadmin/discussion/Help", + "issues": "https://sourceforge.net/p/phpmyadmin/bugs/", + "wiki": "http://wiki.phpmyadmin.net/", + "source": "https://github.com/phpmyadmin/phpmyadmin" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "satooshi/php-coveralls": "dev-master" + } +} diff --git a/phpMyAdmin/config.sample.inc.php b/phpMyAdmin/config.sample.inc.php index da61640..07047ac 100644 --- a/phpMyAdmin/config.sample.inc.php +++ b/phpMyAdmin/config.sample.inc.php @@ -4,8 +4,8 @@ * phpMyAdmin sample configuration, you can use it as base for * manual configuration. For easier setup you can use setup/ * - * All directives are explained in Documentation.html and on phpMyAdmin - * wiki . + * All directives are explained in documentation in the doc/ folder + * or at . * * @package PhpMyAdmin */ @@ -41,23 +41,27 @@ /* User used to manipulate with storage */ // $cfg['Servers'][$i]['controlhost'] = ''; +// $cfg['Servers'][$i]['controlport'] = ''; // $cfg['Servers'][$i]['controluser'] = 'pma'; // $cfg['Servers'][$i]['controlpass'] = 'pmapass'; /* Storage database and tables */ // $cfg['Servers'][$i]['pmadb'] = 'phpmyadmin'; -// $cfg['Servers'][$i]['bookmarktable'] = 'pma_bookmark'; -// $cfg['Servers'][$i]['relation'] = 'pma_relation'; -// $cfg['Servers'][$i]['table_info'] = 'pma_table_info'; -// $cfg['Servers'][$i]['table_coords'] = 'pma_table_coords'; -// $cfg['Servers'][$i]['pdf_pages'] = 'pma_pdf_pages'; -// $cfg['Servers'][$i]['column_info'] = 'pma_column_info'; -// $cfg['Servers'][$i]['history'] = 'pma_history'; -// $cfg['Servers'][$i]['table_uiprefs'] = 'pma_table_uiprefs'; -// $cfg['Servers'][$i]['tracking'] = 'pma_tracking'; -// $cfg['Servers'][$i]['designer_coords'] = 'pma_designer_coords'; -// $cfg['Servers'][$i]['userconfig'] = 'pma_userconfig'; -// $cfg['Servers'][$i]['recent'] = 'pma_recent'; +// $cfg['Servers'][$i]['bookmarktable'] = 'pma__bookmark'; +// $cfg['Servers'][$i]['relation'] = 'pma__relation'; +// $cfg['Servers'][$i]['table_info'] = 'pma__table_info'; +// $cfg['Servers'][$i]['table_coords'] = 'pma__table_coords'; +// $cfg['Servers'][$i]['pdf_pages'] = 'pma__pdf_pages'; +// $cfg['Servers'][$i]['column_info'] = 'pma__column_info'; +// $cfg['Servers'][$i]['history'] = 'pma__history'; +// $cfg['Servers'][$i]['table_uiprefs'] = 'pma__table_uiprefs'; +// $cfg['Servers'][$i]['tracking'] = 'pma__tracking'; +// $cfg['Servers'][$i]['designer_coords'] = 'pma__designer_coords'; +// $cfg['Servers'][$i]['userconfig'] = 'pma__userconfig'; +// $cfg['Servers'][$i]['recent'] = 'pma__recent'; +// $cfg['Servers'][$i]['users'] = 'pma__users'; +// $cfg['Servers'][$i]['usergroups'] = 'pma__usergroups'; +// $cfg['Servers'][$i]['navigationhiding'] = 'pma__navigationhiding'; /* Contrib / Swekey authentication */ // $cfg['Servers'][$i]['auth_swekey_config'] = '/etc/swekey-pma.conf'; @@ -85,18 +89,13 @@ */ //$cfg['MaxRows'] = 50; -/** - * Use graphically less intense menu tabs - * default = false - */ -//$cfg['LightTabs'] = true; - /** * disallow editing of binary fields * valid values are: - * false allow editing - * 'blob' allow editing except for BLOB fields - * 'all' disallow editing + * false allow editing + * 'blob' allow editing except for BLOB fields + * 'noblob' disallow editing except for BLOB fields + * 'all' disallow editing * default = blob */ //$cfg['ProtectBinary'] = 'false'; @@ -139,8 +138,15 @@ */ //$cfg['QueryHistoryMax'] = 100; +/** + * Should error reporting be enabled for JavaScript errors + * + * default = 'ask' + */ +//$cfg['SendErrorReports'] = 'ask'; + /* - * You can find more configuration options in Documentation.html - * or here: http://wiki.phpmyadmin.net/pma/Config + * You can find more configuration options in the documentation + * in the doc/ folder or at . */ ?> diff --git a/phpMyAdmin/db_create.php b/phpMyAdmin/db_create.php index 2bebe0e..85443a4 100644 --- a/phpMyAdmin/db_create.php +++ b/phpMyAdmin/db_create.php @@ -1,6 +1,7 @@ tryQuery($sql_query); if (! $result) { - $message = PMA_Message::rawError(PMA_DBI_getError()); + $message = PMA_Message::rawError($GLOBALS['dbi']->getError()); // avoid displaying the not-created db name in header or navi panel $GLOBALS['db'] = ''; $GLOBALS['table'] = ''; /** - * If in an Ajax request, just display the message with {@link PMA_ajaxResponse} + * If in an Ajax request, just display the message with {@link PMA_Response} */ if ($GLOBALS['is_ajax_request'] == true) { - PMA_ajaxResponse($message, false); + $response = PMA_Response::getInstance(); + $response->isSuccess(false); + $response->addJSON('message', $message); + } else { + include_once 'index.php'; } - - include_once './libraries/header.inc.php'; - include_once './main.php'; } else { $message = PMA_Message::success(__('Database %1$s has been created.')); - $message->addParam($new_db); - $GLOBALS['db'] = $new_db; + $message->addParam($_POST['new_db']); + $GLOBALS['db'] = $_POST['new_db']; /** * If in an Ajax request, build the output and send it */ if ($GLOBALS['is_ajax_request'] == true) { + //Construct the html for the new database, so that it can be appended to + // the list of databases on server_databases.php /** - * String containing the SQL Query formatted in pretty HTML - * @global array $GLOBALS['extra_data'] - * @name $extra_data - */ - $extra_data['sql_query'] = PMA_showMessage(null, $sql_query, 'success'); - - //Construct the html for the new database, so that it can be appended to the list of databases on server_databases.php - - /** - * Build the array to be passed to {@link PMA_generate_common_url} to generate the links + * Build the array to be passed to {@link PMA_URL_getCommon} + * to generate the links + * * @global array $GLOBALS['db_url_params'] * @name $db_url_params */ - $db_url_params['db'] = $new_db; + $db_url_params['db'] = $_POST['new_db']; - $is_superuser = PMA_isSuperuser(); + $is_superuser = $GLOBALS['dbi']->isSuperuser(); $column_order = PMA_getColumnOrder(); - $url_query = PMA_generate_common_url($new_db); + $url_query = PMA_URL_getCommon($_POST['new_db']); /** * String that will contain the output HTML @@ -99,7 +95,7 @@ // $dbstats comes from the create table dialog if (! empty($dbstats)) { $current = array( - 'SCHEMA_NAME' => $new_db, + 'SCHEMA_NAME' => $_POST['new_db'], 'DEFAULT_COLLATION_NAME' => $db_collation_for_ajax, 'SCHEMA_TABLES' => '0', 'SCHEMA_TABLE_ROWS' => '0', @@ -111,21 +107,30 @@ ); } else { $current = array( - 'SCHEMA_NAME' => $new_db + 'SCHEMA_NAME' => $_POST['new_db'], + 'DEFAULT_COLLATION_NAME' => $db_collation_for_ajax ); } - list($column_order, $generated_html) = PMA_buildHtmlForDb($current, $is_superuser, (isset($checkall) ? $checkall : ''), $url_query, $column_order, $replication_types, $replication_info); + list($column_order, $generated_html) = PMA_buildHtmlForDb( + $current, $is_superuser, $url_query, + $column_order, $replication_types, $replication_info + ); $new_db_string .= $generated_html; $new_db_string .= ''; - $extra_data['new_db_string'] = $new_db_string; - - PMA_ajaxResponse($message, true, $extra_data); + $response = PMA_Response::getInstance(); + $response->addJSON('message', $message); + $response->addJSON('new_db_string', $new_db_string); + $response->addJSON( + 'sql_query', + PMA_Util::getMessage( + null, $sql_query, 'success' + ) + ); + } else { + include_once '' . $cfg['DefaultTabDatabase']; } - - include_once './libraries/header.inc.php'; - include_once './' . $cfg['DefaultTabDatabase']; } ?> diff --git a/phpMyAdmin/db_datadict.php b/phpMyAdmin/db_datadict.php index 1f62a09..f08a5c4 100644 --- a/phpMyAdmin/db_datadict.php +++ b/phpMyAdmin/db_datadict.php @@ -1,6 +1,7 @@ getHeader(); +$header->enablePrintView(); /** * Gets the relations settings */ $cfgRelation = PMA_getRelationsParam(); -require_once './libraries/transformations.lib.php'; - +require_once 'libraries/transformations.lib.php'; +require_once 'libraries/Index.class.php'; /** * Check parameters */ -PMA_checkParameters(array('db')); +PMA_Util::checkParameters(array('db')); /** * Defines the url to return to in case of error in a sql statement */ if (strlen($table)) { - $err_url = 'tbl_sql.php?' . PMA_generate_common_url($db, $table); + $err_url = 'tbl_sql.php?' . PMA_URL_getCommon($db, $table); } else { - $err_url = 'db_sql.php?' . PMA_generate_common_url($db); + $err_url = 'db_sql.php?' . PMA_URL_getCommon($db); } if ($cfgRelation['commwork']) { @@ -45,18 +49,16 @@ * Displays DB comment */ if ($comment) { - ?> -

-

- ' . __('Database comment: ') + . '' . htmlspecialchars($comment) . '

'; } // end if } /** * Selects the database and gets tables names */ -PMA_DBI_select_db($db); -$tables = PMA_DBI_get_tables($db); +$GLOBALS['dbi']->selectDb($db); +$tables = $GLOBALS['dbi']->getTables($db); $count = 0; foreach ($tables as $table) { @@ -75,8 +77,8 @@ * Gets table keys and retains them */ - PMA_DBI_select_db($db); - $indexes = PMA_DBI_get_table_indexes($db, $table); + $GLOBALS['dbi']->selectDb($db); + $indexes = $GLOBALS['dbi']->getTableIndexes($db, $table); $primary = ''; $indexes = array(); $lastIndex = ''; @@ -95,19 +97,21 @@ $indexes[] = $row['Key_name']; $lastIndex = $row['Key_name']; } - $indexes_info[$row['Key_name']]['Sequences'][] = $row['Seq_in_index']; - $indexes_info[$row['Key_name']]['Non_unique'] = $row['Non_unique']; + $indexes_info[$row['Key_name']]['Sequences'][] = $row['Seq_in_index']; + $indexes_info[$row['Key_name']]['Non_unique'] = $row['Non_unique']; if (isset($row['Cardinality'])) { $indexes_info[$row['Key_name']]['Cardinality'] = $row['Cardinality']; } // I don't know what does following column mean.... // $indexes_info[$row['Key_name']]['Packed'] = $row['Packed']; - $indexes_info[$row['Key_name']]['Comment'] = $row['Comment']; + $indexes_info[$row['Key_name']]['Comment'] = $row['Comment']; - $indexes_data[$row['Key_name']][$row['Seq_in_index']]['Column_name'] = $row['Column_name']; + $indexes_data[$row['Key_name']][$row['Seq_in_index']]['Column_name'] + = $row['Column_name']; if (isset($row['Sub_part'])) { - $indexes_data[$row['Key_name']][$row['Seq_in_index']]['Sub_part'] = $row['Sub_part']; + $indexes_data[$row['Key_name']][$row['Seq_in_index']]['Sub_part'] + = $row['Sub_part']; } } // end while @@ -115,8 +119,7 @@ /** * Gets columns properties */ - $columns = PMA_DBI_get_columns($db, $table); - $fields_cnt = count($columns); + $columns = $GLOBALS['dbi']->getColumns($db, $table); if (PMA_MYSQL_INT_VERSION < 50025) { // We need this to correctly learn if a TIMESTAMP is NOT NULL, since @@ -124,9 +127,12 @@ // and SHOW CREATE TABLE says NOT NULL // http://bugs.mysql.com/20910. - $show_create_table = PMA_DBI_fetch_value( - 'SHOW CREATE TABLE ' . PMA_backquote($db) . '.' . PMA_backquote($table), - 0, 1); + $show_create_table_query = 'SHOW CREATE TABLE ' + . PMA_Util::backquote($db) . '.' + . PMA_Util::backquote($table); + $show_create_table = $GLOBALS['dbi']->fetchValue( + $show_create_table_query, 0, 1 + ); $analyzed_sql = PMA_SQP_analyze(PMA_SQP_parse($show_create_table)); } @@ -150,22 +156,19 @@ * Displays the comments of the table if MySQL >= 3.23 */ if (!empty($show_comment)) { - echo __('Table comments') . ': ' . htmlspecialchars($show_comment) . '

'; + echo __('Table comments:') . ' '; + echo htmlspecialchars($show_comment) . '

'; } /** * Displays the table structure */ - ?> - - - - -*/ ?> - - -*/ ?> - '; + echo ''; + echo ''; + echo ''; + echo ''; if ($have_rel) { echo ' ' . "\n"; } @@ -173,26 +176,28 @@ if ($cfgRelation['mimework']) { echo ' ' . "\n"; } - ?> - - '; $odd_row = true; foreach ($columns as $row) { if ($row['Null'] == '') { $row['Null'] = 'NO'; } - $extracted_fieldspec = PMA_extractFieldSpec($row['Type']); + $extracted_columnspec + = PMA_Util::extractColumnSpec($row['Type']); + // reformat mysql query output // set or enum types: slashes single quotes inside options - if ('set' == $extracted_fieldspec['type'] || 'enum' == $extracted_fieldspec['type']) { + if ('set' == $extracted_columnspec['type'] + || 'enum' == $extracted_columnspec['type'] + ) { $type_nowrap = ''; } else { - $type_nowrap = ' nowrap="nowrap"'; + $type_nowrap = ' class="nowrap"'; } - $type = htmlspecialchars($extracted_fieldspec['print_type']); - $attribute = $extracted_fieldspec['attribute']; + $type = htmlspecialchars($extracted_columnspec['print_type']); + $attribute = $extracted_columnspec['attribute']; if (! isset($row['Default'])) { if ($row['Null'] != 'NO') { $row['Default'] = 'NULL'; @@ -200,76 +205,87 @@ } else { $row['Default'] = htmlspecialchars($row['Default']); } - $field_name = $row['Field']; + $column_name = $row['Field']; + $tmp_column = $analyzed_sql[0]['create_table_fields'][$column_name]; if (PMA_MYSQL_INT_VERSION < 50025 - && ! empty($analyzed_sql[0]['create_table_fields'][$field_name]['type']) - && $analyzed_sql[0]['create_table_fields'][$field_name]['type'] == 'TIMESTAMP' - && $analyzed_sql[0]['create_table_fields'][$field_name]['timestamp_not_null']) { - // here, we have a TIMESTAMP that SHOW FULL COLUMNS reports as having the - // NULL attribute, but SHOW CREATE TABLE says the contrary. Believe - // the latter. + && ! empty($tmp_column['type']) + && $tmp_column['type'] == 'TIMESTAMP' + && $tmp_column['timestamp_not_null'] + ) { + // here, we have a TIMESTAMP that SHOW FULL COLUMNS reports as + // having the NULL attribute, but SHOW CREATE TABLE says the + // contrary. Believe the latter. /** * @todo merge this logic with the one in tbl_structure.php - * or move it in a function similar to PMA_DBI_get_columns_full() + * or move it in a function similar to $GLOBALS['dbi']->getColumnsFull() * but based on SHOW CREATE TABLE because information_schema * cannot be trusted in this case (MySQL bug) */ $row['Null'] = 'NO'; } - ?> - - - xml:lang="en" dir="ltr"> ->*/ ?> - - ->*/ ?> - '; + echo '' . $type . ''; + echo ''; + echo ''; + if ($have_rel) { echo ' ' . "\n"; } echo ' ' . "\n"; if ($cfgRelation['mimework']) { $mime_map = PMA_getMIME($db, $table, true); echo ' ' . "\n"; } - ?> - - '; } // end foreach $count++; - ?> -
' . __('Column') . '' . __('Type') . '' . __('Null') . '' . __('Default') . '' . __('Links to') . 'MIME
- '; + echo ''; + if (isset($pk_array[$row['Field']])) { - echo '' . htmlspecialchars($field_name) . ''; + echo '' . htmlspecialchars($column_name) . ''; } else { - echo htmlspecialchars($field_name); + echo htmlspecialchars($column_name); } - ?> - '; + echo (($row['Null'] == 'NO') ? __('No') : __('Yes')); + echo ''; + if (isset($row['Default'])) { + echo $row['Default']; + } + echo ''; - if (isset($res_rel[$field_name])) { - echo htmlspecialchars($res_rel[$field_name]['foreign_table'] . ' -> ' . $res_rel[$field_name]['foreign_field']); + if (isset($res_rel[$column_name])) { + echo htmlspecialchars( + $res_rel[$column_name]['foreign_table'] + . ' -> ' + . $res_rel[$column_name]['foreign_field'] + ); } echo ''; - if (isset($comments[$field_name])) { - echo htmlspecialchars($comments[$field_name]); + if (isset($comments[$column_name])) { + echo htmlspecialchars($comments[$column_name]); } echo ''; - if (isset($mime_map[$field_name])) { - echo htmlspecialchars(str_replace('_', '/', $mime_map[$field_name]['mimetype'])); + if (isset($mime_map[$column_name])) { + echo htmlspecialchars( + str_replace('_', '/', $mime_map[$column_name]['mimetype']) + ); } echo '
- - '; + // display indexes information + if (count(PMA_Index::getFromTable($table, $db)) > 0) { + echo PMA_Index::getView($table, $db, true); + } + echo ''; } //ends main while /** * Displays the footer */ -PMA_printButton(); +echo PMA_Util::getButton(); -require './libraries/footer.inc.php'; ?> diff --git a/phpMyAdmin/db_events.php b/phpMyAdmin/db_events.php index 7716fb0..917778b 100644 --- a/phpMyAdmin/db_events.php +++ b/phpMyAdmin/db_events.php @@ -9,28 +9,18 @@ /** * Include required files */ -require_once './libraries/common.inc.php'; -require_once './libraries/common.lib.php'; - -/** - * Include JavaScript libraries - */ -$GLOBALS['js_include'][] = 'jquery/jquery-ui-1.8.16.custom.js'; -$GLOBALS['js_include'][] = 'jquery/timepicker.js'; -$GLOBALS['js_include'][] = 'rte/common.js'; -$GLOBALS['js_include'][] = 'rte/events.js'; -$GLOBALS['js_include'][] = 'codemirror/lib/codemirror.js'; -$GLOBALS['js_include'][] = 'codemirror/mode/mysql/mysql.js'; +require_once 'libraries/common.inc.php'; +require_once 'libraries/Util.class.php'; /** * Include all other files */ -require_once './libraries/rte/rte_events.lib.php'; +require_once 'libraries/rte/rte_events.lib.php'; /** * Do the magic */ $_PMA_RTE = 'EVN'; -require_once './libraries/rte/rte_main.inc.php'; +require_once 'libraries/rte/rte_main.inc.php'; ?> diff --git a/phpMyAdmin/db_export.php b/phpMyAdmin/db_export.php index 326b73a..5313e0e 100644 --- a/phpMyAdmin/db_export.php +++ b/phpMyAdmin/db_export.php @@ -9,16 +9,19 @@ /** * Gets some core libraries */ -require_once './libraries/common.inc.php'; +require_once 'libraries/common.inc.php'; -$GLOBALS['js_include'][] = 'export.js'; +$response = PMA_Response::getInstance(); +$header = $response->getHeader(); +$scripts = $header->getScripts(); +$scripts->addFile('export.js'); // $sub_part is also used in db_info.inc.php to see if we are coming from // db_export.php, in which case we don't obey $cfg['MaxTableList'] $sub_part = '_export'; -require_once './libraries/db_common.inc.php'; +require_once 'libraries/db_common.inc.php'; $url_query .= '&goto=db_export.php'; -require_once './libraries/db_info.inc.php'; +require_once 'libraries/db_info.inc.php'; /** * Displays the form @@ -28,27 +31,33 @@ // exit if no tables in db found if ($num_tables < 1) { PMA_Message::error(__('No tables found in database.'))->display(); - include './libraries/footer.inc.php'; exit; } // end if -$checkall_url = 'db_export.php?' - . PMA_generate_common_url($db) - . '&goto=db_export.php'; +$multi_values = '
'; +$multi_values .= ''; +$multi_values .= __('Select All'); +$multi_values .= ''; +$multi_values .= ' / '; +$multi_values .= ''; +$multi_values .= __('Unselect All'); +$multi_values .= '
'; -$multi_values = '
'; -$multi_values .= '' . __('Select All') . ' - / - ' . __('Unselect All') . '
'; - -$multi_values .= ''; $multi_values .= "\n"; -if (!empty($selected_tbl) && empty($table_select)) { - $table_select = $selected_tbl; +// when called by libraries/mult_submits.inc.php +if (!empty($_POST['selected_tbl']) && empty($table_select)) { + $table_select = $_POST['selected_tbl']; } -// Check if the selected tables are defined in $_GET (from clicking Back button on export.php) +// Check if the selected tables are defined in $_GET +// (from clicking Back button on export.php) if (isset($_GET['table_select'])) { $_GET['table_select'] = urldecode($_GET['table_select']); $_GET['table_select'] = explode(",", $_GET['table_select']); @@ -61,9 +70,12 @@ } else { $is_selected = ''; } - } elseif (! empty($unselectall) - || (! empty($table_select) && !in_array($each_table['Name'], $table_select))) { - $is_selected = ''; + } elseif (isset($table_select)) { + if (in_array($each_table['Name'], $table_select)) { + $is_selected = ' selected="selected"'; + } else { + $is_selected = ''; + } } else { $is_selected = ' selected="selected"'; } @@ -77,10 +89,6 @@ $multi_values .= '
'; $export_type = 'database'; -require_once './libraries/display_export.lib.php'; +require_once 'libraries/display_export.inc.php'; -/** - * Displays the footer - */ -require './libraries/footer.inc.php'; ?> diff --git a/phpMyAdmin/db_import.php b/phpMyAdmin/db_import.php index fcf56b6..70425b2 100644 --- a/phpMyAdmin/db_import.php +++ b/phpMyAdmin/db_import.php @@ -1,29 +1,25 @@ getHeader(); +$scripts = $header->getScripts(); +$scripts->addFile('import.js'); /** * Gets tables informations and displays top links */ -require './libraries/db_common.inc.php'; -require './libraries/db_info.inc.php'; +require 'libraries/db_common.inc.php'; +require 'libraries/db_info.inc.php'; $import_type = 'database'; -require './libraries/display_import.lib.php'; +require 'libraries/display_import.inc.php'; -/** - * Displays the footer - */ -require './libraries/footer.inc.php'; ?> - diff --git a/phpMyAdmin/db_operations.php b/phpMyAdmin/db_operations.php index e4c5591..6d0db19 100644 --- a/phpMyAdmin/db_operations.php +++ b/phpMyAdmin/db_operations.php @@ -15,59 +15,42 @@ /** * requirements */ -require_once './libraries/common.inc.php'; -require_once './libraries/mysql_charsets.lib.php'; +require_once 'libraries/common.inc.php'; +require_once 'libraries/mysql_charsets.inc.php'; -// add blobstreaming library functions -require_once "./libraries/blobstreaming.lib.php"; +/** + * functions implementation for this script + */ +require_once 'libraries/operations.lib.php'; // add a javascript file for jQuery functions to handle Ajax actions -// also add jQueryUI -$GLOBALS['js_include'][] = 'jquery/jquery-ui-1.8.16.custom.js'; -$GLOBALS['js_include'][] = 'db_operations.js'; +$response = PMA_Response::getInstance(); +$header = $response->getHeader(); +$scripts = $header->getScripts(); +$scripts->addFile('db_operations.js'); /** * Rename/move or copy database */ -if (strlen($db) && (! empty($db_rename) || ! empty($db_copy))) { - - if (! empty($db_rename)) { +if (strlen($db) + && (! empty($_REQUEST['db_rename']) || ! empty($_REQUEST['db_copy'])) +) { + if (! empty($_REQUEST['db_rename'])) { $move = true; } else { $move = false; } - if (! isset($newname) || ! strlen($newname)) { + if (! isset($_REQUEST['newname']) || ! strlen($_REQUEST['newname'])) { $message = PMA_Message::error(__('The database name is empty!')); } else { $sql_query = ''; // in case target db exists $_error = false; - if ($move || (isset($create_database_before_copying) && $create_database_before_copying)) { - // lower_case_table_names=1 `DB` becomes `db` - if (!PMA_DRIZZLE) { - $lower_case_table_names = PMA_DBI_fetch_value('SHOW VARIABLES LIKE "lower_case_table_names"', 0, 1); - if ($lower_case_table_names === '1') { - $newname = PMA_strtolower($newname); - } - } - - $local_query = 'CREATE DATABASE ' . PMA_backquote($newname); - if (isset($db_collation)) { - $local_query .= ' DEFAULT' . PMA_generateCharsetQueryPart($db_collation); - } - $local_query .= ';'; - $sql_query = $local_query; - // save the original db name because Tracker.class.php which - // may be called under PMA_DBI_query() changes $GLOBALS['db'] - // for some statements, one of which being CREATE DATABASE - $original_db = $db; - PMA_DBI_query($local_query); - $db = $original_db; - unset($original_db); - - // rebuild the database list because PMA_Table::moveCopy - // checks in this list if the target db exists - $GLOBALS['pma']->databases->build(); + if ($move + || (isset($_REQUEST['create_database_before_copying']) + && $_REQUEST['create_database_before_copying']) + ) { + $sql_query = PMA_getSqlQueryAndCreateDbBeforeCopy(); } // here I don't use DELIMITER because it's not part of the @@ -76,224 +59,96 @@ // to avoid selecting alternatively the current and new db // we would need to modify the CREATE definitions to qualify // the db name - $procedure_names = PMA_DBI_get_procedures_or_functions($db, 'PROCEDURE'); - if ($procedure_names) { - foreach ($procedure_names as $procedure_name) { - PMA_DBI_select_db($db); - $tmp_query = PMA_DBI_get_definition($db, 'PROCEDURE', $procedure_name); - // collect for later display - $GLOBALS['sql_query'] .= "\n" . $tmp_query; - PMA_DBI_select_db($newname); - PMA_DBI_query($tmp_query); - } - } - - $function_names = PMA_DBI_get_procedures_or_functions($db, 'FUNCTION'); - if ($function_names) { - foreach ($function_names as $function_name) { - PMA_DBI_select_db($db); - $tmp_query = PMA_DBI_get_definition($db, 'FUNCTION', $function_name); - // collect for later display - $GLOBALS['sql_query'] .= "\n" . $tmp_query; - PMA_DBI_select_db($newname); - PMA_DBI_query($tmp_query); - } - } + PMA_runProcedureAndFunctionDefinitions($db); // go back to current db, just in case - PMA_DBI_select_db($db); + $GLOBALS['dbi']->selectDb($db); - $GLOBALS['sql_constraints_query_full_db'] = array(); - - $tables_full = PMA_DBI_get_tables_full($db); - $views = array(); + $tables_full = $GLOBALS['dbi']->getTablesFull($db); + include_once "libraries/plugin_interface.lib.php"; // remove all foreign key constraints, otherwise we can get errors - include_once './libraries/export/sql.php'; - foreach ($tables_full as $each_table => $tmp) { - $sql_constraints = ''; - $sql_drop_foreign_keys = ''; - $sql_structure = PMA_getTableDef($db, $each_table, "\n", '', false, false); - if ($move && ! empty($sql_drop_foreign_keys)) { - PMA_DBI_query($sql_drop_foreign_keys); - } - // keep the constraint we just dropped - if (! empty($sql_constraints)) { - $GLOBALS['sql_constraints_query_full_db'][] = $sql_constraints; - } - } - unset($sql_constraints, $sql_drop_foreign_keys, $sql_structure); - - foreach ($tables_full as $each_table => $tmp) { - // to be able to rename a db containing views, - // first all the views are collected and a stand-in is created - // the real views are created after the tables - if (PMA_Table::isView($db, $each_table)) { - $views[] = $each_table; - // Create stand-in definition to resolve view dependencies - $sql_view_standin = PMA_getTableDefStandIn($db, $each_table, "\n"); - PMA_DBI_select_db($newname); - PMA_DBI_query($sql_view_standin); - $GLOBALS['sql_query'] .= "\n" . $sql_view_standin; - } - } + $export_sql_plugin = PMA_getPlugin( + "export", + "sql", + 'libraries/plugins/export/', + array( + 'single_table' => isset($single_table), + 'export_type' => 'database' + ) + ); + $GLOBALS['sql_constraints_query_full_db'] + = PMA_getSqlConstraintsQueryForFullDb( + $tables_full, $export_sql_plugin, $move, $db + ); - foreach ($tables_full as $each_table => $tmp) { - // skip the views; we have creted stand-in definitions - if (PMA_Table::isView($db, $each_table)) { - continue; - } - $back = $sql_query; - $sql_query = ''; - - // value of $what for this table only - $this_what = $what; - - // do not copy the data from a Merge table - // note: on the calling FORM, 'data' means 'structure and data' - if (PMA_Table::isMerge($db, $each_table)) { - if ($this_what == 'data') { - $this_what = 'structure'; - } - if ($this_what == 'dataonly') { - $this_what = 'nocopy'; - } - } + $views = PMA_getViewsAndCreateSqlViewStandIn( + $tables_full, $export_sql_plugin, $db + ); - if ($this_what != 'nocopy') { - // keep the triggers from the original db+table - // (third param is empty because delimiters are only intended - // for importing via the mysql client or our Import feature) - $triggers = PMA_DBI_get_triggers($db, $each_table, ''); - - if (! PMA_Table::moveCopy( - $db, $each_table, $newname, $each_table, - isset($this_what) ? $this_what : 'data', $move, 'db_copy') - ) { - $_error = true; - // $sql_query is filled by PMA_Table::moveCopy() - $sql_query = $back . $sql_query; - break; - } - // apply the triggers to the destination db+table - if ($triggers) { - PMA_DBI_select_db($newname); - foreach ($triggers as $trigger) { - PMA_DBI_query($trigger['create']); - $GLOBALS['sql_query'] .= "\n" . $trigger['create'] . ';'; - } - unset($trigger); - } - unset($triggers); - - // this does not apply to a rename operation - if (isset($GLOBALS['add_constraints']) && !empty($GLOBALS['sql_constraints_query'])) { - $GLOBALS['sql_constraints_query_full_db'][] = $GLOBALS['sql_constraints_query']; - unset($GLOBALS['sql_constraints_query']); - } - } - // $sql_query is filled by PMA_Table::moveCopy() - $sql_query = $back . $sql_query; - } // end (foreach) - unset($each_table); + list($sql_query, $_error) = PMA_getSqlQueryForCopyTable( + $tables_full, $sql_query, $move, $db + ); // handle the views if (! $_error) { - // temporarily force to add DROP IF EXIST to CREATE VIEW query, - // to remove stand-in VIEW that was created earlier - if (isset($GLOBALS['drop_if_exists'])) { - $temp_drop_if_exists = $GLOBALS['drop_if_exists']; - } - $GLOBALS['drop_if_exists'] = 'true'; - - foreach ($views as $view) { - if (! PMA_Table::moveCopy($db, $view, $newname, $view, 'structure', $move, 'db_copy')) { - $_error = true; - break; - } - } - unset($GLOBALS['drop_if_exists']); - if (isset($temp_drop_if_exists)) { - // restore previous value - $GLOBALS['drop_if_exists'] = $temp_drop_if_exists; - unset($temp_drop_if_exists); - } + $_error = PMA_handleTheViews($views, $move, $db); } - unset($view, $views); + unset($views); // now that all tables exist, create all the accumulated constraints if (! $_error && count($GLOBALS['sql_constraints_query_full_db']) > 0) { - PMA_DBI_select_db($newname); - foreach ($GLOBALS['sql_constraints_query_full_db'] as $one_query) { - PMA_DBI_query($one_query); - // and prepare to display them - $GLOBALS['sql_query'] .= "\n" . $one_query; - } - - unset($GLOBALS['sql_constraints_query_full_db'], $one_query); + PMA_createAllAccumulatedConstraints(); } - if (!PMA_DRIZZLE && PMA_MYSQL_INT_VERSION >= 50100) { + if (! PMA_DRIZZLE && PMA_MYSQL_INT_VERSION >= 50100) { // here DELIMITER is not used because it's not part of the // language; each statement is sent one by one - // to avoid selecting alternatively the current and new db - // we would need to modify the CREATE definitions to qualify - // the db name - $event_names = PMA_DBI_fetch_result('SELECT EVENT_NAME FROM information_schema.EVENTS WHERE EVENT_SCHEMA= \'' . PMA_sqlAddSlashes($db, true) . '\';'); - if ($event_names) { - foreach ($event_names as $event_name) { - PMA_DBI_select_db($db); - $tmp_query = PMA_DBI_get_definition($db, 'EVENT', $event_name); - // collect for later display - $GLOBALS['sql_query'] .= "\n" . $tmp_query; - PMA_DBI_select_db($newname); - PMA_DBI_query($tmp_query); - } - } + PMA_runEventDefinitionsForDb($db); } // go back to current db, just in case - PMA_DBI_select_db($db); + $GLOBALS['dbi']->selectDb($db); // Duplicate the bookmarks for this db (done once for each db) - if (! $_error && $db != $newname) { - $get_fields = array('user', 'label', 'query'); - $where_fields = array('dbase' => $db); - $new_fields = array('dbase' => $newname); - PMA_Table::duplicateInfo('bookmarkwork', 'bookmark', $get_fields, - $where_fields, $new_fields); - } + PMA_duplicateBookmarks($_error, $db); if (! $_error && $move) { /** * cleanup pmadb stuff for this db */ - include_once './libraries/relation_cleanup.lib.php'; + include_once 'libraries/relation_cleanup.lib.php'; PMA_relationsCleanupDatabase($db); // if someday the RENAME DATABASE reappears, do not DROP - $local_query = 'DROP DATABASE ' . PMA_backquote($db) . ';'; + $local_query = 'DROP DATABASE ' . PMA_Util::backquote($db) . ';'; $sql_query .= "\n" . $local_query; - PMA_DBI_query($local_query); + $GLOBALS['dbi']->query($local_query); - $message = PMA_Message::success(__('Database %s has been renamed to %s')); + $message = PMA_Message::success( + __('Database %1$s has been renamed to %2$s') + ); $message->addParam($db); - $message->addParam($newname); + $message->addParam($_REQUEST['newname']); } elseif (! $_error) { - $message = PMA_Message::success(__('Database %s has been copied to %s')); + $message = PMA_Message::success( + __('Database %1$s has been copied to %2$s') + ); $message->addParam($db); - $message->addParam($newname); + $message->addParam($_REQUEST['newname']); } $reload = true; /* Change database to be used */ if (! $_error && $move) { - $db = $newname; + $db = $_REQUEST['newname']; } elseif (! $_error) { - if (isset($switch_to_new) && $switch_to_new == 'true') { + if (isset($_REQUEST['switch_to_new']) + && $_REQUEST['switch_to_new'] == 'true' + ) { $GLOBALS['PMA_Config']->setCookie('pma_switch_to_new', 'true'); - $db = $newname; + $db = $_REQUEST['newname']; } else { $GLOBALS['PMA_Config']->setCookie('pma_switch_to_new', ''); } @@ -306,16 +161,22 @@ /** * Database has been successfully renamed/moved. If in an Ajax request, - * generate the output with {@link PMA_ajaxResponse} and exit + * generate the output with {@link PMA_Response} and exit */ - if ( $GLOBALS['is_ajax_request'] == true) { - $extra_data['newname'] = $newname; - $extra_data['sql_query'] = PMA_showMessage(null, $sql_query); - PMA_ajaxResponse($message, $message->isSuccess(), $extra_data); - }; + if ($GLOBALS['is_ajax_request'] == true) { + $response = PMA_Response::getInstance(); + $response->isSuccess($message->isSuccess()); + $response->addJSON('message', $message); + $response->addJSON('newname', $_REQUEST['newname']); + $response->addJSON( + 'sql_query', + PMA_Util::getMessage(null, $sql_query) + ); + $response->addJSON('db', $db); + exit; + } } - /** * Settings for relations stuff */ @@ -327,276 +188,113 @@ * (must be done before displaying the menu tabs) */ if (isset($_REQUEST['comment'])) { - PMA_setDbComment($db, $comment); + PMA_setDbComment($db, $_REQUEST['comment']); } -/** - * Prepares the tables list if the user where not redirected to this script - * because there is no table in the database ($is_info is true) - */ -if (empty($is_info)) { - include './libraries/db_common.inc.php'; - $url_query .= '&goto=db_operations.php'; - - // Gets the database structure - $sub_part = '_structure'; - include './libraries/db_info.inc.php'; - echo "\n"; - - if (isset($message)) { - PMA_showMessage($message, $sql_query); - unset($message); - } +require 'libraries/db_common.inc.php'; +$url_query .= '&goto=db_operations.php'; + +// Gets the database structure +$sub_part = '_structure'; +require 'libraries/db_info.inc.php'; +echo "\n"; + +if (isset($message)) { + echo PMA_Util::getMessage($message, $sql_query); + unset($message); } -$db_collation = PMA_getDbCollation($db); -$is_information_schema = PMA_is_system_schema($db); +$_REQUEST['db_collation'] = PMA_getDbCollation($db); +$is_information_schema = $GLOBALS['dbi']->isSystemSchema($db); + +$response->addHTML('
'); if (!$is_information_schema) { if ($cfgRelation['commwork']) { /** * database comment */ - ?> -
-
- -
- - '; - } - echo __('Database comment: '); - ?> - - -
-
- -
-
-
- addHTML(PMA_getHtmlForDatabaseComment($db)); } - ?> -
- -
- addHTML('
'); + ob_start(); + include 'libraries/display_create_table.lib.php'; + $content = ob_get_contents(); + ob_end_clean(); + $response->addHTML($content); + $response->addHTML('
'); + /** * rename database */ -if ($db != 'mysql') { - ?> -
-
method="post" action="db_operations.php" - onsubmit="return emptyFormElements(this, 'newname')"> - ' . "\n"; - } - ?> - - - -
- - addHTML(PMA_getHtmlForRenameDatabase($db)); } - echo __('Rename database to') . ':'; - ?> - - -
-
- -
-
-
- -
-
- - -
    - $this_sql_query, - 'back' => 'db_operations.php', - 'goto' => 'main.php', - 'reload' => '1', - 'purge' => '1', - 'message_to_show' => sprintf(__('Database %s has been dropped.'), htmlspecialchars(PMA_backquote($db))), - 'db' => null, - ); - ?> -
  • > - - -
  • -
-
-
- - addHTML(PMA_getHtmlForDropDatabaseLink($db)); + } /** * Copy database */ - ?> -
-
method="post" action="db_operations.php" - onsubmit="return emptyFormElements(this, 'newname')"> - ' . "\n"; - } - echo '' . "\n"; - echo PMA_generate_common_hidden_inputs($db); - ?> -
- - - -
- __('Structure only'), - 'data' => __('Structure and data'), - 'dataonly' => __('Data only')); - PMA_display_html_radio('what', $choices, 'data', true); - unset($choices); -?> - -
- -
- -
- -
- - - /> - -
-
- -
-
-
- addHTML(PMA_getHtmlForCopyDatabase($db)); /** * Change database charset */ - echo '
' - . PMA_generate_common_hidden_inputs($db, $table) - . '
' . "\n" - . ' '; - if ($cfg['PropertiesIconic']) { - echo PMA_getImage('s_asci.png'); - } - echo ' ' . "\n" - . ' ' . "\n" - . PMA_generateCharsetDropdownBox(PMA_CSDROPDOWN_COLLATION, - 'db_collation', 'select_db_collation', $db_collation, false, 3) - . '
' - . '
' - . ' ' . "\n" - . '
' . "\n" - . '
' . "\n"; + $response->addHTML(PMA_getHtmlForChangeDatabaseCharset($db, $table)); if ($num_tables > 0 - && ! $cfgRelation['allworks'] && $cfg['PmaNoRelation_DisableWarning'] == false) { - $message = PMA_Message::notice(__('The phpMyAdmin configuration storage has been deactivated. To find out why click %shere%s.')); - $message->addParam('', false); + && ! $cfgRelation['allworks'] + && $cfg['PmaNoRelation_DisableWarning'] == false + ) { + $message = PMA_Message::notice( + __('The phpMyAdmin configuration storage has been deactivated. To find out why click %shere%s.') + ); + $message->addParam( + '', + false + ); $message->addParam('', false); /* Show error if user has configured something, notice elsewhere */ if (!empty($cfg['Servers'][$server]['pmadb'])) { $message->isError(true); } - echo '
'; - $message->display(); - echo '
'; + $response->addHTML('
'); + $response->addHTML($message->getDisplay()); + $response->addHTML('
'); } // end if } // end if (!$is_information_schema) +$response->addHTML('
'); // not sure about displaying the PDF dialog in case db is information_schema -if ($cfgRelation['pdfwork'] && $num_tables > 0) { ?> - - - 0) { // We only show this if we find something in the new pdf_pages table - $test_query = ' SELECT * - FROM ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($cfgRelation['pdf_pages']) . ' - WHERE db_name = \'' . PMA_sqlAddSlashes($db) . '\''; - $test_rs = PMA_query_as_controluser($test_query, null, PMA_DBI_QUERY_STORE); + FROM ' . PMA_Util::backquote($GLOBALS['cfgRelation']['db']) + . '.' . PMA_Util::backquote($cfgRelation['pdf_pages']) . ' + WHERE db_name = \'' . PMA_Util::sqlAddSlashes($db) . '\''; + $test_rs = PMA_queryAsControlUser( + $test_query, + null, + PMA_DatabaseInterface::QUERY_STORE + ); /* * Export Relational Schema View */ - echo ''; + $response->addHTML(PMA_getHtmlForExportRelationalSchemaView($url_query)); } // end if -/** - * Displays the footer - */ -require './libraries/footer.inc.php'; ?> diff --git a/phpMyAdmin/db_printview.php b/phpMyAdmin/db_printview.php index 5512fa6..137bdaa 100644 --- a/phpMyAdmin/db_printview.php +++ b/phpMyAdmin/db_printview.php @@ -1,6 +1,7 @@ getHeader(); +$header->enablePrintView(); -PMA_checkParameters(array('db')); +PMA_Util::checkParameters(array('db')); /** * Defines the url to return to in case of error in a sql statement */ -$err_url = 'db_sql.php?' . PMA_generate_common_url($db); +$err_url = 'db_sql.php?' . PMA_URL_getCommon($db); /** * Settings for relations stuff */ $cfgRelation = PMA_getRelationsParam(); -/** - * Gets the list of the table in the current db and informations about these - * tables if possible - * - * @todo merge this speedup _optionaly_ into PMA_DBI_get_tables_full() - * -// speedup view on locked tables -// Special speedup for newer MySQL Versions (in 4.0 format changed) -if ($cfg['SkipLockedTables'] == true) { - $result = PMA_DBI_query('SHOW OPEN TABLES FROM ' . PMA_backquote($db) . ';'); - // Blending out tables in use - if ($result != false && PMA_DBI_num_rows($result) > 0) { - while ($tmp = PMA_DBI_fetch_row($result)) { - // if in use memorize tablename - if (preg_match('@in_use=[1-9]+@i', $tmp[0])) { - $sot_cache[$tmp[0]] = true; - } - } - PMA_DBI_free_result($result); - - if (isset($sot_cache)) { - $result = PMA_DBI_query('SHOW TABLES FROM ' . PMA_backquote($db) . ';', null, PMA_DBI_QUERY_STORE); - if ($result != false && PMA_DBI_num_rows($result) > 0) { - while ($tmp = PMA_DBI_fetch_row($result)) { - if (! isset($sot_cache[$tmp[0]])) { - $sts_result = PMA_DBI_query('SHOW TABLE STATUS FROM ' . PMA_backquote($db) . ' LIKE \'' . PMA_sqlAddSlashes($tmp[0], true) . '\';'); - $sts_tmp = PMA_DBI_fetch_assoc($sts_result); - $tables[] = $sts_tmp; - } else { // table in use - $tables[] = array('Name' => $tmp[0]); - } - } - PMA_DBI_free_result($result); - $sot_ready = true; - } - } - unset($tmp, $result); - } -} - -if (! isset($sot_ready)) { - $result = PMA_DBI_query('SHOW TABLE STATUS FROM ' . PMA_backquote($db) . ';'); - if (PMA_DBI_num_rows($result) > 0) { - while ($sts_tmp = PMA_DBI_fetch_assoc($result)) { - $tables[] = $sts_tmp; - } - PMA_DBI_free_result($result); - unset($res); - } -} - */ - /** * If there is at least one table, displays the printer friendly view, else * an error message */ -$tables = PMA_DBI_get_tables_full($db); +$tables = $GLOBALS['dbi']->getTablesFull($db); $num_tables = count($tables); echo '
'; @@ -93,76 +40,66 @@ if ($num_tables == 0) { echo __('No tables found in database.'); } else { -// 2. Shows table information - ?> - - - - - - - '; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; if ($cfg['ShowStats']) { echo ''; } - ?> - - - - - ' . __('Comments') . ''; + echo ''; + echo ''; + echo ''; $sum_entries = $sum_size = 0; $odd_row = true; foreach ($tables as $sts_data) { if (PMA_Table::isMerge($db, $sts_data['TABLE_NAME']) - || strtoupper($sts_data['ENGINE']) == 'FEDERATED') { + || strtoupper($sts_data['ENGINE']) == 'FEDERATED' + ) { $merged_size = true; } else { $merged_size = false; } $sum_entries += $sts_data['TABLE_ROWS']; - ?> - - - '; + echo ''; if (isset($sts_data['TABLE_ROWS'])) { - ?> - - - '; + echo ''; if ($cfg['ShowStats']) { $tblsize = $sts_data['Data_length'] + $sts_data['Index_length']; $sum_size += $tblsize; - list($formated_size, $unit) = PMA_formatByteDown($tblsize, 3, 1); - ?> - - '; + echo $formated_size . ' ' . $unit; + echo ''; } // end if } else { - ?> - - '; + if (! PMA_Table::isView($db, $sts_data['TABLE_NAME'])) { + echo __('in use'); + } + echo ''; } - ?> - - - '; + echo ''; } - ?> - - - - - '; + echo ''; + echo ''; + echo ''; if ($cfg['ShowStats']) { - list($sum_formated, $unit) = PMA_formatByteDown($sum_size, 3, 1); - ?> - - '; + echo $sum_formated . ' ' . $unit; + echo ''; } - ?> - - - -
' . __('Table') . '' . __('Rows') . '' . __('Type') . '' . __('Size') . '
- - '; + echo htmlspecialchars($sts_data['TABLE_NAME']); + echo ' - '; if ($merged_size) { - echo '' . PMA_formatNumber($sts_data['TABLE_ROWS'], 0) . '' . "\n"; + echo ''; + echo PMA_Util::formatNumber($sts_data['TABLE_ROWS'], 0); + echo ''; } else { - echo PMA_formatNumber($sts_data['TABLE_ROWS'], 0) . "\n"; + echo PMA_Util::formatNumber($sts_data['TABLE_ROWS'], 0); } - ?> - - - '; + echo $sts_data['ENGINE']; + echo ' - - - - - '; if (! empty($sts_data['Comment'])) { echo htmlspecialchars($sts_data['Comment']); $needs_break = '
'; @@ -171,82 +108,73 @@ } if (! empty($sts_data['Create_time']) - || ! empty($sts_data['Update_time']) - || ! empty($sts_data['Check_time'])) { + || ! empty($sts_data['Update_time']) + || ! empty($sts_data['Check_time']) + ) { echo $needs_break; - ?> - - '; if (! empty($sts_data['Create_time'])) { - ?> - - - - - '; + echo ''; + echo ''; + echo ''; } if (! empty($sts_data['Update_time'])) { - ?> - - - - - '; + echo ''; + echo ''; + echo ''; } if (! empty($sts_data['Check_time'])) { - ?> - - - - - '; + echo ''; + echo ''; + echo ''; } - ?> -
' . __('Creation:') . ''; + echo PMA_Util::localisedDate(strtotime($sts_data['Create_time'])); + echo '
' . __('Last update:') . ''; + echo PMA_Util::localisedDate(strtotime($sts_data['Update_time'])); + echo '
' . __('Last check:') . ''; + echo PMA_Util::localisedDate(strtotime($sts_data['Check_time'])); + echo '
- '; } - ?> -
- - - - - -- - '; + printf( + _ngettext('%s table', '%s tables', $num_tables), + PMA_Util::formatNumber($num_tables, 0) + ); + echo ''; + echo PMA_Util::formatNumber($sum_entries, 0); + echo ''; + echo '--'; + echo ' - -
- '; + echo ''; + echo ''; + echo ''; } /** * Displays the footer */ -PMA_printButton(); +echo PMA_Util::getButton(); echo "
\n"; - -require './libraries/footer.inc.php'; ?> diff --git a/phpMyAdmin/db_qbe.php b/phpMyAdmin/db_qbe.php index b4249bf..7fad34d 100644 --- a/phpMyAdmin/db_qbe.php +++ b/phpMyAdmin/db_qbe.php @@ -9,13 +9,15 @@ /** * requirements */ -require_once './libraries/common.inc.php'; +require_once 'libraries/common.inc.php'; +require_once 'libraries/DBQbe.class.php'; +require_once 'libraries/bookmark.lib.php'; +require_once 'libraries/sql.lib.php'; -/** - * Gets the relation settings - */ -$cfgRelation = PMA_getRelationsParam(); +$response = PMA_Response::getInstance(); +// Gets the relation settings +$cfgRelation = PMA_getRelationsParam(); /** * A query has been submitted -> (maybe) execute it @@ -26,941 +28,51 @@ $message_to_display = true; } else { $goto = 'db_sql.php'; - include './sql.php'; - exit; + + // Parse and analyze the query + include_once 'libraries/parse_analyze.inc.php'; + + PMA_executeQueryAndSendQueryResponse( + $analyzed_sql_results, false, $_REQUEST['db'], null, null, null, null, + false, null, null, null, null, $goto, $pmaThemeImage, null, null, null, + $sql_query, null, null + ); } } $sub_part = '_qbe'; -require './libraries/db_common.inc.php'; +require 'libraries/db_common.inc.php'; $url_query .= '&goto=db_qbe.php'; $url_params['goto'] = 'db_qbe.php'; -require './libraries/db_info.inc.php'; +require 'libraries/db_info.inc.php'; if ($message_to_display) { PMA_Message::error(__('You have to choose at least one column to display'))->display(); } unset($message_to_display); -/** - * Initialize some variables - */ -$col_cnt = PMA_ifSetOr($_REQUEST['col_cnt'], 3, 'numeric'); -$add_col = PMA_ifSetOr($_REQUEST['add_col'], 0, 'numeric'); -$add_row = PMA_ifSetOr($_REQUEST['add_row'], 0, 'numeric'); - -$rows = PMA_ifSetOr($_REQUEST['rows'], 0, 'numeric'); -$ins_col = PMA_ifSetOr($_REQUEST['ins_col'], null, 'array'); -$del_col = PMA_ifSetOr($_REQUEST['del_col'], null, 'array'); - -$prev_criteria = isset($_REQUEST['prev_criteria']) - ? $_REQUEST['prev_criteria'] - : array(); -$criteria = isset($_REQUEST['criteria']) - ? $_REQUEST['criteria'] - : array_fill(0, $col_cnt, ''); - -$ins_row = isset($_REQUEST['ins_row']) - ? $_REQUEST['ins_row'] - : array_fill(0, $col_cnt, ''); -$del_row = isset($_REQUEST['del_row']) - ? $_REQUEST['del_row'] - : array_fill(0, $col_cnt, ''); -$and_or_row = isset($_REQUEST['and_or_row']) - ? $_REQUEST['and_or_row'] - : array_fill(0, $col_cnt, ''); -$and_or_col = isset($_REQUEST['and_or_col']) - ? $_REQUEST['and_or_col'] - : array_fill(0, $col_cnt, ''); - -// minimum width -$form_column_width = 12; -$col = max($col_cnt + $add_col, 0); -$row = max($rows + $add_row, 0); - - -// The tables list sent by a previously submitted form -if (PMA_isValid($_REQUEST['TableList'], 'array')) { - foreach ($_REQUEST['TableList'] as $each_table) { - $tbl_names[$each_table] = ' selected="selected"'; - } -} // end if - - -// this was a work in progress, deactivated for now -//$columns = PMA_DBI_get_columns_full($GLOBALS['db']); -//$tables = PMA_DBI_get_columns_full($GLOBALS['db']); - - -/** - * Prepares the form - */ -$tbl_result = PMA_DBI_query('SHOW TABLES FROM ' . PMA_backquote($db) . ';', null, PMA_DBI_QUERY_STORE); -$tbl_result_cnt = PMA_DBI_num_rows($tbl_result); -if (0 == $tbl_result_cnt) { - PMA_Message::error(__('No tables found in database.'))->display(); - include './libraries/footer.inc.php'; - exit; -} - -// The tables list gets from MySQL -while (list($tbl) = PMA_DBI_fetch_row($tbl_result)) { - $fld_results = PMA_DBI_get_columns($db, $tbl); - - if (empty($tbl_names[$tbl]) && !empty($_REQUEST['TableList'])) { - $tbl_names[$tbl] = ''; - } else { - $tbl_names[$tbl] = ' selected="selected"'; - } // end if - - // The fields list per selected tables - if ($tbl_names[$tbl] == ' selected="selected"') { - $each_table = PMA_backquote($tbl); - $fld[] = $each_table . '.*'; - foreach ($fld_results as $each_field) { - $each_field = $each_table . '.' . PMA_backquote($each_field['Field']); - $fld[] = $each_field; - - // increase the width if necessary - $form_column_width = max(strlen($each_field), $form_column_width); - } // end foreach - } // end if -} // end while -PMA_DBI_free_result($tbl_result); - -// largest width found -$realwidth = $form_column_width . 'ex'; - +// create new qbe search instance +$db_qbe = new PMA_DBQbe($GLOBALS['db']); /** * Displays the Query by example form */ - -/** - * Enter description here... - * - * @param array $columns - * @param integer $column_number - * @param string $selected - */ -function showColumnSelectCell($columns, $column_number, $selected = '') -{ - ?> - - - - - $value) { - $tab_designer['link'] .= PMA_get_arg_separator('html') . urlencode($param) . '=' - . urlencode($value); - } - } - } - if (! empty($tab['fragment'])) { - $tab['link'] .= $tab['fragment']; - } - if (isset($tab_designer['link'])) { -?> -
- -', ''); ?> - -
- -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
:
: - - - -
: - - - /> -
: - - - - -
- - - - - - - - - - - - -
- : - - - : - - /> -   -
- : - - - : - - /> -   -
-
- - - -
- - - - - - - - - - - - -
- : - - - : - - /> -
- : - - - : - - /> -
-
- - - -
: - : - /> -   : - /> -
- - -    - -
- : - /> -   : - /> -
- - -    - -
- - - -
-
- - - - - - - - - -
- : - -  : - -  
-
- - - - - - -
-
- - $val) { - $options .= ' '; - $options .= '' . "\n"; - $numTableListOptions++; -} -?> - -
-
- -
-
  -
- %s:'), PMA_getDbLink($db)); ?> - - -
-
- -
-
-
-addHTML($db_qbe->getSelectionForm($cfgRelation)); ?> diff --git a/phpMyAdmin/db_routines.php b/phpMyAdmin/db_routines.php index 1d4ee0c..a58d4c0 100644 --- a/phpMyAdmin/db_routines.php +++ b/phpMyAdmin/db_routines.php @@ -9,34 +9,19 @@ /** * Include required files */ -require_once './libraries/common.inc.php'; -require_once './libraries/common.lib.php'; -require_once './libraries/mysql_charsets.lib.php'; -if (PMA_DRIZZLE) { - include_once './libraries/data_drizzle.inc.php'; -} else { - include_once './libraries/data_mysql.inc.php'; -} - -/** - * Include JavaScript libraries - */ -$GLOBALS['js_include'][] = 'jquery/jquery-ui-1.8.16.custom.js'; -$GLOBALS['js_include'][] = 'jquery/timepicker.js'; -$GLOBALS['js_include'][] = 'rte/common.js'; -$GLOBALS['js_include'][] = 'rte/routines.js'; -$GLOBALS['js_include'][] = 'codemirror/lib/codemirror.js'; -$GLOBALS['js_include'][] = 'codemirror/mode/mysql/mysql.js'; +require_once 'libraries/common.inc.php'; +require_once 'libraries/Util.class.php'; +require_once 'libraries/mysql_charsets.inc.php'; /** * Include all other files */ -require_once './libraries/rte/rte_routines.lib.php'; +require_once 'libraries/rte/rte_routines.lib.php'; /** * Do the magic */ $_PMA_RTE = 'RTN'; -require_once './libraries/rte/rte_main.inc.php'; +require_once 'libraries/rte/rte_main.inc.php'; ?> diff --git a/phpMyAdmin/db_search.php b/phpMyAdmin/db_search.php index 68cb463..acfec8e 100644 --- a/phpMyAdmin/db_search.php +++ b/phpMyAdmin/db_search.php @@ -9,353 +9,49 @@ */ /** - * + * Gets some core libraries */ -require_once './libraries/common.inc.php'; +require_once 'libraries/common.inc.php'; +require_once 'libraries/DbSearch.class.php'; -$GLOBALS['js_include'][] = 'db_search.js'; -$GLOBALS['js_include'][] = 'sql.js'; -$GLOBALS['js_include'][] = 'makegrid.js'; -$GLOBALS['js_include'][] = 'jquery/timepicker.js'; +$response = PMA_Response::getInstance(); +$header = $response->getHeader(); +$scripts = $header->getScripts(); +$scripts->addFile('db_search.js'); +$scripts->addFile('sql.js'); +$scripts->addFile('makegrid.js'); +$scripts->addFile('jquery/jquery-ui-timepicker-addon.js'); -/** - * Gets some core libraries and send headers - */ -require './libraries/db_common.inc.php'; +require 'libraries/db_common.inc.php'; -/** - * init - */ // If config variable $GLOBALS['cfg']['Usedbsearch'] is on false : exit. if (! $GLOBALS['cfg']['UseDbSearch']) { - PMA_mysqlDie(__('Access denied'), '', false, $err_url); + PMA_Util::mysqlDie( + __('Access denied'), '', false, $err_url + ); } // end if $url_query .= '&goto=db_search.php'; $url_params['goto'] = 'db_search.php'; -/** - * @global array list of tables from the current database - * but do not clash with $tables coming from db_info.inc.php - */ -$tables_names_only = PMA_DBI_get_tables($GLOBALS['db']); - -$search_options = array( - '1' => __('at least one of the words'), - '2' => __('all words'), - '3' => __('the exact phrase'), - '4' => __('as regular expression'), -); - -if (empty($_REQUEST['search_option']) || ! is_string($_REQUEST['search_option']) - || ! array_key_exists($_REQUEST['search_option'], $search_options)) { - $search_option = 1; - unset($_REQUEST['submit_search']); -} else { - $search_option = (int) $_REQUEST['search_option']; - $option_str = $search_options[$_REQUEST['search_option']]; -} - -if (empty($_REQUEST['search_str']) || ! is_string($_REQUEST['search_str'])) { - unset($_REQUEST['submit_search']); - $searched = ''; -} else { - $searched = htmlspecialchars($_REQUEST['search_str']); - // For "as regular expression" (search option 4), we should not treat - // this as an expression that contains a LIKE (second parameter of - // PMA_sqlAddSlashes()). - // - // Usage example: If user is seaching for a literal $ in a regexp search, - // he should enter \$ as the value. - $search_str = PMA_sqlAddSlashes($_REQUEST['search_str'], ($search_option == 4 ? false : true)); -} - -$tables_selected = array(); -if (empty($_REQUEST['table_select']) || ! is_array($_REQUEST['table_select'])) { - unset($_REQUEST['submit_search']); -} elseif (! isset($_REQUEST['selectall']) && ! isset($_REQUEST['unselectall'])) { - $tables_selected = array_intersect($_REQUEST['table_select'], $tables_names_only); -} - -if (isset($_REQUEST['selectall'])) { - $tables_selected = $tables_names_only; -} elseif (isset($_REQUEST['unselectall'])) { - $tables_selected = array(); -} - -if (empty($_REQUEST['field_str']) || ! is_string($_REQUEST['field_str'])) { - unset($field_str); -} else { - $field_str = PMA_sqlAddSlashes($_REQUEST['field_str'], true); -} - -/** - * Displays top links if we are not in an Ajax request - */ -$sub_part = ''; +// Create a database search instance +$db_search = new PMA_DbSearch($GLOBALS['db']); +// Display top links if we are not in an Ajax request if ( $GLOBALS['is_ajax_request'] != true) { - include './libraries/db_info.inc.php'; - echo '
'; + include 'libraries/db_info.inc.php'; } +$response->addHTML('
'); -/** - * 1. Main search form has been submitted - */ +// Main search form has been submitted, get results if (isset($_REQUEST['submit_search'])) { + $response->addHTML($db_search->getSearchResults()); +} - /** - * Builds the SQL search query - * - * @todo can we make use of fulltextsearch IN BOOLEAN MODE for this? - * PMA_backquote - * PMA_DBI_free_result - * PMA_DBI_fetch_assoc - * $GLOBALS['db'] - * explode - * count - * strlen - * @param string the table name - * @param string restrict the search to this field - * @param string the string to search - * @param integer type of search (1 -> 1 word at least, 2 -> all words, - * 3 -> exact string, 4 -> regexp) - * - * @return array 3 SQL querys (for count, display and delete results) - */ - function PMA_getSearchSqls($table, $field, $search_str, $search_option) - { - // Statement types - $sqlstr_select = 'SELECT'; - $sqlstr_delete = 'DELETE'; - - // Fields to select - $tblfields = PMA_DBI_get_columns($GLOBALS['db'], $table); - - // Table to use - $sqlstr_from = ' FROM ' . PMA_backquote($GLOBALS['db']) . '.' . PMA_backquote($table); - - $search_words = (($search_option > 2) ? array($search_str) : explode(' ', $search_str)); - - $like_or_regex = (($search_option == 4) ? 'REGEXP' : 'LIKE'); - $automatic_wildcard = (($search_option < 3) ? '%' : ''); - - $fieldslikevalues = array(); - foreach ($search_words as $search_word) { - // Eliminates empty values - if (strlen($search_word) === 0) { - continue; - } - - $thefieldlikevalue = array(); - foreach ($tblfields as $tblfield) { - if (! isset($field) || strlen($field) == 0 || $tblfield['Field'] == $field) { - // Drizzle has no CONVERT and all text columns are UTF-8 - if (PMA_DRIZZLE) { - $thefieldlikevalue[] = PMA_backquote($tblfield['Field']) - . ' ' . $like_or_regex . ' ' - . "'" . $automatic_wildcard - . $search_word - . $automatic_wildcard . "'"; - } else { - $thefieldlikevalue[] = 'CONVERT(' . PMA_backquote($tblfield['Field']) . ' USING utf8)' - . ' ' . $like_or_regex . ' ' - . "'" . $automatic_wildcard - . $search_word - . $automatic_wildcard . "'"; - } - } - } // end for - - if (count($thefieldlikevalue) > 0) { - $fieldslikevalues[] = implode(' OR ', $thefieldlikevalue); - } - } // end for - - $implode_str = ($search_option == 1 ? ' OR ' : ' AND '); - if ( empty($fieldslikevalues)) { - // this could happen when the "inside field" does not exist - // in any selected tables - $sqlstr_where = ' WHERE FALSE'; - } else { - $sqlstr_where = ' WHERE (' . implode(') ' . $implode_str . ' (', $fieldslikevalues) . ')'; - } - unset($fieldslikevalues); - - // Builds complete queries - $sql['select_fields'] = $sqlstr_select . ' * ' . $sqlstr_from . $sqlstr_where; - // here, I think we need to still use the COUNT clause, even for - // VIEWs, anyway we have a WHERE clause that should limit results - $sql['select_count'] = $sqlstr_select . ' COUNT(*) AS `count`' . $sqlstr_from . $sqlstr_where; - $sql['delete'] = $sqlstr_delete . $sqlstr_from . $sqlstr_where; - - return $sql; - } // end of the "PMA_getSearchSqls()" function - - - /** - * Displays the results - */ - $this_url_params = array( - 'db' => $GLOBALS['db'], - 'goto' => 'db_sql.php', - 'pos' => 0, - 'is_js_confirmed' => 0, - ); - - // Displays search string - echo '
' . "\n" - .'' . "\n" - .'' . "\n"; - - $num_search_result_total = 0; - $odd_row = true; - - foreach ($tables_selected as $each_table) { - // Gets the SQL statements - $newsearchsqls = PMA_getSearchSqls($each_table, (! empty($field_str) ? $field_str : ''), $search_str, $search_option); - - // Executes the "COUNT" statement - $res_cnt = PMA_DBI_fetch_value($newsearchsqls['select_count']); - $num_search_result_total += $res_cnt; - - $sql_query .= $newsearchsqls['select_count']; - - echo '' - .'\n"; - - if ($res_cnt > 0) { - $this_url_params['sql_query'] = $newsearchsqls['select_fields']; - $browse_result_path = 'sql.php' . PMA_generate_common_url($this_url_params); - ?> - - - -  ' . "\n" - .'' . "\n"; - }// end if else - $odd_row = ! $odd_row; - echo '' . "\n"; - } // end for - - echo '
' . "\n" - .sprintf(__('Search results for "%s" %s:'), - $searched, $option_str) . "\n" - .'
' . sprintf(_ngettext('%s match inside table %s', '%s matches inside table %s', $res_cnt), $res_cnt, - htmlspecialchars($each_table)) . "  
' . "\n"; - - if (count($tables_selected) > 1) { - echo '

' . sprintf(_ngettext('Total: %s match', 'Total: %s matches', $num_search_result_total), - $num_search_result_total) . '

' . "\n"; - } -} // end 1. - -/** - * If we are in an Ajax request, we need to exit after displaying all the HTML - */ -if ($GLOBALS['is_ajax_request'] == true) { +// If we are in an Ajax request, we need to exit after displaying all the HTML +if ($GLOBALS['is_ajax_request'] == true && empty($_REQUEST['ajax_page_request'])) { exit; -} else { - echo '
';//end searchresults div } -/** - * 2. Displays the main search form - */ -?> - -
method="post" action="db_search.php" name="db_search"> - -
- - - - - - - - - - - - - - - - - -
- __('at least one of the words') . PMA_showHint(__('Words are separated by a space character (" ").')), - '2' => __('all words') . PMA_showHint(__('Words are separated by a space character (" ").')), - '3' => __('the exact phrase'), - '4' => __('as regular expression') . ' ' . PMA_showMySQLDocu('Regexp', 'Regexp') -); -// 4th parameter set to true to add line breaks -// 5th parameter set to false to avoid htmlspecialchars() escaping in the label -// since we have some HTML in some labels -PMA_display_html_radio('search_option', $choices, $search_option, true, false); -unset($choices); - ?> -
- -' . "\n"; -foreach ($tables_names_only as $each_table) { - if (in_array($each_table, $tables_selected)) { - $is_selected = ' selected="selected"'; - } else { - $is_selected = ''; - } - - echo ' ' . "\n"; -} // end while - -echo ' ' . "\n"; -$alter_select - = '' . __('Select All') . '' - . ' / ' - . '' . __('Unselect All') . ''; -?> -
-
-
-
-
- -
-
- - -
- -
-
- -
-
-
- -
- - - -addHTML($db_search->getSelectionForm($url_params)); ?> diff --git a/phpMyAdmin/db_sql.php b/phpMyAdmin/db_sql.php index 9b4e74d..67bbbb5 100644 --- a/phpMyAdmin/db_sql.php +++ b/phpMyAdmin/db_sql.php @@ -1,6 +1,7 @@ getHeader(); +$scripts = $header->getScripts(); +$scripts->addFile('functions.js'); +$scripts->addFile('makegrid.js'); +$scripts->addFile('sql.js'); -require './libraries/db_common.inc.php'; -require_once './libraries/sql_query_form.lib.php'; +require 'libraries/db_common.inc.php'; +require_once 'libraries/sql_query_form.lib.php'; // After a syntax error, we return to this script // with the typed query in the textarea. $goto = 'db_sql.php'; $back = 'db_sql.php'; -/** - * Gets informations about the database and, if it is empty, move to the - * "db_structure.php" script where table can be created - */ -require './libraries/db_info.inc.php'; -if ($num_tables == 0 && empty($db_query_force)) { - $sub_part = ''; - $is_info = true; - include './db_structure.php'; - exit(); -} - /** * Query box, bookmark, insert data from textfile */ -PMA_sqlQueryForm(true, false, isset($_REQUEST['delimiter']) ? htmlspecialchars($_REQUEST['delimiter']) : ';'); +$response->addHTML( + PMA_getHtmlForSqlQueryForm( + true, false, + isset($_REQUEST['delimiter']) + ? htmlspecialchars($_REQUEST['delimiter']) + : ';' + ) +); -/** - * Displays the footer - */ -require './libraries/footer.inc.php'; ?> diff --git a/phpMyAdmin/db_structure.php b/phpMyAdmin/db_structure.php index 43fa401..0eed9ad 100644 --- a/phpMyAdmin/db_structure.php +++ b/phpMyAdmin/db_structure.php @@ -1,6 +1,7 @@ libraries/mult_submits.inc.php -> sql.php - // -> db_structure.php and if we got an error on the multi submit, - // we must display it here and not call again mult_submits.inc.php - if (! isset($error) || false === $error) { - include './libraries/mult_submits.inc.php'; - } - if (empty($message)) { - $message = PMA_Message::success(); - } +require_once 'libraries/structure.lib.php'; + +$response = PMA_Response::getInstance(); +$header = $response->getHeader(); +$scripts = $header->getScripts(); +$scripts->addFile('db_structure.js'); +$scripts->addFile('tbl_change.js'); +$scripts->addFile('jquery/jquery-ui-timepicker-addon.js'); + +// Drops/deletes/etc. multiple tables if required +if ((!empty($_POST['submit_mult']) && isset($_POST['selected_tbl'])) + || isset($_POST['mult_btn']) +) { + $action = 'db_structure.php'; + $err_url = 'db_structure.php?'. PMA_URL_getCommon($db); + + // see bug #2794840; in this case, code path is: + // db_structure.php -> libraries/mult_submits.inc.php -> sql.php + // -> db_structure.php and if we got an error on the multi submit, + // we must display it here and not call again mult_submits.inc.php + if (! isset($_POST['error']) || false === $_POST['error']) { + include 'libraries/mult_submits.inc.php'; } - include './libraries/db_common.inc.php'; - $url_query .= '&goto=db_structure.php'; + if (empty($_POST['message'])) { + $_POST['message'] = PMA_Message::success(); + } +} +require 'libraries/db_common.inc.php'; +$url_query .= '&goto=db_structure.php'; - // Gets the database structure - $sub_part = '_structure'; - include './libraries/db_info.inc.php'; +// Gets the database structure +$sub_part = '_structure'; +require 'libraries/db_info.inc.php'; - if (!PMA_DRIZZLE) { - include_once './libraries/replication.inc.php'; - } else { - $server_slave_status = false; - } +if (!PMA_DRIZZLE) { + include_once 'libraries/replication.inc.php'; +} else { + $server_slave_status = false; } -require_once './libraries/bookmark.lib.php'; +require_once 'libraries/bookmark.lib.php'; -require_once './libraries/mysql_charsets.lib.php'; +require_once 'libraries/mysql_charsets.inc.php'; $db_collation = PMA_getDbCollation($db); -// in a separate file to avoid redeclaration of functions in some code paths -require_once './libraries/db_structure.lib.php'; -$titles = PMA_buildActionTitles(); +$titles = PMA_Util::buildActionTitles(); // 1. No tables if ($num_tables == 0) { - echo '

' . __('No tables found in database') . '

' . "\n"; - + $response->addHTML( + '

' . __('No tables found in database.') . '

' . "\n" + ); if (empty($db_is_information_schema)) { - include './libraries/display_create_table.lib.php'; + ob_start(); + include 'libraries/display_create_table.lib.php'; + $content = ob_get_contents(); + ob_end_clean(); + $response->addHTML($content); + unset($content); } // end if (Create Table dialog) - - /** - * Displays the footer - */ - include_once './libraries/footer.inc.php'; exit; } @@ -84,7 +84,7 @@ /** * Displays the tables list */ -echo '
'; +$response->addHTML('
'); $_url_params = array( 'pos' => $pos, 'db' => $db); @@ -98,176 +98,119 @@ $_url_params['sort_order'] = $_REQUEST['sort_order']; } -PMA_listNavigator( - $total_num_tables, $pos, $_url_params, 'db_structure.php', - 'frame_content', $GLOBALS['cfg']['MaxTableList'] +$response->addHTML( + PMA_Util::getListNavigator( + $total_num_tables, $pos, $_url_params, 'db_structure.php', + 'frame_content', $GLOBALS['cfg']['MaxTableList'] + ) ); -?> -
-addHTML( + '' +); + +$response->addHTML(PMA_URL_getHiddenInputs($db)); -PMA_TableHeader($db_is_information_schema, $server_slave_status); +$response->addHTML( + PMA_tableHeader($db_is_information_schema, $server_slave_status) +); $i = $sum_entries = 0; -$sum_size = (double) 0; -$overhead_size = (double) 0; $overhead_check = ''; -$checked = !empty($checkall) ? ' checked="checked"' : ''; +$create_time_all = ''; +$update_time_all = ''; +$check_time_all = ''; $num_columns = $cfg['PropertiesNumColumns'] > 1 ? ceil($num_tables / $cfg['PropertiesNumColumns']) + 1 : 0; $row_count = 0; - +$sum_size = (double) 0; +$overhead_size = (double) 0; $hidden_fields = array(); $odd_row = true; $sum_row_count_pre = ''; -$tableReductionCount = 0; // the amount to reduce the table count by - -foreach ($tables as $keyname => $each_table) { - if (PMA_BS_IsHiddenTable($keyname)) { - $tableReductionCount++; - continue; - } - +foreach ($tables as $keyname => $current_table) { // Get valid statistics whatever is the table type + $drop_query = ''; + $drop_message = ''; + $overhead = ''; + $table_is_view = false; - $table_encoded = urlencode($each_table['TABLE_NAME']); + $table_encoded = urlencode($current_table['TABLE_NAME']); // Sets parameters for links $tbl_url_query = $url_query . '&table=' . $table_encoded; // do not list the previous table's size info for a view - $formatted_size = '-'; - $unit = ''; - - switch ( $each_table['ENGINE']) { - // MyISAM, ISAM or Heap table: Row count, data size and index size - // are accurate; data size is accurate for ARCHIVE - case 'MyISAM' : - case 'ISAM' : - case 'HEAP' : - case 'MEMORY' : - case 'ARCHIVE' : - case 'Aria' : - case 'Maria' : - if ($db_is_information_schema) { - $each_table['Rows'] = PMA_Table::countRecords( - $db, $each_table['Name'] - ); - } - - if ($is_show_stats) { - $tblsize = doubleval($each_table['Data_length']) + doubleval($each_table['Index_length']); - $sum_size += $tblsize; - list($formatted_size, $unit) = PMA_formatByteDown($tblsize, 3, ($tblsize > 0) ? 1 : 0); - if (isset($each_table['Data_free']) && $each_table['Data_free'] > 0) { - list($formatted_overhead, $overhead_unit) = PMA_formatByteDown($each_table['Data_free'], 3, ($each_table['Data_free'] > 0) ? 1 : 0); - $overhead_size += $each_table['Data_free']; - } - } - break; - case 'InnoDB' : - case 'PBMS' : - // InnoDB table: Row count is not accurate but data and index sizes are. - // PBMS table in Drizzle: TABLE_ROWS is taken from table cache, so it may be unavailable - - if (($each_table['ENGINE'] == 'InnoDB' - && $each_table['TABLE_ROWS'] < $GLOBALS['cfg']['MaxExactCount']) - || !isset($each_table['TABLE_ROWS']) - ) { - $each_table['COUNTED'] = true; - $each_table['TABLE_ROWS'] = PMA_Table::countRecords( - $db, $each_table['TABLE_NAME'], - $force_exact = true, $is_view = false - ); - } else { - $each_table['COUNTED'] = false; - } - // Drizzle doesn't provide data and index length, check for null - if ($is_show_stats && $each_table['Data_length'] !== null) { - $tblsize = $each_table['Data_length'] + $each_table['Index_length']; - $sum_size += $tblsize; - list($formatted_size, $unit) = PMA_formatByteDown($tblsize, 3, ($tblsize > 0) ? 1 : 0); - } - //$display_rows = ' - '; - break; - // Mysql 5.0.x (and lower) uses MRG_MyISAM and MySQL 5.1.x (and higher) uses MRG_MYISAM - // Both are aliases for MERGE - case 'MRG_MyISAM' : - case 'MRG_MYISAM' : - case 'MERGE' : - case 'BerkeleyDB' : - // Merge or BerkleyDB table: Only row count is accurate. - if ($is_show_stats) { - $formatted_size = ' - '; - $unit = ''; - } - break; - // for a view, the ENGINE is sometimes reported as null, - // or on some servers it's reported as "SYSTEM VIEW" - case null : - case 'SYSTEM VIEW' : - case 'FunctionEngine' : - // if table is broken, Engine is reported as null, so one more test - if ($each_table['TABLE_TYPE'] == 'VIEW') { - // countRecords() takes care of $cfg['MaxExactCountViews'] - $each_table['TABLE_ROWS'] = PMA_Table::countRecords( - $db, $each_table['TABLE_NAME'], - $force_exact = true, $is_view = true + list($current_table, $formatted_size, $unit, $formatted_overhead, + $overhead_unit, $overhead_size, $table_is_view, $sum_size) + = PMA_getStuffForEngineTypeTable( + $current_table, $db_is_information_schema, + $is_show_stats, $table_is_view, $sum_size, $overhead_size ); - $table_is_view = true; - } - break; - default : - // Unknown table type. - if ($is_show_stats) { - $formatted_size = __('unknown'); - $unit = ''; - } - } // end switch - if (! PMA_Table::isMerge($db, $each_table['TABLE_NAME'])) { - $sum_entries += $each_table['TABLE_ROWS']; + if (! PMA_Table::isMerge($db, $current_table['TABLE_NAME'])) { + $sum_entries += $current_table['TABLE_ROWS']; } - if (isset($each_table['Collation'])) { + if (isset($current_table['Collation'])) { $collation = '' - . $each_table['Collation'] . ''; + . PMA_getCollationDescr($current_table['Collation']) . '">' + . $current_table['Collation'] . ''; } else { $collation = '---'; } if ($is_show_stats) { - if (isset($formatted_overhead)) { + if ($formatted_overhead != '') { $overhead = '' . $formatted_overhead - . ' ' . $overhead_unit . '' . "\n"; - unset($formatted_overhead); + . $tbl_url_query . '#showusage">' + . '' . $formatted_overhead . '' + . '' . $overhead_unit . '' + . '' . "\n"; $overhead_check .= - "document.getElementById('checkbox_tbl_" . ($i + 1) . "').checked = true;"; + "markAllRows('row_tbl_" . ($i + 1) . "');"; } else { $overhead = '-'; } } // end if - $alias = (!empty($tooltip_aliasname) && isset($tooltip_aliasname[$each_table['TABLE_NAME']])) - ? str_replace(' ', ' ', htmlspecialchars($tooltip_truename[$each_table['TABLE_NAME']])) - : str_replace(' ', ' ', htmlspecialchars($each_table['TABLE_NAME'])); - $truename = (!empty($tooltip_truename) && isset($tooltip_truename[$each_table['TABLE_NAME']])) - ? str_replace(' ', ' ', htmlspecialchars($tooltip_truename[$each_table['TABLE_NAME']])) - : str_replace(' ', ' ', htmlspecialchars($each_table['TABLE_NAME'])); + unset($showtable); + + if ($GLOBALS['cfg']['ShowDbStructureCreation']) { + list($create_time, $create_time_all) = PMA_getTimeForCreateUpdateCheck( + $current_table, 'Create_time', $create_time_all + ); + } + + if ($GLOBALS['cfg']['ShowDbStructureLastUpdate']) { + // $showtable might already be set from ShowDbStructureCreation, see above + list($update_time, $update_time_all) = PMA_getTimeForCreateUpdateCheck( + $current_table, 'Update_time', $update_time_all + ); + } + + if ($GLOBALS['cfg']['ShowDbStructureLastCheck']) { + // $showtable might already be set from ShowDbStructureCreation, see above + list($check_time, $check_time_all) = PMA_getTimeForCreateUpdateCheck( + $current_table, 'Check_time', $check_time_all + ); + } + + list($alias, $truename) = PMA_getAliasAndTrueName( + $tooltip_aliasname, $current_table, $tooltip_truename + ); $i++; $row_count++; if ($table_is_view) { $hidden_fields[] = ''; + . htmlspecialchars($current_table['TABLE_NAME']) . '" />'; } /* @@ -280,69 +223,15 @@ * I could have used the PHP ternary conditional operator but I find * the code easier to read without this operator. */ - if ($each_table['TABLE_ROWS'] > 0 || $table_is_view) { - $may_have_rows = true; - } else { - $may_have_rows = false; - } - $browse_table = ''; - if ($may_have_rows) { - $browse_table .= $titles['Browse']; - } else { - $browse_table .= $titles['NoBrowse']; - } - $browse_table .= ''; - - $search_table = ''; - if ($may_have_rows) { - $search_table .= $titles['Search']; - } else { - $search_table .= $titles['NoSearch']; - } - $search_table .= ''; - - $browse_table_label = '' . $truename . ''; - - if (! $db_is_information_schema) { - $empty_table = ''; - if ($may_have_rows) { - $empty_table .= $titles['Empty']; - } else { - $empty_table .= $titles['NoEmpty']; - } - $empty_table .= ''; - - $drop_query = 'DROP ' - . (($table_is_view || $each_table['ENGINE'] == null) ? 'VIEW' : 'TABLE') - . ' ' . PMA_backquote($each_table['TABLE_NAME']); - $drop_message = sprintf( - ($table_is_view || $each_table['ENGINE'] == null)? __('View %s has been dropped') : __('Table %s has been dropped'), - str_replace(' ', ' ', htmlspecialchars($each_table['TABLE_NAME'])) + list($browse_table, $search_table, $browse_table_label, $empty_table, + $tracking_icon) = PMA_getHtmlForActionLinks( + $current_table, $table_is_view, $tbl_url_query, + $titles, $truename, $db_is_information_schema, $url_query ); - } - $tracking_icon = ''; - if (PMA_Tracker::isActive()) { - if (PMA_Tracker::isTracked($GLOBALS["db"], $truename)) { - $tracking_icon = '' - . PMA_getImage('eye.png', __('Tracking is active.')) - . ''; - } elseif (PMA_Tracker::getVersion($GLOBALS["db"], $truename) > 0) { - $tracking_icon = '' - . PMA_getImage('eye.png', __('Tracking is not active.')) - . ''; - } + if (! $db_is_information_schema) { + list($drop_query, $drop_message) + = PMA_getTableDropQueryAndMessage($table_is_view, $current_table); } if ($num_columns > 0 @@ -351,313 +240,78 @@ ) { $row_count = 1; $odd_row = true; - ?> - - - - addHTML( + '' + ); - if ((strlen(array_search($truename, $server_slave_Do_Table)) > 0) - || (strlen(array_search($db, $server_slave_Do_DB)) > 0) - || (count($server_slave_Do_DB) == 1 && count($server_slave_Ignore_DB) == 1) - ) { - $do = true; - } - foreach ($server_slave_Wild_Do_Table as $db_table) { - $table_part = PMA_extract_db_or_table($db_table, 'table'); - if (($db == PMA_extract_db_or_table($db_table, 'db')) - && (preg_match("@^" . substr($table_part, 0, strlen($table_part) - 1) . "@", $truename)) - ) { - $do = true; - } - } - //////////////////////////////////////////////////////////////////// - if ((strlen(array_search($truename, $server_slave_Ignore_Table)) > 0) - || (strlen(array_search($db, $server_slave_Ignore_DB)) > 0) - ) { - $ignored = true; - } - foreach ($server_slave_Wild_Ignore_Table as $db_table) { - $table_part = PMA_extract_db_or_table($db_table, 'table'); - if (($db == PMA_extract_db_or_table($db_table)) - && (preg_match("@^" . substr($table_part, 0, strlen($table_part) - 1) . "@", $truename)) - ) { - $ignored = true; - } - } - unset($table_part); + $response->addHTML(PMA_tableHeader(false, $server_slave_status)); } - ?> - - - /> - - - - - - - - - - - - href="tbl_change.php?"> - - - - href="sql.php?&reload=1&purge=1&sql_query=&message_to_show=" > - - = $GLOBALS['cfg']['MaxExactCountViews'] - && $each_table['ENGINE'] != 'FunctionEngine' - ) { - $row_count_pre = '~'; - $sum_row_count_pre = '~'; - $show_superscript = PMA_showHint( - PMA_sanitize( - sprintf( - __('This view has at least this number of rows. Please refer to %sdocumentation%s.'), - '[a@./Documentation.html#cfg_MaxExactCountViews@_blank]', - '[/a]' - ) - ) - ); - } - } elseif ($each_table['ENGINE'] == 'InnoDB' && (! $each_table['COUNTED'])) { - // InnoDB table: we did not get an accurate row count - $row_count_pre = '~'; - $sum_row_count_pre = '~'; - $show_superscript = ''; - } - ?> - - 1)) { ?> - - - - - - - - ' . $formatted_size . ' ' . $unit . ''; ?> - - - - - - - --- - - - - - - - - - - - - addHTML($html_output); + } // end foreach // Show Summary -if ($is_show_stats) { - list($sum_formatted, $unit) = PMA_formatByteDown($sum_size, 3, 1); - list($overhead_formatted, $overhead_unit) - = PMA_formatByteDown($overhead_size, 3, 1); -} -?> - - - - - - - ' . __('Replication') . '' . "\n"; - } - ?> - - - - 1)) { - $default_engine = PMA_DBI_fetch_value('SHOW VARIABLES LIKE \'storage_engine\';', 0, 1); - echo ' ' . "\n" - . ' ' .$default_engine . '' . "\n"; - // we got a case where $db_collation was empty - echo ' ' . "\n"; - if (! empty($db_collation)) { - echo ' ' . $db_collation - . ''; - } - echo ''; -} - -if ($is_show_stats) { - ?> - - - - - - +$response->addHTML(''); +$response->addHTML( + PMA_getHtmlBodyForTableSummary( + $num_tables, $server_slave_status, $db_is_information_schema, $sum_entries, + $db_collation, $is_show_stats, $sum_size, $overhead_size, $create_time_all, + $update_time_all, $check_time_all, $sum_row_count_pre + ) +); +$response->addHTML(''); +//check all +$response->addHTML( + PMA_getHtmlForCheckAllTables( + $pmaThemeImage, $text_dir, $overhead_check, + $db_is_information_schema, $hidden_fields + ) +); +$response->addHTML('
'); //end of form -
- -<?php echo __('With selected:'); ?> - - -/ - - - -/ - - - - - - - - -
- -addHTML( + PMA_Util::getListNavigator( + $total_num_tables, $pos, $_url_params, 'db_structure.php', + 'frame_content', $GLOBALS['cfg']['MaxTableList'] + ) ); -?> -
-
-addHTML('

'); /** * Work on the database */ /* DATABASE WORK */ /* Printable view of a table */ -echo '

'; -echo ''; -echo PMA_getIcon('b_print.png', __('Print view'), true) . ''; - -echo ''; -echo PMA_getIcon('b_tblanalyse.png', __('Data Dictionary'), true) . ''; -echo '

'; +$response->addHTML( + PMA_getHtmlForTablePrintViewLink($url_query) + . PMA_getHtmlForDataDictionaryLink($url_query) +); if (empty($db_is_information_schema)) { - include './libraries/display_create_table.lib.php'; + ob_start(); + include 'libraries/display_create_table.lib.php'; + $content = ob_get_contents(); + ob_end_clean(); + $response->addHTML($content); } // end if (Create Table dialog) -/** - * Displays the footer - */ -require './libraries/footer.inc.php'; ?> diff --git a/phpMyAdmin/db_tracking.php b/phpMyAdmin/db_tracking.php index 6fd9a9c..bcd552c 100644 --- a/phpMyAdmin/db_tracking.php +++ b/phpMyAdmin/db_tracking.php @@ -1,29 +1,31 @@ getHeader(); +$scripts = $header->getScripts(); +$scripts->addFile('db_structure.js'); /** * If we are not in an Ajax request, then do the common work and show the links etc. */ -if ($GLOBALS['is_ajax_request'] != true) { - include './libraries/db_common.inc.php'; -} +require 'libraries/db_common.inc.php'; $url_query .= '&goto=tbl_tracking.php&back=db_tracking.php'; // Get the database structure $sub_part = '_structure'; -require './libraries/db_info.inc.php'; +require 'libraries/db_info.inc.php'; // Work to do? // (here, do not use $_REQUEST['db] as it can be crafted) @@ -32,11 +34,12 @@ /** * If in an Ajax request, generate the success message and use - * {@link PMA_ajaxResponse()} to send the output + * {@link PMA_Response()} to send the output */ if ($GLOBALS['is_ajax_request'] == true) { - $message = PMA_Message::success(); - PMA_ajaxResponse($message, true); + $response = PMA_Response::getInstance(); + $response->addJSON('message', PMA_Message::success()); + exit; } } @@ -48,34 +51,26 @@ echo '

' . __('No tables found in database.') . '

' . "\n"; if (empty($db_is_information_schema)) { - include './libraries/display_create_table.lib.php'; + include 'libraries/display_create_table.lib.php'; } - - // Display the footer - include './libraries/footer.inc.php'; exit; } // --------------------------------------------------------------------------- -/* - * Display top menu links - */ -require_once './libraries/db_links.inc.php'; - // Prepare statement to get HEAD version $all_tables_query = ' SELECT table_name, MAX(version) as version FROM ' . - PMA_backquote($GLOBALS['cfg']['Server']['pmadb']) . '.' . - PMA_backquote($GLOBALS['cfg']['Server']['tracking']) . - ' WHERE db_name = \'' . PMA_sqlAddSlashes($_REQUEST['db']) . '\' ' . - ' GROUP BY table_name' . - ' ORDER BY table_name ASC'; + PMA_Util::backquote($GLOBALS['cfg']['Server']['pmadb']) . '.' . + PMA_Util::backquote($GLOBALS['cfg']['Server']['tracking']) . + ' WHERE db_name = \'' . PMA_Util::sqlAddSlashes($_REQUEST['db']) . '\' ' . + ' GROUP BY table_name' . + ' ORDER BY table_name ASC'; -$all_tables_result = PMA_query_as_controluser($all_tables_query); +$all_tables_result = PMA_queryAsControlUser($all_tables_query); // If a HEAD version exists -if (PMA_DBI_num_rows($all_tables_result) > 0) { -?> +if ($GLOBALS['dbi']->numRows($all_tables_result) > 0) { + ?>

@@ -98,31 +93,39 @@ // Print out information about versions $drop_image_or_text = ''; - if (true == $GLOBALS['cfg']['PropertiesIconic']) { - $drop_image_or_text .= PMA_getImage('b_drop.png', __('Delete tracking data for this table')); + if (PMA_Util::showIcons('ActionLinksMode')) { + $drop_image_or_text .= PMA_Util::getImage( + 'b_drop.png', + __('Delete tracking data for this table') + ); } - if ('both' === $GLOBALS['cfg']['PropertiesIconic'] || false === $GLOBALS['cfg']['PropertiesIconic']) { + if (PMA_Util::showText('ActionLinksMode')) { $drop_image_or_text .= __('Drop'); } $style = 'odd'; - while ($one_result = PMA_DBI_fetch_array($all_tables_result)) { + while ($one_result = $GLOBALS['dbi']->fetchArray($all_tables_result)) { list($table_name, $version_number) = $one_result; $table_query = ' SELECT * FROM ' . - PMA_backquote($GLOBALS['cfg']['Server']['pmadb']) . '.' . - PMA_backquote($GLOBALS['cfg']['Server']['tracking']) . - ' WHERE `db_name` = \'' . PMA_sqlAddSlashes($_REQUEST['db']) . '\' AND `table_name` = \'' . PMA_sqlAddSlashes($table_name) . '\' AND `version` = \'' . $version_number . '\''; + PMA_Util::backquote($GLOBALS['cfg']['Server']['pmadb']) . '.' . + PMA_Util::backquote($GLOBALS['cfg']['Server']['tracking']) . + ' WHERE `db_name` = \'' . PMA_Util::sqlAddSlashes($_REQUEST['db']) + . '\' AND `table_name` = \'' . PMA_Util::sqlAddSlashes($table_name) + . '\' AND `version` = \'' . $version_number . '\''; - $table_result = PMA_query_as_controluser($table_query); - $version_data = PMA_DBI_fetch_array($table_result); + $table_result = PMA_queryAsControlUser($table_query); + $version_data = $GLOBALS['dbi']->fetchArray($table_result); if ($version_data['tracking_active'] == 1) { $version_status = __('active'); } else { $version_status = __('not active'); } - $tmp_link = 'tbl_tracking.php?' . $url_query . '&table=' . htmlspecialchars($version_data['table_name']); - $delete_link = 'db_tracking.php?' . $url_query . '&table=' . htmlspecialchars($version_data['table_name']) . '&delete_tracking=true&'; + $tmp_link = 'tbl_tracking.php?' . $url_query . '&table=' + . htmlspecialchars($version_data['table_name']); + $delete_link = 'db_tracking.php?' . $url_query . '&table=' + . htmlspecialchars($version_data['table_name']) + . '&delete_tracking=true&'; ?> @@ -131,12 +134,22 @@ - href="" > - - | - | - + + + ' + . '' + . '' . __('Versions') . '' + . ' | ' + . '' . __('Tracking report') . '' + . ' | ' + . '' . __('Structure snapshot') + . '' + . '' + . ''; if ($style == 'even') { $style = 'odd'; } else { @@ -148,29 +161,36 @@
- $value) { // If $value is a table group. - if (array_key_exists(('is' . $sep . 'group'), $value) && $value['is' . $sep . '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 propery of the table group. - if (is_array($temp_table) && array_key_exists('Name', $temp_table)) { - if (PMA_Tracker::getVersion($GLOBALS['db'], $temp_table['Name']) == -1) { + 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']; } } } - // If $value is a table. - } else { + } else { // If $value is a table. if (PMA_Tracker::getVersion($GLOBALS['db'], $value['Name']) == -1) { $my_tables[] = $value['Name']; } @@ -179,32 +199,34 @@ // If untracked tables exist if (isset($my_tables)) { -?> + ?>

- + - $tablename) { if (PMA_Tracker::getVersion($GLOBALS['db'], $tablename) == -1) { - $my_link = ''; - $my_link .= PMA_getIcon('eye.png', __('Track table')) . ''; - ?> + $my_link = ''; + $my_link .= PMA_Util::getIcon('eye.png', __('Track table')); + $my_link .= ''; + ?> -
- - 0) { $log = ''; foreach ($data['ddlog'] as $entry) { - $log .= '# ' . $entry['date'] . ' ' . $entry['username'] . "\n" . $entry['statement'] . "\n"; + $log .= '# ' . $entry['date'] . ' ' . $entry['username'] . "\n" + . $entry['statement'] . "\n"; } - PMA_showMessage(__('Database Log'), $log); + echo PMA_Util::getMessage(__('Database Log'), $log); } -/** - * Display the footer - */ -require './libraries/footer.inc.php'; ?> diff --git a/phpMyAdmin/db_triggers.php b/phpMyAdmin/db_triggers.php index 210dbfd..d1a2a8c 100644 --- a/phpMyAdmin/db_triggers.php +++ b/phpMyAdmin/db_triggers.php @@ -9,27 +9,17 @@ /** * Include required files */ -require_once './libraries/common.inc.php'; -require_once './libraries/common.lib.php'; - -/** - * Include JavaScript libraries - */ -$GLOBALS['js_include'][] = 'jquery/jquery-ui-1.8.16.custom.js'; -$GLOBALS['js_include'][] = 'rte/common.js'; -$GLOBALS['js_include'][] = 'rte/triggers.js'; -$GLOBALS['js_include'][] = 'codemirror/lib/codemirror.js'; -$GLOBALS['js_include'][] = 'codemirror/mode/mysql/mysql.js'; +require_once 'libraries/common.inc.php'; /** * Include all other files */ -require_once './libraries/rte/rte_triggers.lib.php'; +require_once 'libraries/rte/rte_triggers.lib.php'; /** * Do the magic */ $_PMA_RTE = 'TRI'; -require_once './libraries/rte/rte_main.inc.php'; +require_once 'libraries/rte/rte_main.inc.php'; ?> diff --git a/phpMyAdmin/doc/Makefile b/phpMyAdmin/doc/Makefile new file mode 100644 index 0000000..1ee62c8 --- /dev/null +++ b/phpMyAdmin/doc/Makefile @@ -0,0 +1,153 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = . + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/phpMyAdmin.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/phpMyAdmin.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/phpMyAdmin" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/phpMyAdmin" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff --git a/phpMyAdmin/doc/_ext/configext.py b/phpMyAdmin/doc/_ext/configext.py new file mode 100644 index 0000000..fdf3314 --- /dev/null +++ b/phpMyAdmin/doc/_ext/configext.py @@ -0,0 +1,189 @@ +from sphinx.locale import l_, _ +from sphinx.domains import Domain, ObjType +from sphinx.roles import XRefRole +from sphinx.domains.std import GenericObject, StandardDomain +from sphinx.directives import ObjectDescription +from sphinx.util.nodes import clean_astext, make_refnode +from sphinx.util import ws_re +from sphinx import addnodes +from sphinx.util.docfields import Field +from docutils import nodes + +def get_id_from_cfg(text): + ''' + Formats anchor ID from config option. + ''' + if text[:6] == '$cfg[\'': + text = text[6:] + if text[-2:] == '\']': + text = text[:-2] + text = text.replace('[$i]', '') + parts = text.split("']['") + return parts + + +class ConfigOption(ObjectDescription): + indextemplate = l_('configuration option; %s') + parse_node = None + + has_arguments = True + + doc_field_types = [ + Field('default', label=l_('Default value'), has_arg=False, + names=('default', )), + Field('type', label=l_('Type'), has_arg=False, + names=('type',)), + ] + + + def handle_signature(self, sig, signode): + signode.clear() + signode += addnodes.desc_name(sig, sig) + # normalize whitespace like XRefRole does + name = ws_re.sub('', sig) + return name + + def add_target_and_index(self, name, sig, signode): + targetparts = get_id_from_cfg(name) + targetname = 'cfg_%s' % '_'.join(targetparts) + signode['ids'].append(targetname) + self.state.document.note_explicit_target(signode) + indextype = 'single' + + # Generic index entries + indexentry = self.indextemplate % (name,) + self.indexnode['entries'].append((indextype, indexentry, + targetname, targetname)) + self.indexnode['entries'].append((indextype, name, + targetname, targetname)) + + # Server section + if targetparts[0] == 'Servers' and len(targetparts) > 1: + indexname = ', '.join(targetparts[1:]) + self.indexnode['entries'].append((indextype, l_('server configuration; %s') % indexname, + targetname, targetname)) + self.indexnode['entries'].append((indextype, indexname, + targetname, targetname)) + else: + indexname = ', '.join(targetparts) + self.indexnode['entries'].append((indextype, indexname, + targetname, targetname)) + + self.env.domaindata['config']['objects'][self.objtype, name] = \ + self.env.docname, targetname + + +class ConfigSectionXRefRole(XRefRole): + """ + Cross-referencing role for configuration sections (adds an index entry). + """ + + def result_nodes(self, document, env, node, is_ref): + if not is_ref: + return [node], [] + varname = node['reftarget'] + tgtid = 'index-%s' % env.new_serialno('index') + indexnode = addnodes.index() + indexnode['entries'] = [ + ('single', varname, tgtid, varname), + ('single', _('configuration section; %s') % varname, tgtid, varname) + ] + targetnode = nodes.target('', '', ids=[tgtid]) + document.note_explicit_target(targetnode) + return [indexnode, targetnode, node], [] + +class ConfigSection(ObjectDescription): + indextemplate = l_('configuration section; %s') + parse_node = None + + def handle_signature(self, sig, signode): + if self.parse_node: + name = self.parse_node(self.env, sig, signode) + else: + signode.clear() + signode += addnodes.desc_name(sig, sig) + # normalize whitespace like XRefRole does + name = ws_re.sub('', sig) + return name + + def add_target_and_index(self, name, sig, signode): + targetname = '%s-%s' % (self.objtype, name) + signode['ids'].append(targetname) + self.state.document.note_explicit_target(signode) + if self.indextemplate: + colon = self.indextemplate.find(':') + if colon != -1: + indextype = self.indextemplate[:colon].strip() + indexentry = self.indextemplate[colon+1:].strip() % (name,) + else: + indextype = 'single' + indexentry = self.indextemplate % (name,) + self.indexnode['entries'].append((indextype, indexentry, + targetname, targetname)) + self.env.domaindata['config']['objects'][self.objtype, name] = \ + self.env.docname, targetname + + +class ConfigOptionXRefRole(XRefRole): + """ + Cross-referencing role for configuration options (adds an index entry). + """ + + def result_nodes(self, document, env, node, is_ref): + if not is_ref: + return [node], [] + varname = node['reftarget'] + tgtid = 'index-%s' % env.new_serialno('index') + indexnode = addnodes.index() + indexnode['entries'] = [ + ('single', varname, tgtid, varname), + ('single', _('configuration option; %s') % varname, tgtid, varname) + ] + targetnode = nodes.target('', '', ids=[tgtid]) + document.note_explicit_target(targetnode) + return [indexnode, targetnode, node], [] + + +class ConfigFileDomain(Domain): + name = 'config' + label = 'Config' + + object_types = { + 'option': ObjType(l_('config option'), 'option'), + 'section': ObjType(l_('config section'), 'section'), + } + directives = { + 'option': ConfigOption, + 'section': ConfigSection, + } + roles = { + 'option': ConfigOptionXRefRole(), + 'section': ConfigSectionXRefRole(), + } + + initial_data = { + 'objects': {}, # (type, name) -> docname, labelid + } + + def clear_doc(self, docname): + for key, (fn, _) in self.data['objects'].items(): + if fn == docname: + del self.data['objects'][key] + + def resolve_xref(self, env, fromdocname, builder, + typ, target, node, contnode): + docname, labelid = self.data['objects'].get((typ, target), ('', '')) + if not docname: + return None + else: + return make_refnode(builder, fromdocname, docname, + labelid, contnode) + + def get_objects(self): + for (type, name), info in self.data['objects'].iteritems(): + yield (name, name, type, info[0], info[1], + self.object_types[type].attrs['searchprio']) + +def setup(app): + app.add_domain(ConfigFileDomain) + diff --git a/phpMyAdmin/doc/_ext/configext.pyc b/phpMyAdmin/doc/_ext/configext.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a46d58feef0adcd22d05bb6847f2660c1a112240 GIT binary patch literal 7773 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 v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'phpMyAdmindoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'phpMyAdmin.tex', u'phpMyAdmin Documentation', + u'The phpMyAdmin devel team', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'phpmyadmin', u'phpMyAdmin Documentation', + [u'The phpMyAdmin devel team'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'phpMyAdmin', u'phpMyAdmin Documentation', + u'The phpMyAdmin devel team', 'phpMyAdmin', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + + +# -- Options for Epub output --------------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = u'phpMyAdmin' +epub_author = u'The phpMyAdmin devel team' +epub_publisher = u'The phpMyAdmin devel team' +epub_copyright = copyright + +# The language of the text. It defaults to the language option +# or en if the language is not set. +#epub_language = '' + +# The scheme of the identifier. Typical schemes are ISBN or URL. +#epub_scheme = '' + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +#epub_identifier = '' + +# A unique identification for the text. +#epub_uid = '' + +# A tuple containing the cover image and cover page html template filenames. +#epub_cover = () + +# HTML files that should be inserted before the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_pre_files = [] + +# HTML files shat should be inserted after the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_post_files = [] + +# A list of files that should not be packed into the epub file. +#epub_exclude_files = [] + +# The depth of the table of contents in toc.ncx. +#epub_tocdepth = 3 + +# Allow duplicate toc entries. +#epub_tocdup = True + +# Highlight PHP without starting `_). + + A good test is to browse a table, edit a row and save it. There should be + an error message if phpMyAdmin is having trouble auto–detecting the correct + value. If you get an error that this must be set or if the autodetect code + fails to detect your path, please post a bug report on our bug tracker so + we can improve the code. + + .. seealso:: :ref:`faq1_40` + +.. config:option:: $cfg['PmaNoRelation_DisableWarning'] + + :type: boolean + :default: false + + Starting with version 2.3.0 phpMyAdmin offers a lot of features to + work with master / foreign – tables (see :config:option:`$cfg['Servers'][$i]['pmadb']`). + + If you tried to set this + up and it does not work for you, have a look on the :guilabel:`Structure` page + of one database where you would like to use it. You will find a link + that will analyze why those features have been disabled. + + If you do not want to use those features set this variable to ``true`` to + stop this message from appearing. + +.. config:option:: $cfg['SuhosinDisableWarning'] + + :type: boolean + :default: false + + A warning is displayed on the main page if Suhosin is detected. + + You can set this parameter to ``true`` to stop this message from appearing. + +.. config:option:: $cfg['McryptDisableWarning'] + + :type: boolean + :default: false + + Disable the default warning that is displayed if mcrypt is missing for + cookie authentication. + + You can set this parameter to ``true`` to stop this message from appearing. + +.. config:option:: $cfg['ServerLibraryDifference_DisableWarning'] + + :type: boolean + :default: false + + A warning is displayed on the main page if there is a difference + between the MySQL library and server version. + + You can set this parameter to ``true`` to stop this message from appearing. + +.. config:option:: $cfg['ReservedWordDisableWarning'] + + :type: boolean + :default: false + + This warning is displayed on the Structure page of a table if one or more + column names match with words which are MySQL reserved. + + If you want to turn off this warning, you can set it to ``true`` and + warning will no longer be displayed. + +.. config:option:: $cfg['TranslationWarningThreshold'] + + :type: integer + :default: 80 + + Show warning about incomplete translations on certain threshold. + +.. config:option:: $cfg['SendErrorReports'] + + :type: string + :default: ``'ask'`` + + Sets the default behavior for JavaScript error reporting. + + Whenever an error is detected in the JavaScript execution, an error report + may be sent to the phpMyAdmin team if the user agrees. + + The default setting of ``'ask'`` will ask the user everytime there is a new + error report. However you can set this parameter to ``'always'`` to send error + reports without asking for confirmation or you can set it to ``'never'`` to + never send error reports. + + This directive is available both in the configuration file and in users + preferences. If the person in charge of a multi-user installation prefers + to disable this feature for all users, a value of ``'never'`` should be + set, and the :config:option:`$cfg['UserprefsDisallow']` directive should + contain ``'SendErrorReports'`` in one of its array values. + +.. config:option:: $cfg['AllowThirdPartyFraming'] + + :type: boolean + :default: false + + Setting this to ``true`` allows phpMyAdmin to be included inside a frame, + and is a potential security hole allowing cross-frame scripting attacks or + clickjacking. + +Server connection settings +-------------------------- + +.. config:option:: $cfg['Servers'] + + :type: array + :default: one server array with settings listed bellow + + Since version 1.4.2, phpMyAdmin supports the administration of multiple + MySQL servers. Therefore, a :config:option:`$cfg['Servers']`-array has been + added which contains the login information for the different servers. The + first :config:option:`$cfg['Servers'][$i]['host']` contains the hostname of + the first server, the second :config:option:`$cfg['Servers'][$i]['host']` + the hostname of the second server, etc. In + :file:`libraries/config.default.php`, there is only one section for server + definition, however you can put as many as you need in + :file:`config.inc.php`, copy that block or needed parts (you don't have to + define all settings, just those you need to change). + + .. note:: + + The :config:option:`$cfg['Servers']` array starts with + $cfg['Servers'][1]. Do not use $cfg['Servers'][0]. If you want more + than one server, just copy following section (including $i + incrementation) serveral times. There is no need to define full server + array, just define values you need to change. + + +.. config:option:: $cfg['Servers'][$i]['host'] + + :type: string + :default: ``'localhost'`` + + The hostname or :term:`IP` address of your $i-th MySQL-server. E.g. + ``localhost``. + + Possible values are: + + * hostname, e.g., ``'localhost'`` or ``'mydb.example.org'`` + * IP address, e.g., ``'127.0.0.1'`` or ``'192.168.10.1'`` + * dot - ``'.'``, i.e., use named pipes on windows systems + * empty - ``''``, disables this server + + .. note:: + + phpMyAdmin supports connecting to MySQL servers reachable via IPv6 only. + To connect to an IPv6 MySQL server, enter its IPv6 address in this field. + +.. config:option:: $cfg['Servers'][$i]['port'] + + :type: string + :default: ``''`` + + The port-number of your $i-th MySQL-server. Default is 3306 (leave + blank). + + .. note:: + + If you use ``localhost`` as the hostname, MySQL ignores this port number + and connects with the socket, so if you want to connect to a port + different from the default port, use ``127.0.0.1`` or the real hostname + in :config:option:`$cfg['Servers'][$i]['host']`. + +.. config:option:: $cfg['Servers'][$i]['socket'] + + :type: string + :default: ``''`` + + The path to the socket to use. Leave blank for default. To determine + the correct socket, check your MySQL configuration or, using the + :command:`mysql` command–line client, issue the ``status`` command. Among the + resulting information displayed will be the socket used. + +.. config:option:: $cfg['Servers'][$i]['ssl'] + + :type: boolean + :default: false + + Whether to enable SSL for the connection between phpMyAdmin and the MySQL server. + + When using :config:option:`$cfg['Servers'][$i]['extension']` = ``'mysql'``, + none of the remaining ``'ssl...'`` configuration options apply. + + We strongly recommend using :config:option:`$cfg['Servers'][$i]['extension']` = ``'mysqli'`` + when using this option. + +.. config:option:: $cfg['Servers'][$i]['ssl_key'] + + :type: string + :default: NULL + + Path to the key file when using SSL for connecting to the MySQL server. + + For example: + + .. code-block:: php + + $cfg['Servers'][$i]['ssl_key'] = '/etc/mysql/server-key.pem'; + +.. config:option:: $cfg['Servers'][$i]['ssl_cert'] + + :type: string + :default: NULL + + Path to the cert file when using SSL for connecting to the MySQL server. + +.. config:option:: $cfg['Servers'][$i]['ssl_ca'] + + :type: string + :default: NULL + + Path to the CA file when using SSL for connecting to the MySQL server. + +.. config:option:: $cfg['Servers'][$i]['ssl_ca_path'] + + :type: string + :default: NULL + + Directory containing trusted SSL CA certificates in PEM format. + +.. config:option:: $cfg['Servers'][$i]['ssl_ciphers'] + + :type: string + :default: NULL + + List of allowable ciphers for SSL connections to the MySQL server. + +.. config:option:: $cfg['Servers'][$i]['connect_type'] + + :type: string + :default: ``'tcp'`` + + What type connection to use with the MySQL server. Your options are + ``'socket'`` and ``'tcp'``. It defaults to tcp as that is nearly guaranteed + to be available on all MySQL servers, while sockets are not supported on + some platforms. To use the socket mode, your MySQL server must be on the + same machine as the Web server. + +.. config:option:: $cfg['Servers'][$i]['extension'] + + :type: string + :default: ``'mysqli'`` + + What php MySQL extension to use for the connection. Valid options are: + + ``mysql`` + The classic MySQL extension. + + ``mysqli`` + The improved MySQL extension. This extension became available with PHP + 5.0.0 and is the recommended way to connect to a server running MySQL + 4.1.x or newer. + +.. config:option:: $cfg['Servers'][$i]['compress'] + + :type: boolean + :default: false + + Whether to use a compressed protocol for the MySQL server connection + or not (experimental). + +.. _controlhost: +.. config:option:: $cfg['Servers'][$i]['controlhost'] + + :type: string + :default: ``''`` + + Permits to use an alternate host to hold the configuration storage + data. + +.. _controlport: +.. config:option:: $cfg['Servers'][$i]['controlport'] + + :type: string + :default: ``''`` + + Permits to use an alternate port to connect to the host that + holds the configuration storage. + +.. _controluser: +.. config:option:: $cfg['Servers'][$i]['controluser'] + + :type: string + :default: ``''`` + +.. config:option:: $cfg['Servers'][$i]['controlpass'] + + :type: string + :default: ``''`` + + This special account is used for 2 distinct purposes: to make possible all + relational features (see :config:option:`$cfg['Servers'][$i]['pmadb']`) and, + for a MySQL server running with ``--skip-show-database``, to enable a + multi-user installation (:term:`HTTP` or cookie + authentication mode). + + When using :term:`HTTP` or + cookie authentication modes (or 'config' authentication mode since phpMyAdmin + 2.2.1), you need to supply the details of a MySQL account that has ``SELECT`` + privilege on the *mysql.user (all columns except "Password")*, *mysql.db (all + columns)* and *mysql.tables\_priv (all columns except "Grantor" and + "Timestamp")* tables. This account is used to check what databases the user + will see at login. + + .. versionchanged:: 2.2.5 + those were called ``stduser`` and ``stdpass`` + + .. seealso:: :ref:`setup`, :ref:`authentication_modes` + +.. config:option:: $cfg['Servers'][$i]['auth_type'] + + :type: string + :default: ``'cookie'`` + + Whether config or cookie or :term:`HTTP` or signon authentication should be + used for this server. + + * 'config' authentication (``$auth_type = 'config'``) is the plain old + way: username and password are stored in :file:`config.inc.php`. + * 'cookie' authentication mode (``$auth_type = 'cookie'``) as + introduced in 2.2.3 allows you to log in as any valid MySQL user with + the help of cookies. Username and password are stored in cookies + during the session and password is deleted when it ends. This can also + allow you to log in in arbitrary server if :config:option:`$cfg['AllowArbitraryServer']` enabled. + * 'http' authentication (was + called 'advanced' in previous versions and can be written also as + 'http') (``$auth_type = 'http';'``) as introduced in 1.3.0 allows you to log in as any + valid MySQL user via HTTP-Auth. + * 'signon' authentication mode (``$auth_type = 'signon'``) as + introduced in 2.10.0 allows you to log in from prepared PHP session + data or using supplied PHP script. This is useful for implementing + single signon from another application. Sample way how to seed session + is in signon example: :file:`examples/signon.php`. There is also + alternative example using OpenID - :file:`examples/openid.php` and example + for scripts based solution - :file:`examples/signon-script.php`. You need + to configure :config:option:`$cfg['Servers'][$i]['SignonSession']` or + :config:option:`$cfg['Servers'][$i]['SignonScript']` and + :config:option:`$cfg['Servers'][$i]['SignonURL']` to use this authentication + method. + + .. seealso:: :ref:`authentication_modes` + +.. _servers_auth_http_realm: +.. config:option:: $cfg['Servers'][$i]['auth_http_realm'] + + :type: string + :default: ``''`` + + When using auth\_type = ``http``, this field allows to define a custom + :term:`HTTP` Basic Auth Realm which will be displayed to the user. If not + explicitly specified in your configuration, a string combined of + "phpMyAdmin " and either :config:option:`$cfg['Servers'][$i]['verbose']` or + :config:option:`$cfg['Servers'][$i]['host']` will be used. + +.. _servers_auth_swekey_config: +.. config:option:: $cfg['Servers'][$i]['auth_swekey_config'] + + :type: string + :default: ``''`` + + The name of the file containing :ref:`swekey` ids and login names for hardware + authentication. Leave empty to deactivate this feature. + +.. _servers_user: +.. config:option:: $cfg['Servers'][$i]['user'] + + :type: string + :default: ``'root'`` + +.. config:option:: $cfg['Servers'][$i]['password'] + + :type: string + :default: ``''`` + + When using :config:option:`$cfg['Servers'][$i]['auth_type']` set to + 'config', this is the user/password-pair which phpMyAdmin will use to + connect to the MySQL server. This user/password pair is not needed when + :term:`HTTP` or cookie authentication is used + and should be empty. + +.. _servers_nopassword: +.. config:option:: $cfg['Servers'][$i]['nopassword'] + + :type: boolean + :default: false + + Allow attempt to log in without password when a login with password + fails. This can be used together with http authentication, when + authentication is done some other way and phpMyAdmin gets user name + from auth and uses empty password for connecting to MySQL. Password + login is still tried first, but as fallback, no password method is + tried. + +.. _servers_only_db: +.. config:option:: $cfg['Servers'][$i]['only_db'] + + :type: string or array + :default: ``''`` + + If set to a (an array of) database name(s), only this (these) + database(s) will be shown to the user. Since phpMyAdmin 2.2.1, + this/these database(s) name(s) may contain MySQL wildcards characters + ("\_" and "%"): if you want to use literal instances of these + characters, escape them (I.E. use ``'my\_db'`` and not ``'my_db'``). + + This setting is an efficient way to lower the server load since the + latter does not need to send MySQL requests to build the available + database list. But **it does not replace the privileges rules of the + MySQL database server**. If set, it just means only these databases + will be displayed but **not that all other databases can't be used.** + + An example of using more that one database: + + .. code-block:: php + + $cfg['Servers'][$i]['only_db'] = array('db1', 'db2'); + + .. versionchanged:: 4.0.0 + Previous versions permitted to specify the display order of + the database names via this directive. + +.. config:option:: $cfg['Servers'][$i]['hide_db'] + + :type: string + :default: ``''`` + + Regular expression for hiding some databases from unprivileged users. + This only hides them from listing, but a user is still able to access + them (using, for example, the SQL query area). To limit access, use + the MySQL privilege system. For example, to hide all databases + starting with the letter "a", use + + .. code-block:: php + + $cfg['Servers'][$i]['hide_db'] = '^a'; + + and to hide both "db1" and "db2" use + + .. code-block:: php + + $cfg['Servers'][$i]['hide_db'] = '^(db1|db2)$'; + + More information on regular expressions can be found in the `PCRE + pattern syntax + `_ portion + of the PHP reference manual. + +.. config:option:: $cfg['Servers'][$i]['verbose'] + + :type: string + :default: ``''`` + + Only useful when using phpMyAdmin with multiple server entries. If + set, this string will be displayed instead of the hostname in the + pull-down menu on the main page. This can be useful if you want to + show only certain databases on your system, for example. For HTTP + auth, all non-US-ASCII characters will be stripped. + +.. config:option:: $cfg['Servers'][$i]['pmadb'] + + :type: string + :default: ``''`` + + The name of the database containing the phpMyAdmin configuration + storage. + + See the :ref:`linked-tables` section in this document to see the benefits of + this feature, and for a quick way of creating this database and the needed + tables. + + If you are the only user of this phpMyAdmin installation, you can use your + current database to store those special tables; in this case, just put your + current database name in :config:option:`$cfg['Servers'][$i]['pmadb']`. For a + multi-user installation, set this parameter to the name of your central + database containing the phpMyAdmin configuration storage. + +.. _bookmark: +.. config:option:: $cfg['Servers'][$i]['bookmarktable'] + + :type: string + :default: ``''`` + + Since release 2.2.0 phpMyAdmin allows users to bookmark queries. This + can be useful for queries you often run. To allow the usage of this + functionality: + + * set up :config:option:`$cfg['Servers'][$i]['pmadb']` and the phpMyAdmin configuration storage + * enter the table name in :config:option:`$cfg['Servers'][$i]['bookmarktable']` + + +.. _relation: +.. config:option:: $cfg['Servers'][$i]['relation'] + + :type: string + :default: ``''`` + + Since release 2.2.4 you can describe, in a special 'relation' table, + which column is a key in another table (a foreign key). phpMyAdmin + currently uses this to: + + * make clickable, when you browse the master table, the data values that + point to the foreign table; + * display in an optional tool-tip the "display column" when browsing the + master table, if you move the mouse to a column containing a foreign + key (use also the 'table\_info' table); (see :ref:`faqdisplay`) + * in edit/insert mode, display a drop-down list of possible foreign keys + (key value and "display column" are shown) (see :ref:`faq6_21`) + * display links on the table properties page, to check referential + integrity (display missing foreign keys) for each described key; + * in query-by-example, create automatic joins (see :ref:`faq6_6`) + * enable you to get a :term:`PDF` schema of + your database (also uses the table\_coords table). + + The keys can be numeric or character. + + To allow the usage of this functionality: + + * set up :config:option:`$cfg['Servers'][$i]['pmadb']` and the phpMyAdmin configuration storage + * put the relation table name in :config:option:`$cfg['Servers'][$i]['relation']` + * now as normal user open phpMyAdmin and for each one of your tables + where you want to use this feature, click :guilabel:`Structure/Relation view/` + and choose foreign columns. + + .. note:: + + In the current version, ``master_db`` must be the same as ``foreign_db``. + Those columns have been put in future development of the cross-db + relations. + +.. _table_info: +.. config:option:: $cfg['Servers'][$i]['table_info'] + + :type: string + :default: ``''`` + + Since release 2.3.0 you can describe, in a special 'table\_info' + table, which column is to be displayed as a tool-tip when moving the + cursor over the corresponding key. This configuration variable will + hold the name of this special table. To allow the usage of this + functionality: + + * set up :config:option:`$cfg['Servers'][$i]['pmadb']` and the phpMyAdmin configuration storage + * put the table name in :config:option:`$cfg['Servers'][$i]['table\_info']` (e.g. + ``pma__table_info``) + * then for each table where you want to use this feature, click + "Structure/Relation view/Choose column to display" to choose the + column. + + .. seealso:: :ref:`faqdisplay` + +.. _table_coords: +.. config:option:: $cfg['Servers'][$i]['table_coords'] + + :type: string + :default: ``''`` + +.. config:option:: $cfg['Servers'][$i]['pdf_pages'] + + :type: string + :default: ``''`` + + Since release 2.3.0 you can have phpMyAdmin create :term:`PDF` pages + showing the relations between your tables. To do this it needs two tables + "pdf\_pages" (storing information about the available :term:`PDF` pages) + and "table\_coords" (storing coordinates where each table will be placed on + a :term:`PDF` schema output). You must be using the "relation" feature. + + To allow the usage of this functionality: + + * set up :config:option:`$cfg['Servers'][$i]['pmadb']` and the phpMyAdmin configuration storage + * put the correct table names in + :config:option:`$cfg['Servers'][$i]['table\_coords']` and + :config:option:`$cfg['Servers'][$i]['pdf\_pages']` + + .. seealso:: :ref:`faqpdf`. + +.. _col_com: +.. config:option:: $cfg['Servers'][$i]['column_info'] + + :type: string + :default: ``''`` + + This part requires a content update! Since release 2.3.0 you can + store comments to describe each column for each table. These will then + be shown on the "printview". + + Starting with release 2.5.0, comments are consequently used on the table + property pages and table browse view, showing up as tool-tips above the + column name (properties page) or embedded within the header of table in + browse view. They can also be shown in a table dump. Please see the + relevant configuration directives later on. + + Also new in release 2.5.0 is a MIME- transformation system which is also + based on the following table structure. See :ref:`transformations` for + further information. To use the MIME- transformation system, your + column\_info table has to have the three new columns 'mimetype', + 'transformation', 'transformation\_options'. + + + To allow the usage of this functionality: + + * set up :config:option:`$cfg['Servers'][$i]['pmadb']` and the phpMyAdmin configuration storage + * put the table name in :config:option:`$cfg['Servers'][$i]['column\_info']` (e.g. + ``pma__column_info``) + * to update your PRE-2.5.0 Column\_comments Table use this: and + remember that the Variable in :file:`config.inc.php` has been renamed from + :config:option:`$cfg['Servers'][$i]['column\_comments']` to + :config:option:`$cfg['Servers'][$i]['column\_info']` + + .. code-block:: mysql + + ALTER TABLE `pma__column_comments` + ADD `mimetype` VARCHAR( 255 ) NOT NULL, + ADD `transformation` VARCHAR( 255 ) NOT NULL, + ADD `transformation_options` VARCHAR( 255 ) NOT NULL; + +.. _history: +.. config:option:: $cfg['Servers'][$i]['history'] + + :type: string + :default: ``''`` + + Since release 2.5.0 you can store your :term:`SQL` history, which means all + queries you entered manually into the phpMyAdmin interface. If you don't + want to use a table-based history, you can use the JavaScript-based + history. + + Using that, all your history items are deleted when closing the window. + Using :config:option:`$cfg['QueryHistoryMax']` you can specify an amount of + history items you want to have on hold. On every login, this list gets cut + to the maximum amount. + + The query history is only available if JavaScript is enabled in + your browser. + + To allow the usage of this functionality: + + * set up :config:option:`$cfg['Servers'][$i]['pmadb']` and the phpMyAdmin configuration storage + * put the table name in :config:option:`$cfg['Servers'][$i]['history']` (e.g. + ``pma__history``) + +.. _recent: +.. config:option:: $cfg['Servers'][$i]['recent'] + + :type: string + :default: ``''`` + + Since release 3.5.0 you can show recently used tables in the + navigation panel. It helps you to jump across table directly, without + the need to select the database, and then select the table. Using + :config:option:`$cfg['NumRecentTables']` you can configure the maximum number + of recent tables shown. When you select a table from the list, it will jump to + the page specified in :config:option:`$cfg['NavigationTreeDefaultTabTable']`. + + + Without configuring the storage, you can still access the recently used tables, + but it will disappear after you logout. + + To allow the usage of this functionality persistently: + + * set up :config:option:`$cfg['Servers'][$i]['pmadb']` and the phpMyAdmin configuration storage + * put the table name in :config:option:`$cfg['Servers'][$i]['recent']` (e.g. + ``pma__recent``) + +.. _table_uiprefs: +.. config:option:: $cfg['Servers'][$i]['table_uiprefs'] + + :type: string + :default: ``''`` + + Since release 3.5.0 phpMyAdmin can be configured to remember several + things (sorted column :config:option:`$cfg['RememberSorting']`, column order, + and column visibility from a database table) for browsing tables. Without + configuring the storage, these features still can be used, but the values will + disappear after you logout. + + To allow the usage of these functionality persistently: + + * set up :config:option:`$cfg['Servers'][$i]['pmadb']` and the phpMyAdmin configuration storage + * put the table name in :config:option:`$cfg['Servers'][$i]['table\_uiprefs']` (e.g. + ``pma__table_uiprefs``) + +.. _configurablemenus: +.. config:option:: $cfg['Servers'][$i]['users'] + + :type: string + :default: ``''`` + +.. config:option:: $cfg['Servers'][$i]['usergroups'] + + :type: string + :default: ``''`` + + Since release 4.1.0 you can create different user groups with menu items + attached to them. Users can be assigned to these groups and the logged in + user would only see menu items configured to the usergroup he is assigned to. + To do this it needs two tables "usergroups" (storing allowed menu items for each + user group) and "users" (storing users and their assignments to user groups). + + To allow the usage of this functionality: + + * set up :config:option:`$cfg['Servers'][$i]['pmadb']` and the phpMyAdmin configuration storage + * put the correct table names in + :config:option:`$cfg['Servers'][$i]['users']` (e.g. ``pma__users``) and + :config:option:`$cfg['Servers'][$i]['usergroups']` (e.g. ``pma__usergroups``) + +.. _navigationhiding: +.. config:option:: $cfg['Servers'][$i]['navigationhiding'] + + :type: string + :default: ``''`` + + Since release 4.1.0 you can hide/show items in the navigation tree. + + To allow the usage of this functionality: + + * set up :config:option:`$cfg['Servers'][$i]['pmadb']` and the phpMyAdmin configuration storage + * put the table name in :config:option:`$cfg['Servers'][$i]['navigationhiding']` (e.g. + ``pma__navigationhiding``) + +.. _tracking: +.. config:option:: $cfg['Servers'][$i]['tracking'] + + :type: string + :default: ``''`` + + Since release 3.3.x a tracking mechanism is available. It helps you to + track every :term:`SQL` command which is + executed by phpMyAdmin. The mechanism supports logging of data + manipulation and data definition statements. After enabling it you can + create versions of tables. + + The creation of a version has two effects: + + * phpMyAdmin saves a snapshot of the table, including structure and + indexes. + * phpMyAdmin logs all commands which change the structure and/or data of + the table and links these commands with the version number. + + Of course you can view the tracked changes. On the :guilabel:`Tracking` + page a complete report is available for every version. For the report you + can use filters, for example you can get a list of statements within a date + range. When you want to filter usernames you can enter \* for all names or + you enter a list of names separated by ','. In addition you can export the + (filtered) report to a file or to a temporary database. + + To allow the usage of this functionality: + + * set up :config:option:`$cfg['Servers'][$i]['pmadb']` and the phpMyAdmin configuration storage + * put the table name in :config:option:`$cfg['Servers'][$i]['tracking']` (e.g. + ``pma__tracking``) + + +.. _tracking2: +.. config:option:: $cfg['Servers'][$i]['tracking_version_auto_create'] + + :type: boolean + :default: false + + Whether the tracking mechanism creates versions for tables and views + automatically. + + If this is set to true and you create a table or view with + + * CREATE TABLE ... + * CREATE VIEW ... + + and no version exists for it, the mechanism will create a version for + you automatically. + +.. _tracking3: +.. config:option:: $cfg['Servers'][$i]['tracking_default_statements'] + + :type: string + :default: ``'CREATE TABLE,ALTER TABLE,DROP TABLE,RENAME TABLE,CREATE INDEX,DROP INDEX,INSERT,UPDATE,DELETE,TRUNCATE,REPLACE,CREATE VIEW,ALTER VIEW,DROP VIEW,CREATE DATABASE,ALTER DATABASE,DROP DATABASE'`` + + Defines the list of statements the auto-creation uses for new + versions. + +.. _tracking4: +.. config:option:: $cfg['Servers'][$i]['tracking_add_drop_view'] + + :type: boolean + :default: true + + Whether a DROP VIEW IF EXISTS statement will be added as first line to + the log when creating a view. + +.. _tracking5: +.. config:option:: $cfg['Servers'][$i]['tracking_add_drop_table'] + + :type: boolean + :default: true + + Whether a DROP TABLE IF EXISTS statement will be added as first line + to the log when creating a table. + +.. _tracking6: +.. config:option:: $cfg['Servers'][$i]['tracking_add_drop_database'] + + :type: boolean + :default: true + + Whether a DROP DATABASE IF EXISTS statement will be added as first + line to the log when creating a database. + +.. _userconfig: +.. config:option:: $cfg['Servers'][$i]['userconfig'] + + :type: string + :default: ``''`` + + Since release 3.4.x phpMyAdmin allows users to set most preferences by + themselves and store them in the database. + + If you don't allow for storing preferences in + :config:option:`$cfg['Servers'][$i]['pmadb']`, users can still personalize + phpMyAdmin, but settings will be saved in browser's local storage, or, it + is is unavailable, until the end of session. + + To allow the usage of this functionality: + + * set up :config:option:`$cfg['Servers'][$i]['pmadb']` and the phpMyAdmin configuration storage + * put the table name in :config:option:`$cfg['Servers'][$i]['userconfig']` + + + +.. _designer_coords: +.. config:option:: $cfg['Servers'][$i]['designer_coords'] + + :type: string + :default: ``''`` + + Since release 2.10.0 a Designer interface is available; it permits to + visually manage the relations. + + To allow the usage of this functionality: + + * set up :config:option:`$cfg['Servers'][$i]['pmadb']` and the phpMyAdmin configuration storage + * put the table name in :config:option:`$cfg['Servers'][$i]['designer\_coords']` + (e.g. ``pma__designer_coords``) + + + +.. config:option:: $cfg['Servers'][$i]['MaxTableUiprefs'] + + :type: integer + :default: 100 + + Maximum number of rows saved in + :config:option:`$cfg['Servers'][$i]['table_uiprefs']` table. + + When tables are dropped or renamed, + :config:option:`$cfg['Servers'][$i]['table_uiprefs']` may contain invalid data + (referring to tables which no longer exist). We only keep this number of newest + rows in :config:option:`$cfg['Servers'][$i]['table_uiprefs']` and automatically + delete older rows. + +.. config:option:: $cfg['Servers'][$i]['AllowRoot'] + + :type: boolean + :default: true + + Whether to allow root access. This is just a shortcut for the + :config:option:`$cfg['Servers'][$i]['AllowDeny']['rules']` below. + +.. config:option:: $cfg['Servers'][$i]['AllowNoPassword'] + + :type: boolean + :default: false + + Whether to allow logins without a password. The default value of + ``false`` for this parameter prevents unintended access to a MySQL + server with was left with an empty password for root or on which an + anonymous (blank) user is defined. + +.. _servers_allowdeny_order: +.. config:option:: $cfg['Servers'][$i]['AllowDeny']['order'] + + :type: string + :default: ``''`` + + If your rule order is empty, then :term:`IP` + authorization is disabled. + + If your rule order is set to + ``'deny,allow'`` then the system applies all deny rules followed by + allow rules. Access is allowed by default. Any client which does not + match a Deny command or does match an Allow command will be allowed + access to the server. + + If your rule order is set to ``'allow,deny'`` + then the system applies all allow rules followed by deny rules. Access + is denied by default. Any client which does not match an Allow + directive or does match a Deny directive will be denied access to the + server. + + If your rule order is set to ``'explicit'``, authorization is + performed in a similar fashion to rule order 'deny,allow', with the + added restriction that your host/username combination **must** be + listed in the *allow* rules, and not listed in the *deny* rules. This + is the **most** secure means of using Allow/Deny rules, and was + available in Apache by specifying allow and deny rules without setting + any order. + + Please also see :config:option:`$cfg['TrustedProxies']` for + detecting IP address behind proxies. + +.. _servers_allowdeny_rules: +.. config:option:: $cfg['Servers'][$i]['AllowDeny']['rules'] + + :type: array of strings + :default: array() + + The general format for the rules is as such: + + .. code-block:: none + + <'allow' | 'deny'> [from] + + If you wish to match all users, it is possible to use a ``'%'`` as a + wildcard in the *username* field. + + There are a few shortcuts you can + use in the *ipmask* field as well (please note that those containing + SERVER\_ADDRESS might not be available on all webservers): + + .. code-block:: none + + + 'all' -> 0.0.0.0/0 + 'localhost' -> 127.0.0.1/8 + 'localnetA' -> SERVER_ADDRESS/8 + 'localnetB' -> SERVER_ADDRESS/16 + 'localnetC' -> SERVER_ADDRESS/24 + + Having an empty rule list is equivalent to either using ``'allow % + from all'`` if your rule order is set to ``'deny,allow'`` or ``'deny % + from all'`` if your rule order is set to ``'allow,deny'`` or + ``'explicit'``. + + For the :term:`IP address` matching + system, the following work: + + * ``xxx.xxx.xxx.xxx`` (an exact :term:`IP address`) + * ``xxx.xxx.xxx.[yyy-zzz]`` (an :term:`IP address` range) + * ``xxx.xxx.xxx.xxx/nn`` (CIDR, Classless Inter-Domain Routing type :term:`IP` addresses) + + But the following does not work: + + * ``xxx.xxx.xxx.xx[yyy-zzz]`` (partial :term:`IP` address range) + + For :term:`IPv6` addresses, the following work: + + * ``xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx`` (an exact :term:`IPv6` address) + * ``xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:[yyyy-zzzz]`` (an :term:`IPv6` address range) + * ``xxxx:xxxx:xxxx:xxxx/nn`` (CIDR, Classless Inter-Domain Routing type :term:`IPv6` addresses) + + But the following does not work: + + * ``xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xx[yyy-zzz]`` (partial :term:`IPv6` address range) + +.. config:option:: $cfg['Servers'][$i]['SignonScript'] + + :type: string + :default: ``''`` + + Name of PHP script to be sourced and executed to obtain login + credentials. This is alternative approach to session based single + signon. The script needs to provide function + ``get_login_credentials`` which returns list of username and + password, accepting single parameter of existing username (can be + empty). See :file:`examples/signon-script.php` for an example. + +.. config:option:: $cfg['Servers'][$i]['SignonSession'] + + :type: string + :default: ``''`` + + Name of session which will be used for signon authentication method. + You should use something different than ``phpMyAdmin``, because this + is session which phpMyAdmin uses internally. Takes effect only if + :config:option:`$cfg['Servers'][$i]['SignonScript']` is not configured. + +.. config:option:: $cfg['Servers'][$i]['SignonURL'] + + :type: string + :default: ``''`` + + :term:`URL` where user will be redirected + to log in for signon authentication method. Should be absolute + including protocol. + +.. config:option:: $cfg['Servers'][$i]['LogoutURL'] + + :type: string + :default: ``''`` + + :term:`URL` where user will be redirected + after logout (doesn't affect config authentication method). Should be + absolute including protocol. + +.. config:option:: $cfg['Servers'][$i]['StatusCacheDatabases'] + + :type: array of strings + :default: array() + + Enables caching of ``TABLE STATUS`` outputs for specific databases on + this server (in some cases ``TABLE STATUS`` can be very slow, so you + may want to cache it). APC is used (if the PHP extension is available, + if not, this setting is ignored silently). You have to provide + :config:option:`$cfg['Servers'][$i]['StatusCacheLifetime']`. + +.. config:option:: $cfg['Servers'][$i]['StatusCacheLifetime'] + + :type: integer + :default: 0 + + Lifetime in seconds of the ``TABLE STATUS`` cache if + :config:option:`$cfg['Servers'][$i]['StatusCacheDatabases']` is used. + +Generic settings +---------------- + +.. config:option:: $cfg['ServerDefault'] + + :type: integer + :default: 1 + + If you have more than one server configured, you can set + :config:option:`$cfg['ServerDefault']` to any one of them to autoconnect to that + server when phpMyAdmin is started, or set it to 0 to be given a list + of servers without logging in. + + If you have only one server configured, + :config:option:`$cfg['ServerDefault']` MUST be set to that server. + +.. config:option:: $cfg['VersionCheck'] + + :type: boolean + :default: true + + Enables check for latest versions using javascript on main phpMyAdmin + page. + + .. note:: + + This setting can be adjusted by your vendor. + +.. config:option:: $cfg['ProxyUrl'] + + :type: string + :default: "" + + The url of the proxy to be used when phpmyadmin needs to access the outside + intenet such as when retrieving the latest version info or submitting error + reports. You need this if the server where phpMyAdmin is installed does not + have direct access to the internet. + The format is: "hostname:portnumber" + +.. config:option:: $cfg['ProxyUser'] + + :type: string + :default: "" + + The username for authenticating with the proxy. By default, no + authentication is performed. If a username is supplied, Basic + Authentication will be performed. No other types of authentication + are currently supported. + +.. config:option:: $cfg['ProxyPass'] + + :type: string + :default: "" + + The password for authenticating with the proxy. + +.. config:option:: $cfg['MaxDbList'] + + :type: integer + :default: 100 + + The maximum number of database names to be displayed in the main panel's + database list. + +.. config:option:: $cfg['MaxTableList'] + + :type: integer + :default: 250 + + The maximum number of table names to be displayed in the main panel's + list (except on the Export page). This limit is also enforced in the + navigation panel when in Light mode. + +.. config:option:: $cfg['ShowHint'] + + :type: boolean + :default: true + + Whether or not to show hints (for example, hints when hovering over + table headers). + +.. config:option:: $cfg['MaxCharactersInDisplayedSQL'] + + :type: integer + :default: 1000 + + The maximum number of characters when a :term:`SQL` query is displayed. The + default limit of 1000 should be correct to avoid the display of tons of + hexadecimal codes that represent BLOBs, but some users have real + :term:`SQL` queries that are longer than 1000 characters. Also, if a + query's length exceeds this limit, this query is not saved in the history. + +.. config:option:: $cfg['PersistentConnections'] + + :type: boolean + :default: false + + Whether `persistent connections `_ should be used or not. Works with + following extensions: + + * mysql (`mysql\_pconnect `_), + * mysqli (requires PHP 5.3.0 or newer, `more information + `_). + +.. config:option:: $cfg['ForceSSL'] + + :type: boolean + :default: false + + Whether to force using https while accessing phpMyAdmin. + + .. note:: + + In some setups (like separate SSL proxy or load balancer) you might + have to set :config:option:`$cfg['PmaAbsoluteUri']` for correct + redirection. + +.. config:option:: $cfg['ExecTimeLimit'] + + :type: integer [number of seconds] + :default: 300 + + Set the number of seconds a script is allowed to run. If seconds is + set to zero, no time limit is imposed. This setting is used while + importing/exporting dump files but has + no effect when PHP is running in safe mode. + +.. config:option:: $cfg['SessionSavePath'] + + :type: string + :default: ``''`` + + Path for storing session data (`session\_save\_path PHP parameter + `_). + +.. config:option:: $cfg['MemoryLimit'] + + :type: string [number of bytes] + :default: ``'-1'`` + + Set the number of bytes a script is allowed to allocate. If set to + ``'-1'``, no limit is imposed. + + This setting is used while importing/exporting dump files and at some other + places in phpMyAdmin so you definitely don't want to put here a too low + value. It has no effect when PHP is running in safe mode. + + You can also use any string as in :file:`php.ini`, eg. '16M'. Ensure you + don't omit the suffix (16 means 16 bytes!) + +.. config:option:: $cfg['SkipLockedTables'] + + :type: boolean + :default: false + + Mark used tables and make it possible to show databases with locked + tables (since MySQL 3.23.30). + +.. config:option:: $cfg['ShowSQL'] + + :type: boolean + :default: true + + Defines whether :term:`SQL` queries + generated by phpMyAdmin should be displayed or not. + +.. config:option:: $cfg['RetainQueryBox'] + + :type: boolean + :default: false + + Defines whether the :term:`SQL` query box + should be kept displayed after its submission. + +.. config:option:: $cfg['CodemirrorEnable'] + + :type: boolean + :default: true + + Defines whether to use a Javascript code editor for SQL query boxes. + CodeMirror provides syntax highlighting and line numbers. However, + middle-clicking for pasting the clipboard contents in some Linux + distributions (such as Ubuntu) is not supported by all browsers. + +.. config:option:: $cfg['AllowUserDropDatabase'] + + :type: boolean + :default: false + + Defines whether normal users (non-administrator) are allowed to delete + their own database or not. If set as false, the link :guilabel:`Drop + Database` will not be shown, and even a ``DROP DATABASE mydatabase`` will + be rejected. Quite practical for :term:`ISP` 's with many customers. + + .. note:: + + This limitation of :term:`SQL` queries is not + as strict as when using MySQL privileges. This is due to nature of + :term:`SQL` queries which might be quite + complicated. So this choice should be viewed as help to avoid accidental + dropping rather than strict privilege limitation. + +.. config:option:: $cfg['Confirm'] + + :type: boolean + :default: true + + Whether a warning ("Are your really sure...") should be displayed when + you're about to lose data. + +.. config:option:: $cfg['UseDbSearch'] + + :type: boolean + :default: true + + Define whether the "search string inside database" is enabled or not. + +.. config:option:: $cfg['IgnoreMultiSubmitErrors'] + + :type: boolean + :default: false + + Define whether phpMyAdmin will continue executing a multi-query + statement if one of the queries fails. Default is to abort execution. + +Cookie authentication options +----------------------------- + +.. config:option:: $cfg['blowfish_secret'] + + :type: string + :default: ``''`` + + The "cookie" auth\_type uses blowfish algorithm to encrypt the + password. If you are using the "cookie" auth\_type, enter here a + random passphrase of your choice. It will be used internally by the + blowfish algorithm: you won’t be prompted for this passphrase. There + is no maximum length for this secret. + + .. versionchanged:: 3.1.0 + Since version 3.1.0 phpMyAdmin can generate this on the fly, but it + makes a bit weaker security as this generated secret is stored in + session and furthermore it makes impossible to recall user name from + cookie. + +.. config:option:: $cfg['LoginCookieRecall'] + + :type: boolean + :default: true + + Define whether the previous login should be recalled or not in cookie + authentication mode. + + This is automatically disabled if you do not have + configured :config:option:`$cfg['blowfish_secret']`. + +.. config:option:: $cfg['LoginCookieValidity'] + + :type: integer [number of seconds] + :default: 1440 + + Define how long a login cookie is valid. Please note that php + configuration option `session.gc\_maxlifetime + `_ might limit session validity and if the session is lost, + the login cookie is also invalidated. So it is a good idea to set + ``session.gc_maxlifetime`` at least to the same value of + :config:option:`$cfg['LoginCookieValidity']`. + +.. config:option:: $cfg['LoginCookieStore'] + + :type: integer [number of seconds] + :default: 0 + + Define how long login cookie should be stored in browser. Default 0 + means that it will be kept for existing session. This is recommended + for not trusted environments. + +.. config:option:: $cfg['LoginCookieDeleteAll'] + + :type: boolean + :default: true + + If enabled (default), logout deletes cookies for all servers, + otherwise only for current one. Setting this to false makes it easy to + forget to log out from other server, when you are using more of them. + +.. _AllowArbitraryServer: +.. config:option:: $cfg['AllowArbitraryServer'] + + :type: boolean + :default: false + + If enabled, allows you to log in to arbitrary servers using cookie + authentication. + + .. note:: + + Please use this carefully, as this may allow users access to MySQL servers + behind the firewall where your :term:`HTTP` + server is placed. + +.. config:option:: $cfg['CaptchaLoginPublicKey'] + + :type: string + :default: ``''`` + + The public key for the reCaptcha service that can be obtain from + http://www.google.com/recaptcha. + + reCaptcha will be then used in :ref:`cookie`. + +.. config:option:: $cfg['CaptchaLoginPrivateKey'] + + :type: string + :default: ``''`` + + The private key for the reCaptcha service that can be obtain from + http://www.google.com/recaptcha. + + reCaptcha will be then used in :ref:`cookie`. + +Navigation panel setup +---------------------- + +.. config:option:: $cfg['MaxNavigationItems'] + + :type: integer + :default: 250 + + The number of items that can be displayed on each page of the + navigation tree. + +.. config:option:: $cfg['NavigationTreeEnableGrouping'] + + :type: boolean + :default: true + + Defines whether to group the databases based on a common prefix + in their name :config:option:`$cfg['NavigationTreeDbSeparator']`. + +.. config:option:: $cfg['NavigationTreeDbSeparator'] + + :type: string or array + :default: ``'_'`` + + The string used to separate the parts of the database name when + showing them in a tree. Alternatively you can specify more strings in + an array and all of them will be used as a separator. + +.. config:option:: $cfg['NavigationTreeTableSeparator'] + + :type: string or array + :default: ``'__'`` + + Defines a string to be used to nest table spaces. This means if you have + tables like ``first__second__third`` this will be shown as a three-level + hierarchy like: first > second > third. If set to false or empty, the + feature is disabled. NOTE: You should not use this separator at the + beginning or end of a table name or multiple times after another without + any other characters in between. + +.. config:option:: $cfg['NavigationTreeTableLevel'] + + :type: integer + :default: 1 + + Defines how many sublevels should be displayed when splitting up + tables by the above separator. + +.. config:option:: $cfg['NumRecentTables'] + + :type: integer + :default: 10 + + The maximum number of recently used tables shown in the navigation + panel. Set this to 0 (zero) to disable the listing of recent tables. + +.. config:option:: $cfg['NavigationDisplayLogo'] + + :type: boolean + :default: true + + Defines whether or not to display the phpMyAdmin logo at the top of + the navigation panel. + +.. config:option:: $cfg['NavigationLogoLink'] + + :type: string + :default: ``'index.php'`` + + Enter :term:`URL` where logo in the + navigation panel will point to. For use especially with self made + theme which changes this. + +.. config:option:: $cfg['NavigationLogoLinkWindow'] + + :type: string + :default: ``'main'`` + + Whether to open the linked page in the main window (``main``) or in a + new one (``new``). Note: use ``new`` if you are linking to + ``phpmyadmin.net``. + +.. config:option:: $cfg['NavigationTreeDisplayItemFilterMinimum'] + + :type: integer + :default: 30 + + Defines the minimum number of items (tables, views, routines and + events) to display a JavaScript filter box above the list of items in + the navigation tree. + + To disable the filter completely some high number can be used (e.g. 9999) + +.. config:option:: $cfg['NavigationTreeDisplayDbFilterMinimum'] + + :type: integer + :default: 30 + + Defines the minimum number of databases to display a JavaScript filter + box above the list of databases in the navigation tree. + + To disable the filter completely some high number can be used + (e.g. 9999) + +.. config:option:: $cfg['NavigationDisplayServers'] + + :type: boolean + :default: true + + Defines whether or not to display a server choice at the top of the + navigation panel. + +.. config:option:: $cfg['DisplayServersList'] + + :type: boolean + :default: false + + Defines whether to display this server choice as links instead of in a + drop-down. + +.. config:option:: $cfg['NavigationTreeDefaultTabTable'] + + :type: string + :default: ``'tbl_structure.php'`` + + Defines the tab displayed by default when clicking the small icon next + to each table name in the navigation panel. Possible values: + + * ``tbl_structure.php`` + * ``tbl_sql.php`` + * ``tbl_select.php`` + * ``tbl_change.php`` + * ``sql.php`` + +Main panel +---------- + +.. config:option:: $cfg['ShowStats'] + + :type: boolean + :default: true + + Defines whether or not to display space usage and statistics about + databases and tables. Note that statistics requires at least MySQL + 3.23.3 and that, at this date, MySQL doesn't return such information + for Berkeley DB tables. + +.. config:option:: $cfg['ShowServerInfo'] + + :type: boolean + :default: true + + Defines whether to display detailed server information on main page. + You can additionally hide more information by using + :config:option:`$cfg['Servers'][$i]['verbose']`. + +.. config:option:: $cfg['ShowPhpInfo'] + + :type: boolean + :default: false + +.. config:option:: $cfg['ShowChgPassword'] + + :type: boolean + :default: true + +.. config:option:: $cfg['ShowCreateDb'] + + :type: boolean + :default: true + + Defines whether to display the :guilabel:`PHP information` and + :guilabel:`Change password` links and form for creating database or not at + the starting main (right) frame. This setting does not check MySQL commands + entered directly. + + Please note that to block the usage of ``phpinfo()`` in scripts, you have to + put this in your :file:`php.ini`: + + .. code-block:: ini + + disable_functions = phpinfo() + + Also note that enabling the :guilabel:`Change password` link has no effect + with config authentication mode: because of the hard coded password value + in the configuration file, end users can't be allowed to change their + passwords. + +Database structure +------------------ + +.. config:option:: $cfg['ShowDbStructureCreation'] + + :type: boolean + :default: false + + Defines whether the database structure page (tables list) has a + "Creation" column that displays when each table was created. + +.. config:option:: $cfg['ShowDbStructureLastUpdate'] + + :type: boolean + :default: false + + Defines whether the database structure page (tables list) has a "Last + update" column that displays when each table was last updated. + +.. config:option:: $cfg['ShowDbStructureLastCheck'] + + :type: boolean + :default: false + + Defines whether the database structure page (tables list) has a "Last + check" column that displays when each table was last checked. + +.. config:option:: $cfg['HideStructureActions'] + + :type: boolean + :default: true + + Defines whether the table structure actions are hidden under a "More" + drop-down. + +Browse mode +----------- + +.. config:option:: $cfg['TableNavigationLinksMode'] + + :type: string + :default: ``'icons'`` + + Defines whether the table navigation links contain ``'icons'``, ``'text'`` + or ``'both'``. + +.. config:option:: $cfg['ShowAll'] + + :type: boolean + :default: false + + Defines whether a user should be displayed a "Show all" button in browse + mode or not in all cases. By default it is shown only on small tables (less + than 500 rows) to avoid performance issues while getting too many rows. + +.. config:option:: $cfg['MaxRows'] + + :type: integer + :default: 25 + + Number of rows displayed when browsing a result set and no LIMIT + clause is used. If the result set contains more rows, "Previous" and + "Next" links will be shown. Possible values: 25,50,100,250,500. + +.. config:option:: $cfg['Order'] + + :type: string + :default: ``'SMART'`` + + Defines whether columns are displayed in ascending (``ASC``) order, in + descending (``DESC``) order or in a "smart" (``SMART``) order - I.E. + descending order for columns of type TIME, DATE, DATETIME and + TIMESTAMP, ascending order else- by default. + +.. config:option:: $cfg['DisplayBinaryAsHex'] + + :type: boolean + :default: true + + Defines whether the "Show binary contents as HEX" browse option is + ticked by default. + +.. config:option:: $cfg['GridEditing'] + + :type: string + :default: ``'double-click'`` + + Defines which action (``double-click`` or ``click``) triggers grid + editing. Can be deactived with the ``disabled`` value. + +.. config:option:: $cfg['SaveCellsAtOnce'] + + :type: boolean + :default: false + + Defines whether or not to save all edited cells at once for grid + editing. + +Editing mode +------------ + +.. config:option:: $cfg['ProtectBinary'] + + :type: boolean or string + :default: ``'blob'`` + + Defines whether ``BLOB`` or ``BINARY`` columns are protected from + editing when browsing a table's content. Valid values are: + + * ``false`` to allow editing of all columns; + * ``'blob'`` to allow editing of all columns except ``BLOBS``; + * ``'noblob'`` to disallow editing of all columns except ``BLOBS`` (the + opposite of ``'blob'``); + * ``'all'`` to disallow editing of all ``BINARY`` or ``BLOB`` columns. + +.. config:option:: $cfg['ShowFunctionFields'] + + :type: boolean + :default: true + + Defines whether or not MySQL functions fields should be initially + displayed in edit/insert mode. Since version 2.10, the user can toggle + this setting from the interface. + +.. config:option:: $cfg['ShowFieldTypesInDataEditView'] + + :type: boolean + :default: true + + Defines whether or not type fields should be initially displayed in + edit/insert mode. The user can toggle this setting from the interface. + +.. config:option:: $cfg['InsertRows'] + + :type: integer + :default: 2 + + Defines the maximum number of concurrent entries for the Insert page. + +.. config:option:: $cfg['ForeignKeyMaxLimit'] + + :type: integer + :default: 100 + + If there are fewer items than this in the set of foreign keys, then a + drop-down box of foreign keys is presented, in the style described by + the :config:option:`$cfg['ForeignKeyDropdownOrder']` setting. + +.. config:option:: $cfg['ForeignKeyDropdownOrder'] + + :type: array + :default: array('content-id', 'id-content') + + For the foreign key drop-down fields, there are several methods of + display, offering both the key and value data. The contents of the + array should be one or both of the following strings: ``content-id``, + ``id-content``. + +Export and import settings +-------------------------- + +.. config:option:: $cfg['ZipDump'] + + :type: boolean + :default: true + +.. config:option:: $cfg['GZipDump'] + + :type: boolean + :default: true + +.. config:option:: $cfg['BZipDump'] + + :type: boolean + :default: true + + Defines whether to allow the use of zip/GZip/BZip2 compression when + creating a dump file + +.. config:option:: $cfg['CompressOnFly'] + + :type: boolean + :default: true + + Defines whether to allow on the fly compression for GZip/BZip2 + compressed exports. This doesn't affect smaller dumps and allows users + to create larger dumps that won't otherwise fit in memory due to php + memory limit. Produced files contain more GZip/BZip2 headers, but all + normal programs handle this correctly. + +.. config:option:: $cfg['Export'] + + :type: array + :default: array(...) + + In this array are defined default parameters for export, names of + items are similar to texts seen on export page, so you can easily + identify what they mean. + +.. config:option:: $cfg['Export']['method'] + + :type: string + :default: ``'quick'`` + + Defines how the export form is displayed when it loads. Valid values + are: + + * ``quick`` to display the minimum number of options to configure + * ``custom`` to display every available option to configure + * ``custom-no-form`` same as ``custom`` but does not display the option + of using quick export + + + +.. config:option:: $cfg['Import'] + + :type: array + :default: array(...) + + In this array are defined default parameters for import, names of + items are similar to texts seen on import page, so you can easily + identify what they mean. + + +Tabs display settings +--------------------- + +.. config:option:: $cfg['TabsMode'] + + :type: string + :default: ``'both'`` + + Defines whether the menu tabs contain ``'icons'``, ``'text'`` or ``'both'``. + +.. config:option:: $cfg['ActionLinksMode'] + + :type: string + :default: ``'both'`` + + If set to ``icons``, will display icons instead of text for db and table + properties links (like :guilabel:`Browse`, :guilabel:`Select`, + :guilabel:`Insert`, ...). Can be set to ``'both'`` + if you want icons AND text. When set to ``text``, will only show text. + +.. config:option:: $cfg['PropertiesNumColumns'] + + :type: integer + :default: 1 + + How many columns will be utilized to display the tables on the database + property view? When setting this to a value larger than 1, the type of the + database will be omitted for more display space. + +.. config:option:: $cfg['DefaultTabServer'] + + :type: string + :default: ``'index.php'`` + + Defines the tab displayed by default on server view. Possible values: + + * ``main.php`` (recommended for multi-user setups) + * ``server_databases.php``, + * ``server_status.php`` + * ``server_variables.php`` + * ``server_privileges.php`` + +.. config:option:: $cfg['DefaultTabDatabase'] + + :type: string + :default: ``'db_structure.php'`` + + Defines the tab displayed by default on database view. Possible + values: + + * ``db_structure.php`` + * ``db_sql.php`` + * ``db_search.php``. + +.. config:option:: $cfg['DefaultTabTable'] + + :type: string + :default: ``'sql.php'`` + + Defines the tab displayed by default on table view. Possible values: + + * ``tbl_structure.php`` + * ``tbl_sql.php`` + * ``tbl_select.php`` + * ``tbl_change.php`` + * ``sql.php`` + +PDF Options +----------- + +.. config:option:: $cfg['PDFPageSizes'] + + :type: array + :default: ``array('A3', 'A4', 'A5', 'letter', 'legal')`` + + Array of possible paper sizes for creating PDF pages. + + You should never need to change this. + +.. config:option:: $cfg['PDFDefaultPageSize'] + + :type: string + :default: ``'A4'`` + + Default page size to use when creating PDF pages. Valid values are any + listed in :config:option:`$cfg['PDFPageSizes']`. + +Languages +--------- + +.. config:option:: $cfg['DefaultLang'] + + :type: string + :default: ``'en'`` + + Defines the default language to use, if not browser-defined or user- + defined. The corresponding language file needs to be in + locale/*code*/LC\_MESSAGES/phpmyadmin.mo. + +.. config:option:: $cfg['DefaultConnectionCollation'] + + :type: string + :default: ``'utf8_general_ci'`` + + Defines the default connection collation to use, if not user-defined. + See the `MySQL documentation `_ for list of possible values. This setting is + ignored when connected to Drizzle server. + +.. config:option:: $cfg['Lang'] + + :type: string + :default: not set + + Force language to use. The corresponding language file needs to be in + locale/*code*/LC\_MESSAGES/phpmyadmin.mo. + +.. config:option:: $cfg['FilterLanguages'] + + :type: string + :default: ``''`` + + Limit list of available languages to those matching the given regular + expression. For example if you want only Czech and English, you should + set filter to ``'^(cs|en)'``. + +.. config:option:: $cfg['RecodingEngine'] + + :type: string + :default: ``'auto'`` + + You can select here which functions will be used for character set + conversion. Possible values are: + + * auto - automatically use available one (first is tested iconv, then + recode) + * iconv - use iconv or libiconv functions + * recode - use recode\_string function + * mb - use mbstring extension + * none - disable encoding conversion + + Enabled charset conversion activates a pull-down menu in the Export + and Import pages, to choose the character set when exporting a file. + The default value in this menu comes from + :config:option:`$cfg['Export']['charset']` and :config:option:`$cfg['Import']['charset']`. + +.. config:option:: $cfg['IconvExtraParams'] + + :type: string + :default: ``'//TRANSLIT'`` + + Specify some parameters for iconv used in charset conversion. See + `iconv documentation `_ for details. By default + ``//TRANSLIT`` is used, so that invalid characters will be + transliterated. + +.. config:option:: $cfg['AvailableCharsets'] + + :type: array + :default: array(..._ + + Available character sets for MySQL conversion. You can add your own + (any of supported by recode/iconv) or remove these which you don't + use. Character sets will be shown in same order as here listed, so if + you frequently use some of these move them to the top. + +Web server settings +------------------- + +.. config:option:: $cfg['OBGzip'] + + :type: string/boolean + :default: ``'auto'`` + + Defines whether to use GZip output buffering for increased speed in + :term:`HTTP` transfers. Set to + true/false for enabling/disabling. When set to 'auto' (string), + phpMyAdmin tries to enable output buffering and will automatically + disable it if your browser has some problems with buffering. IE6 with + a certain patch is known to cause data corruption when having enabled + buffering. + +.. config:option:: $cfg['TrustedProxies'] + + :type: array + :default: array() + + Lists proxies and HTTP headers which are trusted for + :config:option:`$cfg['Servers'][$i]['AllowDeny']['order']`. This list is by + default empty, you need to fill in some trusted proxy servers if you + want to use rules for IP addresses behind proxy. + + The following example specifies that phpMyAdmin should trust a + HTTP\_X\_FORWARDED\_FOR (``X -Forwarded-For``) header coming from the proxy + 1.2.3.4: + + .. code-block:: php + + $cfg['TrustedProxies'] = array('1.2.3.4' => 'HTTP_X_FORWARDED_FOR'); + + The :config:option:`$cfg['Servers'][$i]['AllowDeny']['rules']` directive uses the + client's IP address as usual. + +.. config:option:: $cfg['GD2Available'] + + :type: string + :default: ``'auto'`` + + Specifies whether GD >= 2 is available. If yes it can be used for MIME + transformations. Possible values are: + + * auto - automatically detect + * yes - GD 2 functions can be used + * no - GD 2 function cannot be used + +.. config:option:: $cfg['CheckConfigurationPermissions'] + + :type: boolean + :default: true + + We normally check the permissions on the configuration file to ensure + it's not world writable. However, phpMyAdmin could be installed on a + NTFS filesystem mounted on a non-Windows server, in which case the + permissions seems wrong but in fact cannot be detected. In this case a + sysadmin would set this parameter to ``false``. + +.. config:option:: $cfg['LinkLengthLimit'] + + :type: integer + :default: 1000 + + Limit for length of :term:`URL` in links. When length would be above this + limit, it is replaced by form with button. This is required as some web + servers (:term:`IIS`) have problems with long :term:`URL` . + +.. config:option:: $cfg['CSPAllow'] + + :type: string + :default: ``''`` + + Additional string to include in allowed script and image sources in Content + Security Policy header. + + This can be useful when you want to include some external javascript files + in :file:`config.footer.inc.php` or :file:`config.header.inc.php`, which + would be normally not allowed by Content Security Policy. + + To allow some sites, just list them within the string: + + .. code-block:: php + + $cfg['CSPAllow'] = 'example.com example.net'; + + .. versionadded:: 4.0.4 + +.. config:option:: $cfg['DisableMultiTableMaintenance'] + + :type: boolean + :default: false + + In the database Structure page, it's possible to mark some tables then + choose an operation like optimizing for many tables. This can slow + down a server; therefore, setting this to ``true`` prevents this kind + of multiple maintenance operation. + +Theme settings +-------------- + +.. config:option:: $cfg['NaviWidth'] + + :type: integer + :default: + + Navigation panel width in pixels. See + :file:`themes/themename/layout.inc.php`. + +.. config:option:: $cfg['NaviBackground'] + + :type: string [CSS color for background] + :default: + +.. config:option:: $cfg['MainBackground'] + + :type: string [CSS color for background] + :default: + + The background styles used for both the frames. See + :file:`themes/themename/layout.inc.php`. + +.. config:option:: $cfg['NaviPointerBackground'] + + :type: string [CSS color for background] + :default: + +.. config:option:: $cfg['NaviPointerColor'] + + :type: string [CSS color] + :default: + + The style used for the pointer in the navigation panel. See + :file:`themes/themename/layout.inc.php`. + +.. config:option:: $cfg['Border'] + + :type: integer + :default: + + The size of a table's border. See :file:`themes/themename/layout.inc.php`. + +.. config:option:: $cfg['ThBackground'] + + :type: string [CSS color for background] + :default: + +.. config:option:: $cfg['ThColor'] + + :type: string [CSS color] + :default: + + The style used for table headers. See + :file:`themes/themename/layout.inc.php`. + +.. _cfg_BgcolorOne: +.. config:option:: $cfg['BgOne'] + + :type: string [CSS color] + :default: + + The color (HTML) #1 for table rows. See + :file:`themes/themename/layout.inc.php`. + +.. _cfg_BgcolorTwo: +.. config:option:: $cfg['BgTwo'] + + :type: string [CSS color] + :default: + + The color (HTML) #2 for table rows. See + :file:`themes/themename/layout.inc.php`. + +.. config:option:: $cfg['BrowsePointerBackground'] + + :type: string [CSS color] + :default: + +.. config:option:: $cfg['BrowsePointerColor'] + + :type: string [CSS color] + :default: + +.. config:option:: $cfg['BrowseMarkerBackground'] + + :type: string [CSS color] + :default: + +.. config:option:: $cfg['BrowseMarkerColor'] + + :type: string [CSS color] + :default: + + The colors (HTML) uses for the pointer and the marker in browse mode. + The former feature highlights the row over which your mouse is passing + and the latter lets you visually mark/unmark rows by clicking on the + corresponding checkbox. Highlighting / marking a column is done by + hovering over / clicking the column's header (outside of the text). + See :file:`themes/themename/layout.inc.php`. + +.. config:option:: $cfg['FontFamily'] + + :type: string + :default: + + You put here a valid CSS font family value, for example ``arial, sans- + serif``. See :file:`themes/themename/layout.inc.php`. + +.. config:option:: $cfg['FontFamilyFixed'] + + :type: string + :default: + + You put here a valid CSS font family value, for example ``monospace``. + This one is used in textarea. See :file:`themes/themename/layout.inc.php`. + +Design customization +-------------------- + +.. config:option:: $cfg['NavigationTreePointerEnable'] + + :type: boolean + :default: true + + A value of ``true`` activates the navi pointer. + +.. config:option:: $cfg['BrowsePointerEnable'] + + :type: boolean + :default: true + + Whether to activate the browse pointer or not. + +.. config:option:: $cfg['BrowseMarkerEnable'] + + :type: boolean + :default: true + + Whether to activate the browse marker or not. + +.. config:option:: $cfg['LimitChars'] + + :type: integer + :default: 50 + + Maximum number of characters shown in any non-numeric field on browse + view. Can be turned off by a toggle button on the browse page. + +.. config:option:: $cfg['RowActionLinks'] + + :type: string + :default: ``'left'`` + + Defines the place where table row links (Edit, Copy, Delete) would be + put when tables contents are displayed (you may have them displayed at + the left side, right side, both sides or nowhere). "left" and "right" + are parsed as "top" and "bottom" with vertical display mode. + +.. config:option:: $cfg['DefaultDisplay'] + + :type: string + :default: ``'horizonta'`` + + There are 3 display modes: horizontal, horizontalflipped and vertical. + Define which one is displayed by default. The first mode displays each + row on a horizontal line, the second rotates the headers by 90 + degrees, so you can use descriptive headers even though columns only + contain small values and still print them out. The vertical mode sorts + each row on a vertical lineup. + +.. config:option:: $cfg['RememberSorting'] + + :type: boolean + :default: true + + If enabled, remember the sorting of each table when browsing them. + +.. config:option:: $cfg['HeaderFlipType'] + + :type: string + :default: ``'auto'`` + + The HeaderFlipType can be set to 'auto', 'css' or 'fake'. When using + 'css' the rotation of the header for horizontalflipped is done via + CSS. The CSS transformation currently works only in Internet + Explorer.If set to 'fake' PHP does the transformation for you, but of + course this does not look as good as CSS. The 'auto' option enables + CSS transformation when browser supports it and use PHP based one + otherwise. + +.. config:option:: $cfg['ShowBrowseComments'] + + :type: boolean + :default: true + +.. config:option:: $cfg['ShowPropertyComments'] + + :type: boolean + :default: true + + By setting the corresponding variable to ``true`` you can enable the + display of column comments in Browse or Property display. In browse + mode, the comments are shown inside the header. In property mode, + comments are displayed using a CSS-formatted dashed-line below the + name of the column. The comment is shown as a tool-tip for that + column. + +Text fields +----------- + +.. config:option:: $cfg['CharEditing'] + + :type: string + :default: ``'input'`` + + Defines which type of editing controls should be used for CHAR and + VARCHAR columns. Possible values are: + + * input - this allows to limit size of text to size of columns in MySQL, + but has problems with newlines in columns + * textarea - no problems with newlines in columns, but also no length + limitations + +.. config:option:: $cfg['MinSizeForInputField'] + + :type: integer + :default: 4 + + Defines the minimum size for input fields generated for CHAR and + VARCHAR columns. + +.. config:option:: $cfg['MaxSizeForInputField'] + + :type: integer + :default: 60 + + Defines the maximum size for input fields generated for CHAR and + VARCHAR columns. + +.. config:option:: $cfg['TextareaCols'] + + :type: integer + :default: 40 + +.. config:option:: $cfg['TextareaRows'] + + :type: integer + :default: 15 + +.. config:option:: $cfg['CharTextareaCols'] + + :type: integer + :default: 40 + +.. config:option:: $cfg['CharTextareaRows'] + + :type: integer + :default: 2 + + Number of columns and rows for the textareas. This value will be + emphasized (\*2) for :term:`SQL` query + textareas and (\*1.25) for :term:`SQL` + textareas inside the query window. + + The Char\* values are used for CHAR + and VARCHAR editing (if configured via :config:option:`$cfg['CharEditing']`). + +.. config:option:: $cfg['LongtextDoubleTextarea'] + + :type: boolean + :default: true + + Defines whether textarea for LONGTEXT columns should have double size. + +.. config:option:: $cfg['TextareaAutoSelect'] + + :type: boolean + :default: false + + Defines if the whole textarea of the query box will be selected on + click. + + +SQL query box settings +---------------------- + +.. config:option:: $cfg['SQLQuery']['Edit'] + + :type: boolean + :default: true + + Whether to display an edit link to change a query in any SQL Query + box. + +.. config:option:: $cfg['SQLQuery']['Explain'] + + :type: boolean + :default: true + + Whether to display a link to explain a SELECT query in any SQL Query + box. + +.. config:option:: $cfg['SQLQuery']['ShowAsPHP'] + + :type: boolean + :default: true + + Whether to display a link to wrap a query in PHP code in any SQL Query + box. + +.. config:option:: $cfg['SQLQuery']['Validate'] + + :type: boolean + :default: false + + Whether to display a link to validate a query in any SQL Query box. + + .. seealso:: :config:option:`$cfg['SQLValidator']` + +.. config:option:: $cfg['SQLQuery']['Refresh'] + + :type: boolean + :default: true + + Whether to display a link to refresh a query in any SQL Query box. + +Web server upload/save/import directories +----------------------------------------- + +.. config:option:: $cfg['UploadDir'] + + :type: string + :default: ``''`` + + The name of the directory where :term:`SQL` files have been uploaded by + other means than phpMyAdmin (for example, ftp). Those files are available + under a drop-down box when you click the database or table name, then the + Import tab. + + If + you want different directory for each user, %u will be replaced with + username. + + Please note that the file names must have the suffix ".sql" + (or ".sql.bz2" or ".sql.gz" if support for compressed formats is + enabled). + + This feature is useful when your file is too big to be + uploaded via :term:`HTTP`, or when file + uploads are disabled in PHP. + + .. note:: + + If PHP is running in safe mode, this directory must be owned by the same + user as the owner of the phpMyAdmin scripts. See also :ref:`faq1_16` for + alternatives. + +.. config:option:: $cfg['SaveDir'] + + :type: string + :default: ``''`` + + The name of the directory where dumps can be saved. + + If you want different directory for each user, %u will be replaced with + username. + + Please note that the directory must exist and has to be writable for + the user running webserver. + + .. note:: + + If PHP is running in safe mode, this directory must be owned by the same + user as the owner of the phpMyAdmin scripts. + +.. config:option:: $cfg['TempDir'] + + :type: string + :default: ``''`` + + The name of the directory where temporary files can be stored. + + This is needed for importing ESRI Shapefiles, see :ref:`faq6_30` and to + work around limitations of ``open_basedir`` for uploaded files, see + :ref:`faq1_11`. + + If the directory where phpMyAdmin is installed is + subject to an ``open_basedir`` restriction, you need to create a + temporary directory in some directory accessible by the web server. + However for security reasons, this directory should be outside the + tree published by webserver. If you cannot avoid having this directory + published by webserver, place at least an empty :file:`index.html` file + there, so that directory listing is not possible. + + This directory should have as strict permissions as possible as the only + user required to access this directory is the one who runs the webserver. + If you have root privileges, simply make this user owner of this directory + and make it accessible only by it: + + .. code-block:: sh + + + chown www-data:www-data tmp + chmod 700 tmp + + If you cannot change owner of the directory, you can achieve a similar + setup using :term:`ACL`: + + .. code-block:: sh + + chmod 700 tmp + setfacl -m "g:www-data:rwx" tmp + setfacl -d -m "g:www-data:rwx" tmp + + If neither of above works for you, you can still make the directory + :command:`chmod 777`, but it might impose risk of other users on system + reading and writing data in this directory. + +Various display setting +----------------------- + +.. config:option:: $cfg['ShowDisplayDirection'] + + :type: boolean + :default: false + + Defines whether or not type display direction option is shown when + browsing a table. + +.. config:option:: $cfg['RepeatCells'] + + :type: integer + :default: 100 + + Repeat the headers every X cells, or 0 to deactivate. + +.. config:option:: $cfg['EditInWindow'] + + :type: boolean + :default: true + +.. config:option:: $cfg['QueryWindowWidth'] + + :type: integer + :default: 550 + +.. config:option:: $cfg['QueryWindowHeight'] + + :type: integer + :default: 310 + +.. config:option:: $cfg['QueryHistoryDB'] + + :type: boolean + :default: false + +.. config:option:: $cfg['QueryWindowDefTab'] + + :type: string + :default: ``'sql'`` + +.. config:option:: $cfg['QueryHistoryMax'] + + :type: integer + :default: 25 + + All those variables affect the query window feature. A :term:`SQL` link or + icon is always displayed in the navigation panel. If JavaScript is enabled + in your browser, a click on this opens a distinct query window, which is a + direct interface to enter :term:`SQL` queries. Otherwise, the right panel + changes to display a query box. + + The size of this query window can be customized with + :config:option:`$cfg['QueryWindowWidth']` and + :config:option:`$cfg['QueryWindowHeight']` - both integers for the size in + pixels. Note that normally, those parameters will be modified in + :file:`layout.inc.php`` for the theme you are using. + + If :config:option:`$cfg['EditInWindow']` is set to true, a click on [Edit] + from the results page (in the :guilabel:`Showing Rows` section) opens the + query window and puts the current query inside it. If set to false, + clicking on the link puts the :term:`SQL` query + in the right panel's query box. + + If :config:option:`$cfg['QueryHistoryDB']` is set to ``true``, all your + Queries are logged to a table, which has to be created by you (see + :config:option:`$cfg['Servers'][$i]['history']`). If set to false, all your + queries will be appended to the form, but only as long as your window is + opened they remain saved. + + When using the JavaScript based query window, it will always get updated + when you click on a new table/db to browse and will focus if you click on + :guilabel:`Edit SQL` after using a query. You can suppress updating the + query window by checking the box :guilabel:`Do not overwrite this query + from outside the window` below the query textarea. Then you can browse + tables/databases in the background without losing the contents of the + textarea, so this is especially useful when composing a query with tables + you first have to look in. The checkbox will get automatically checked + whenever you change the contents of the textarea. Please uncheck the button + whenever you definitely want the query window to get updated even though + you have made alterations. + + If :config:option:`$cfg['QueryHistoryDB']` is set to ``true`` you can + specify the amount of saved history items using + :config:option:`$cfg['QueryHistoryMax']`. + + The query window also has a custom tabbed look to group the features. + Using the variable :config:option:`$cfg['QueryWindowDefTab']` you can + specify the default tab to be used when opening the query window. It can be + set to either ``sql``, ``files``, ``history`` or ``full``. + +.. config:option:: $cfg['BrowseMIME'] + + :type: boolean + :default: true + + Enable :ref:`transformations`. + +.. config:option:: $cfg['MaxExactCount'] + + :type: integer + :default: 0 + + For InnoDB tables, determines for how large tables phpMyAdmin should + get the exact row count using ``SELECT COUNT``. If the approximate row + count as returned by ``SHOW TABLE STATUS`` is smaller than this value, + ``SELECT COUNT`` will be used, otherwise the approximate count will be + used. + +.. config:option:: $cfg['MaxExactCountViews'] + + :type: integer + :default: 0 + + For VIEWs, since obtaining the exact count could have an impact on + performance, this value is the maximum to be displayed, using a + ``SELECT COUNT ... LIMIT``. Setting this to 0 bypasses any row + counting. + +.. config:option:: $cfg['NaturalOrder'] + + :type: boolean + :default: true + + Sorts database and table names according to natural order (for + example, t1, t2, t10). Currently implemented in the navigation panel + and in Database view, for the table list. + +.. config:option:: $cfg['InitialSlidersState'] + + :type: string + :default: ``'closed'`` + + If set to ``'closed'``, the visual sliders are initially in a closed + state. A value of ``'open'`` does the reverse. To completely disable + all visual sliders, use ``'disabled'``. + +.. config:option:: $cfg['UserprefsDisallow'] + + :type: array + :default: array() + + Contains names of configuration options (keys in ``$cfg`` array) that + users can't set through user preferences. For possible values, refer + to :file:`libraries/config/user_preferences.forms.php`. + +.. config:option:: $cfg['UserprefsDeveloperTab'] + + :type: boolean + :default: false + + Activates in the user preferences a tab containing options for + developers of phpMyAdmin. + +Page titles +----------- + +.. config:option:: $cfg['TitleTable'] + + :type: string + :default: ``'@HTTP_HOST@ / @VSERVER@ / @DATABASE@ / @TABLE@ | @PHPMYADMIN@'`` + +.. config:option:: $cfg['TitleDatabase'] + + :type: string + :default: ``'@HTTP_HOST@ / @VSERVER@ / @DATABASE@ | @PHPMYADMIN@'`` + +.. config:option:: $cfg['TitleServer'] + + :type: string + :default: ``'@HTTP_HOST@ / @VSERVER@ | @PHPMYADMIN@'`` + +.. config:option:: $cfg['TitleDefault'] + + :type: string + :default: ``'@HTTP_HOST@ | @PHPMYADMIN@'`` + + Allows you to specify window's title bar. You can use :ref:`faq6_27`. + +Theme manager settings +---------------------- + +.. config:option:: $cfg['ThemePath'] + + :type: string + :default: ``'./themes'`` + + If theme manager is active, use this as the path of the subdirectory + containing all the themes. + +.. config:option:: $cfg['ThemeManager'] + + :type: boolean + :default: true + + Enables user-selectable themes. See :ref:`faqthemes`. + +.. config:option:: $cfg['ThemeDefault'] + + :type: string + :default: ``'pmahomme'`` + + The default theme (a subdirectory under :config:option:`$cfg['ThemePath']`). + +.. config:option:: $cfg['ThemePerServer'] + + :type: boolean + :default: false + + Whether to allow different theme for each server. + +Default queries +--------------- + +.. config:option:: $cfg['DefaultQueryTable'] + + :type: string + :default: ``'SELECT * FROM @TABLE@ WHERE 1'`` + +.. config:option:: $cfg['DefaultQueryDatabase'] + + :type: string + :default: ``''`` + + Default queries that will be displayed in query boxes when user didn't + specify any. You can use standard :ref:`faq6_27`. + +SQL validator settings +---------------------- + +.. config:option:: $cfg['SQLValidator'] + + :type: array + :default: array(...) + + + +.. config:option:: $cfg['SQLValidator']['use'] + + :type: boolean + :default: false + + phpMyAdmin now supports use of the `Mimer SQL Validator + `_ service, as originally + published on `Slashdot + `_. For + help in setting up your system to use the service, see the + :ref:`faqsqlvalidator`. + +.. config:option:: $cfg['SQLValidator']['username'] + + :type: string + :default: ``''`` + +.. config:option:: $cfg['SQLValidator']['password'] + + :type: string + :default: ``''`` + + The SOAP service allows you to log in with ``anonymous`` and any password, + so we use those by default. Instead, if you have an account with them, you + can put your login details here, and it will be used in place of the + anonymous login. + +MySQL settings +-------------- + +.. config:option:: $cfg['DefaultFunctions'] + + :type: array + :default: array(...) + + Functions selected by default when inserting/changing row, Functions + are defined for meta types as (FUNC\_NUMBER, FUNC\_DATE, FUNC\_CHAR, + FUNC\_SPATIAL, FUNC\_UUID) and for ``first_timestamp``, which is used + for first timestamp column in table. + + +Developer +--------- + +.. warning:: + + These settings might have huge effect on performance or security. + +.. config:option:: $cfg['DBG'] + + :type: array + :default: array(...) + +.. config:option:: $cfg['DBG']['sql'] + + :type: boolean + :default: false + + Enable logging queries and execution times to be + displayed in the bottom of main page (right frame). + +.. config:option:: $cfg['DBG']['demo'] + + :type: boolean + :default: false + + Enable to let server present itself as demo server. + This is used for . + +.. config:option:: $cfg['Error_Handler']['display'] + + :type: boolean + :default: false + + Whether to display errors from PHP or not. + diff --git a/phpMyAdmin/doc/copyright.rst b/phpMyAdmin/doc/copyright.rst new file mode 100644 index 0000000..cfcb863 --- /dev/null +++ b/phpMyAdmin/doc/copyright.rst @@ -0,0 +1,30 @@ +.. _copyright: + +Copyright +========= + +.. code-block:: none + + Copyright (C) 1998-2000 Tobias Ratschiller + Copyright (C) 2001-2013 Marc Delisle + Olivier Müller + Robin Johnson + Alexander M. Turek + Michal ÄŒihaÅ™ + Garvin Hicking + Michael Keck + Sebastian Mendel + [check credits for more details] + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2, as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see `http://www.gnu.org/licenses/ +`_. diff --git a/phpMyAdmin/doc/credits.rst b/phpMyAdmin/doc/credits.rst new file mode 100644 index 0000000..61c7758 --- /dev/null +++ b/phpMyAdmin/doc/credits.rst @@ -0,0 +1,626 @@ +.. _credits: + +Credits +======= + + +Credits, in chronological order ++++++++++++++++++++++++++++++++ + +* Tobias Ratschiller + + * creator of the phpmyadmin project + + * maintainer from 1998 to summer 2000 + +* Marc Delisle + + * multi-language version in December 1998 + + * various fixes and improvements + + * :term:`SQL` analyser (most of it) + + * current project maintainer + + * maintains content on our website + +* Olivier Müller + + * started SourceForge phpMyAdmin project in March 2001 + + * sync'ed different existing CVS trees with new features and bugfixes + + * multi-language improvements, dynamic language selection + + * many bugfixes and improvements + +* Loïc Chapeaux + + * rewrote and optimized javascript, DHTML and DOM stuff + + * rewrote the scripts so they fit the :term:`PEAR` coding standards and + generate XHTML1.0 and CSS2 compliant codes + + * improved the language detection system + + * many bugfixes and improvements + +* Robin Johnson + + * database maintenance controls + + * table type code + + * Host authentication :term:`IP` Allow/Deny + + * DB-based configuration (Not completed) + + * :term:`SQL` parser and pretty-printer + + * :term:`SQL` validator + + * many bugfixes and improvements + +* Armel Fauveau + + * bookmarks feature + + * multiple dump feature + + * gzip dump feature + + * zip dump feature + +* Geert Lund + + * various fixes + + * moderator of the phpMyAdmin former users forum at phpwizard.net + +* Korakot Chaovavanich + + * "insert as new row" feature + +* Pete Kelly + + * rewrote and fix dump code + + * bugfixes + +* Steve Alberty + + * rewrote dump code for PHP4 + + * mySQL table statistics + + * bugfixes + +* Benjamin Gandon + + * main author of the version 2.1.0.1 + + * bugfixes + +* Alexander M. Turek + + * MySQL 4.0 / 4.1 / 5.0 compatibility + + * abstract database interface (PMA\_DBI) with MySQLi support + + * privileges administration + + * :term:`XML` exports + + * various features and fixes + + * German language file updates + +* Mike Beck + + * automatic joins in QBE + + * links column in printview + + * Relation view + +* Michal ÄŒihaÅ™ + + * enhanced index creation/display feature + + * feature to use a different charset for HTML than for MySQL + + * improvements of export feature + + * various features and fixes + + * Czech language file updates + + * created current website for phpMyAdmin + +* Christophe Gesché from the "MySQL Form Generator for PHPMyAdmin" + (http://sf.net/projects/phpmysqlformgen/) + + * suggested the patch for multiple table printviews + +* Garvin Hicking + + * built the patch for vertical display of table rows + + * built the Javascript based Query window + :term:`SQL` history + + * Improvement of column/db comments + + * (MIME)-Transformations for columns + + * Use custom alias names for Databases in left frame + + * hierarchical/nested table display + + * :term:`PDF`-scratchboard for WYSIWYG- + distribution of :term:`PDF` relations + + * new icon sets + + * vertical display of column properties page + + * some bugfixes, features, support, German language additions + +* Yukihiro Kawada + + * japanese kanji encoding conversion feature + +* Piotr Roszatycki and Dan Wilson + + * the Cookie authentication mode + +* Axel Sander + + * table relation-links feature + +* Maxime Delorme + + * :term:`PDF` schema output, thanks also to + Olivier Plathey for the "FPDF" library (see ), Steven + Wittens for the "UFPDF" library (see ) and + Nicola Asuni for the "TCPDF" library (see ). + +* Olof Edlund + + * :term:`SQL` validator server + +* Ivan R. Lanin + + * phpMyAdmin logo (until June 2004) + +* Mike Cochrane + + * blowfish library from the Horde project (withdrawn in release 4.0) + +* Marcel Tschopp + + * mysqli support + + * many bugfixes and improvements + +* Nicola Asuni (Tecnick.com) + + * TCPDF library (`http://www.tcpdf.org `_) + +* Michael Keck + + * redesign for 2.6.0 + + * phpMyAdmin sailboat logo (June 2004) + +* Mathias Landhäußer + + * Representation at conferences + +* Sebastian Mendel + + * interface improvements + + * various bugfixes + +* Ivan A Kirillov + + * new relations Designer + +* Raj Kissu Rajandran (Google Summer of Code 2008) + + * BLOBstreaming support (withdrawn in release 4.0) + +* Piotr Przybylski (Google Summer of Code 2008, 2010 and 2011) + + * improved setup script + + * user preferences + + * Drizzle support + +* Derek Schaefer (Google Summer of Code 2009) + + * Improved the import system + +* Alexander Rutkowski (Google Summer of Code 2009) + + * Tracking mechanism + +* Zahra Naeem (Google Summer of Code 2009) + + * Synchronization feature (removed in release 4.0) + +* Tomáš Srnka (Google Summer of Code 2009) + + * Replication support + +* Muhammad Adnan (Google Summer of Code 2010) + + * Relation schema export to multiple formats + +* Lori Lee (Google Summer of Code 2010) + + * User interface improvements + + * ENUM/SET editor + + * Simplified interface for export/import + +* Ninad Pundalik (Google Summer of Code 2010) + + * AJAXifying the interface + +* Martynas MickeviÄius (Google Summer of Code 2010) + + * Charts + +* Barrie Leslie + + * BLOBstreaming support with PBMS PHP extension (withdrawn in release + 4.0) + +* Ankit Gupta (Google Summer of Code 2010) + + * Visual query builder + +* Madhura Jayaratne (Google Summer of Code 2011) + + * OpenGIS support + +* Ammar Yasir (Google Summer of Code 2011) + + * Zoom search + +* Aris Feryanto (Google Summer of Code 2011) + + * Browse-mode improvements + +* Thilanka Kaushalya (Google Summer of Code 2011) + + * AJAXification + +* Tyron Madlener (Google Summer of Code 2011) + + * Query statistics and charts for the status page + +* Zarubin Stas (Google Summer of Code 2011) + + * Automated testing + +* Rouslan Placella (Google Summer of Code 2011 and 2012) + + * Improved support for Stored Routines, Triggers and Events + + * Italian translation updates + + * Removal of frames, new navigation + +* Dieter Adriaenssens + + * Various bugfixes + + * Dutch translation updates + +* Alex Marin (Google Summer of Code 2012) + + * New plugins and properties system + +* Thilina Buddika Abeyrathna (Google Summer of Code 2012) + + * Refactoring + +* Atul Pratap Singh (Google Summer of Code 2012) + + * Refactoring + +* Chanaka Indrajith (Google Summer of Code 2012) + + * Refactoring + +* Yasitha Pandithawatta (Google Summer of Code 2012) + + * Automated testing + +* Jim Wigginton (phpseclib.sourceforge.net) + + * phpseclib + +* Bin Zu (Google Summer of Code 2013) + + * Refactoring + +* Supun Nakandala (Google Summer of Code 2013) + + * Refactoring + +* Mohamed Ashraf (Google Summer of Code 2013) + + * AJAX error reporting + +* Adam Kang (Google Summer of Code 2013) + + * Automated testing + +* Ayush Chaudhary (Google Summer of Code 2013) + + * Automated testing + +* Kasun Chathuranga (Google Summer of Code 2013) + + * Interface 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: + +Bora Alioglu, Ricardo ?, Sven-Erik Andersen, Alessandro Astarita, +Péter Bakondy, Borges Botelho, Olivier Bussier, Neil Darlow, Mats +Engstrom, Ian Davidson, Laurent Dhima, Kristof Hamann, Thomas Kläger, +Lubos Klokner, Martin Marconcini, Girish Nair, David Nordenberg, +Andreas Pauley, Bernard M. Piller, Laurent Haas, "Sakamoto", Yuval +Sarna, www.securereality.com.au, Alexis Soulard, Alvar Soome, Siu Sun, +Peter Svec, Michael Tacelosky, Rachim Tamsjadi, Kositer Uros, Luís V., +Martijn W. van der Lee, Algis Vainauskas, Daniel Villanueva, Vinay, +Ignacio Vazquez-Abrams, Chee Wai, Jakub Wilk, Thomas Michael +Winningham, Vilius Zigmantas, "Manuzhai". + + +Translators ++++++++++++ + +Following people have contributed to translation of phpMyAdmin: + +* Arabic + + * Abdullah Al-Saedi + +* Bulgarian + + * stoyanster + +* Catalan + + * Xavier Navarro + +* Czech + + * Michal ÄŒihaÅ™ + +* Danish + + * opensource + * Jørgen Thomsen + +* German + + * mrbendig + * torsten.funck + * Sven Strickroth + * typo3 + * Jo Michael + +* Greek + + * Panagiotis Papazoglou + +* English (United Kingdom) + + * Robert Readman + +* Spanish + + * Matías Bellone + +* French + + * Marc Delisle + +* Hindi + + * u4663530 + * rsedwardian + +* Hungarian + + * gergo314 + +* Italian + + * Rouslan Placella + +* Japanese + + * Yuichiro + +* Lithuanian + + * KÄ™stutis + +* Norwegian BokmÃ¥l + + * Sven-Erik Andersen + +* Dutch + + * Dieter Adriaenssens + * Herman van Rink + +* Polish + + * StanisÅ‚aw Krukowski + * Marcin KozioÅ‚ + +* Portuguese + + * JoaoTMDias + +* Portuguese (Brazil) + + * wiltave + * emerson4br + +* Romanian + + * alexukf + +* Russian + + * Victor Volkov + +* Sinhala + + * Madhura Jayaratne + +* Slovak + + * Martin Lacina + +* Slovenian + + * Domen + +* Swedish + + * stefan + +* Tamil + + * ysajeepan + +* Telugu + + * veeven + +* Thai + + * kanitchet + +* Turkish + + * Burak Yavuz + +* Uighur + + * gheni + +* Ukrainian + + * typim + * oleg-ilnytskyi + +* Urdu + + * Mehbooob Khan + +* Simplified Chinese + + * shanyan baishui + +* Traditional Chinese + + * star + +Documentation translators ++++++++++++++++++++++++++ + +Following people have contributed to translation of phpMyAdmin documentation: + +* Czech + + * Michal ÄŒihaÅ™ + +* Greek + + * Panagiotis Papazoglou + +* English (United Kingdom) + + * Robert Readman + +* French + + * Cédric Corazza + +* Japanese + + * Yuichiro Takahashi + +* Polish + + * StanisÅ‚aw Krukowski + +* Portuguese (Brazil) + + * mjaning + +* Slovenian + + * Domen + +Original Credits of Version 2.1.0 ++++++++++++++++++++++++++++++++++ + +This work is based on Peter Kuppelwieser's MySQL-Webadmin. It was his +idea to create a web-based interface to MySQL using PHP3. Although I +have not used any of his source-code, there are some concepts I've +borrowed from him. phpMyAdmin was created because Peter told me he +wasn't going to further develop his (great) tool. + +Thanks go to + +* Amalesh Kempf who contributed the + code for the check when dropping a table or database. He also + suggested that you should be able to specify the primary key on + tbl\_create.php3. To version 1.1.1 he contributed the ldi\_\*.php3-set + (Import text-files) as well as a bug-report. Plus many smaller + improvements. +* Jan Legenhausen : He made many of the changes that + were introduced in 1.3.0 (including quite significant ones like the + authentication). For 1.4.1 he enhanced the table-dump feature. Plus + bug-fixes and help. +* Marc Delisle made phpMyAdmin + language-independent by outsourcing the strings to a separate file. He + also contributed the French translation. +* Alexandr Bravo who contributed + tbl\_select.php3, a feature to display only some columns from a table. +* Chris Jackson added support for MySQL functions + in tbl\_change.php3. He also added the "Query by Example" feature in + 2.0. +* Dave Walton added support for multiple + servers and is a regular contributor for bug-fixes. +* Gabriel Ash contributed the random access + features for 2.0.6. + +The following people have contributed minor changes, enhancements, +bugfixes or support for a new language: + +Jim Kraai, Jordi Bruguera, Miquel Obrador, Geert Lund, Thomas +Kleemann, Alexander Leidinger, Kiko Albiol, Daniel C. Chao, Pavel +Piankov, Sascha Kettler, Joe Pruett, Renato Lins, Mark Kronsbein, +Jannis Hermanns, G. Wieggers. + +And thanks to everyone else who sent me email with suggestions, bug- +reports and or just some feedback. + diff --git a/phpMyAdmin/doc/developers.rst b/phpMyAdmin/doc/developers.rst new file mode 100644 index 0000000..5574527 --- /dev/null +++ b/phpMyAdmin/doc/developers.rst @@ -0,0 +1,12 @@ +.. _developers: + +Developers Information +====================== + +phpMyAdmin is Open Source, so you're invited to contribute to it. Many +great features have been written by other people and you too can help +to make phpMyAdmin a useful tool. + +You can check out all the possibilities to contribute in the +`contribute section on our website +`_. \ No newline at end of file diff --git a/phpMyAdmin/doc/doctrees/config.doctree b/phpMyAdmin/doc/doctrees/config.doctree new file mode 100644 index 0000000000000000000000000000000000000000..4acf48f107e47ec0b209032e925366bf4f0769f1 GIT binary patch literal 802067 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ⅈ4LHIdx-!YMna1 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:Ro~oX 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 Szrf*LFYO@^Vr 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 literal 0 HcmV?d00001 diff --git a/phpMyAdmin/doc/doctrees/credits.doctree b/phpMyAdmin/doc/doctrees/credits.doctree new file mode 100644 index 0000000000000000000000000000000000000000..882133ecc557e7185b7e787be11c31aa03a8d1c6 GIT binary patch literal 119697 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 literal 0 HcmV?d00001 diff --git a/phpMyAdmin/doc/doctrees/developers.doctree b/phpMyAdmin/doc/doctrees/developers.doctree new file mode 100644 index 0000000000000000000000000000000000000000..87a3a196d9fd7a36e78fa86920be0441dbbfd708 GIT binary patch literal 4687 zcmdT|_nTB#8D^I)GXuN8QbGdAU6e2wb_Nnm2!;rf0Axt8>?2-45!pa$H&R z1Dnf&e(P~x6=-1Zc^XV;b&=(L%j2pQa!Er84Hst$t5&VD`5bqHkVle6rUz!WEcwWA z{6-LYmU050Mk_Ou__iMSDspPE;)djP{f(jj;>eiiHR&i$x#@wJZIE$IDo4Soz&CB) zkd#lTz{W!>lHByTlvWd-tf|skHeQdT2;Q0!cIuqQDy(4hdJttdk5|})6|0~T1j-K- zH>I*7MeC*q*r>+j*pk*Kw4o?Q^mAQ66JnHY>Aj!oN3&7n*kljOR2$1w;7`GasScJ+ zG0WA3f+jbw#nKDvDKcbye)H(!rwGC?>erTcw8-#i$tJvAAY>NWdj_#ftU; zx5W3v3d|O+G5!keRLvS}Nz@lf(a-+{F%ZMd! z#I8Q*mgx3AX7gQGbV9RxawT?0wCtMQM~I{UkASBk@FNpCr3KdDZ%qXjTEnI1pELG6)^^wB4K2cXL`h}Z>QsLpUE>ERi zX)5_#l||rjGeos7J6;$Cb6g*|`J7qmNhMN!9<`D_g^oUtE<&Iq_ZJF127H}K=nhTH z{k8@Kl}od!Tbl~RAj8>&9;5z&0&A zuA85vuu8=8bw{N`lBB3gGHqdNJJVF!brpuEu7|z3E3VSqB~47Wq~c!ZP=V&b{z5{n zOd}BaWSyaG*wtNadLRpe&Ip5Mh7OC)pLTon`XN1QvZ0fe+fLI{VjUe%P0Lb}(9^mW zpMGi1Zxajp@LiB#KO{H-D-oc~8rhU$?COm)yL3;&NN9kO_Bc?Y^U&-W2|Y8rW1C3Q z$Py>A02^NllAZ;vHO>nOJ-h4Gb1oleA;T#$gcnnUiwQlqYwLL{A-tdwJ|75gUlHMd zthXxye*u8MFrgQ9fG_p~7XZq2AcjGt5UDS&u$*JJN9mV9uCe~;ll0Omy^M`@!Yd28 zyAygjTkrU`6X_W&(?ilLs`N^hlUymsZ%TSqUtBdJtP9+?3ui4i#$H0N4(K%ry|&0E zI>B%1!BXoh>2+{pBTNU8je!}XhK&giU5Q>_VQZsC9Y?V{#F0yHVB6X?OSgSla=2=g zf~Z**%5%%~MwUm+*SR)LZ-UkFkcYjQQPP_$Y+Pc}4b6Js=|xG>Tadac(06p)c`F;n zH&Kh;#>QOBZ^r0hIB#=$I~&A4@D7%@Eyb~ocp<%0yO@$|rs+ZNnjU0p0Rvl*pY1X4 z##$pRSG5nkXL^{8wVh~B(C@8?BNeutM^O-&z#iCO)Xd%rOhhh(dmme`U6go4;6fKL z>HTcj=C!y<_f*(=?$t0AOVx6@6r3yiz#`j$jvvPAU)lU1k{E2%72OM$psgQ!=7O$i z^dYdf&W^p%>{by;9|l*LxEIj~v|B>e%#aq{15f27qMCKKKnj7)vpCYvgY+HnPpj`+D}f#_y(A zWn1^}6Z(T*RZG}AOJb8a7b6h+e^$vxia#dwCk!q7^rZ9WwArM?+48;|vwWxIO8QHc Y{+iB2db|HyLVp(%Rr-h6YQcW#pQd55-T(jq literal 0 HcmV?d00001 diff --git a/phpMyAdmin/doc/doctrees/environment.pickle b/phpMyAdmin/doc/doctrees/environment.pickle new file mode 100644 index 0000000000000000000000000000000000000000..29bcba82c479947c425401a69f5932ed1d5095fe GIT binary patch literal 224370 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 literal 0 HcmV?d00001 diff --git a/phpMyAdmin/doc/doctrees/faq.doctree b/phpMyAdmin/doc/doctrees/faq.doctree new file mode 100644 index 0000000000000000000000000000000000000000..6efeec3f676b3563f893d9ca3a571741481c8b8d GIT binary patch literal 556274 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 C{clMC literal 0 HcmV?d00001 diff --git a/phpMyAdmin/doc/doctrees/index.doctree b/phpMyAdmin/doc/doctrees/index.doctree new file mode 100644 index 0000000000000000000000000000000000000000..8a26ff86335b2ef16caead760f8c0770364b0ed3 GIT binary patch literal 5709 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 A;{X5v literal 0 HcmV?d00001 diff --git a/phpMyAdmin/doc/doctrees/intro.doctree b/phpMyAdmin/doc/doctrees/intro.doctree new file mode 100644 index 0000000000000000000000000000000000000000..e65bbcb1ef892587a89b9e96f6069d9bf4f4fd05 GIT binary patch literal 24029 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 literal 0 HcmV?d00001 diff --git a/phpMyAdmin/doc/doctrees/require.doctree b/phpMyAdmin/doc/doctrees/require.doctree new file mode 100644 index 0000000000000000000000000000000000000000..9992c697d986c545fc24b0ff8df2c022c2dab4a6 GIT binary patch literal 14973 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 AhyVZp literal 0 HcmV?d00001 diff --git a/phpMyAdmin/doc/doctrees/setup.doctree b/phpMyAdmin/doc/doctrees/setup.doctree new file mode 100644 index 0000000000000000000000000000000000000000..c1e83eeb97e7eaee01fd888cabfcc51b238aa18e GIT binary patch literal 134547 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 literal 0 HcmV?d00001 diff --git a/phpMyAdmin/doc/doctrees/user.doctree b/phpMyAdmin/doc/doctrees/user.doctree new file mode 100644 index 0000000000000000000000000000000000000000..cc07264432ea4b8c692bf6ee198fd62dae75b2ae GIT binary patch literal 2834 zcmbtW`Fk8k5mjUzyK7x`Y$srg+(v+7c({X>MGP51N z5 zl|pDEgH#$LhIrrhxkD>qsWoB*CNFg;`KU*oNQSuiOjUvZ9tr& z8Cn2Z;NrW~EG;zO@1Ay}WueO~4nbFkU$%V-Wb}4~?(OdG_J*wv;Wh2pf54|Bj;IHHen_nenjhPr_4$=*L6kI? z#F^xctyws0O3n|fSq0)=wK1JC3Y#F=SA(}lD&E{sr)mw5)4)@;2D<7lbwb^(POEjA zug$rq0QS)hb)T>9_tgWwdeB#A{Zb*OY9gJR4)l!NgYsT8?fo$@biU%(BCv9i9x3~x z>`y-q^R&pzEb8#%0D7U~i?FAeL&#ba6Mn*hd$Iw?ucK9)hgM6uxvND{NX@Sohar0t z#Fs)-s5sl}iYOX4O!KhAZ$QvDR{W+(&Sblxms&>rmMx&8Ij01E zD|Kq#Or9kpe%n6H4U@djZ{K&kfxR(}XHjn`RL7|IQ$D|A!`ohk0Ie388RR;xJIL^r z8~jeMX0g!mPMk>Bds{d7UEcOQ%yX*{@#+osBrT{oiqJ9d-lwHF3zHJfiwB0^v9X$X6-%oqAe9*tOAfKt2sD)q0LVUL3 z_tTmgrTsh!CYFY`ef|I)yRG}{*B|uxLv&)wJgEQmVV`|!hp}yP|A^0lD;F(I#!M~s zk7BAEAiOn@gwK5ktH`wl?$D!F95oXs!o*oVjK#3@c|gmPU}FHoiWRNJSrltbm;l3S zD6Qex=Z{g#NNeM4X!zQpt{Uh(vl2>uRwN~cE+;vs6=xfCd_qOwIvK#P8O{OYPPoo> zgvnaqoy<3ixL#>)3oN&GI*j8FhQF99L-0vUk>@YM{5#2=L$Q5ww08YKeJEk zd1;H%{x6@O#S#D;q2=cR3AIJz279i}_yw@H8kK1g9B9h$4RD2F8fSyNG5ee&c~|Jn z0fsLrQoiZYNyoeEGFP?0$`p9523M0!1d87${&C$14Dx~{N}kQ9>2&xqQ%K+@?*O6 z|1I~Q&?=^Z#a?qg1*$Fo^d_~3GLtxWP_&;R#ac+WsQo#b#wp~WuYW=JG<}UDqg#xu z%Cow!Be~OqrRni6>CEj!P4&mG)bq6BW?68HoL|#y9Pw`uAIs0J_@;)x-KW#z4#fRZ zj{(qURWLa;eg~a5bk{02{Cl5H)q0LI?6Ud>l$ona#D72w9L1T1CL4eFBR(wG86V8X zKY3-JPEJqv@!9w1t(oy9^OuVMs@BvA1Kk}yHplzqZx#Pttz+(E$Nr<<>-E~4oN+iz eaD?Fep!Q_K8vdux|Dpva6dX$buJ}J?zx!WsZWg8h literal 0 HcmV?d00001 diff --git a/phpMyAdmin/doc/doctrees/vendors.doctree b/phpMyAdmin/doc/doctrees/vendors.doctree new file mode 100644 index 0000000000000000000000000000000000000000..11a8b76f0fa21e6254a52615cd6a1b5b0c837a17 GIT binary patch literal 7769 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 on the official +phpMyAdmin homepage for in-depth coverage of phpMyAdmin's features and +or interface. + +.. _faqserver: + +Server +++++++ + +.. _faq1_1: + +1.1 My server is crashing each time a specific action is required or phpMyAdmin sends a blank page or a page full of cryptic characters to my browser, what can I do? +--------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +Try to set the :config:option:`$cfg['OBGzip']` directive to ``false`` in your +:file:`config.inc.php` file and the ``zlib.output_compression`` directive to +``Off`` in your php configuration file. + +.. _faq1_2: + +1.2 My Apache server crashes when using phpMyAdmin. +--------------------------------------------------- + +You should first try the latest versions of Apache (and possibly MySQL). If +your server keeps crashing, please ask for help in the various Apache support +groups. + +.. seealso:: :ref:`faq1_1` + +.. _faq1_3: + +1.3 (withdrawn). +---------------- + +.. _faq1_4: + +1.4 Using phpMyAdmin on IIS, I'm displayed the error message: "The specified CGI application misbehaved by not returning a complete set of HTTP headers ...". +------------------------------------------------------------------------------------------------------------------------------------------------------------- + +You just forgot to read the *install.txt* file from the PHP +distribution. Have a look at the last message in this `PHP bug report #12061 +`_ from the official PHP bug +database. + +.. _faq1_5: + +1.5 Using phpMyAdmin on IIS, I'm facing crashes and/or many error messages with the HTTP. +----------------------------------------------------------------------------------------- + +This is a known problem with the PHP :term:`ISAPI` filter: it's not so stable. +Please use instead the cookie authentication mode. + +.. _faq1_6: + +1.6 I can't use phpMyAdmin on PWS: nothing is displayed! +-------------------------------------------------------- + +This seems to be a PWS bug. Filippo Simoncini found a workaround (at +this time there is no better fix): remove or comment the ``DOCTYPE`` +declarations (2 lines) from the scripts :file:`libraries/Header.class.php` +and :file:`index.php`. + +.. _faq1_7: + +1.7 How can I GZip a dump or a CSV export? It does not seem to work. +-------------------------------------------------------------------- + +This feature is based on the ``gzencode()`` +PHP function to be more independent of the platform (Unix/Windows, +Safe Mode or not, and so on). So, you must have Zlib support +(``--with-zlib``). + +.. _faq1_8: + +1.8 I cannot insert a text file in a table, and I get an error about safe mode being in effect. +----------------------------------------------------------------------------------------------- + +Your uploaded file is saved by PHP in the "upload dir", as defined in +:file:`php.ini` by the variable ``upload_tmp_dir`` (usually the system +default is */tmp*). We recommend the following setup for Apache +servers running in safe mode, to enable uploads of files while being +reasonably secure: + +* create a separate directory for uploads: :command:`mkdir /tmp/php` +* give ownership to the Apache server's user.group: :command:`chown + apache.apache /tmp/php` +* give proper permission: :command:`chmod 600 /tmp/php` +* put ``upload_tmp_dir = /tmp/php`` in :file:`php.ini` +* restart Apache + +.. _faq1_9: + +1.9 (withdrawn). +---------------- + +.. _faq1_10: + +1.10 I'm having troubles when uploading files with phpMyAdmin running on a secure server. My browser is Internet Explorer and I'm using the Apache server. +---------------------------------------------------------------------------------------------------------------------------------------------------------- + +As suggested by "Rob M" in the phpWizard forum, add this line to your +*httpd.conf*: + +.. code-block:: apache + + SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown + +It seems to clear up many problems between Internet Explorer and SSL. + +.. _faq1_11: + +1.11 I get an 'open\_basedir restriction' while uploading a file from the query box. +------------------------------------------------------------------------------------ + +Since version 2.2.4, phpMyAdmin supports servers with open\_basedir +restrictions. However you need to create temporary directory and configure it +as :config:option:`$cfg['TempDir']`. The uploaded files will be moved there, +and after execution of your :term:`SQL` commands, removed. + +.. _faq1_12: + +1.12 I have lost my MySQL root password, what can I do? +------------------------------------------------------- + +The MySQL manual explains how to `reset the permissions +`_. + +.. _faq1_13: + +1.13 (withdrawn). +----------------- + +.. _faq1_14: + +1.14 (withdrawn). +----------------- + +.. _faq1_15: + +1.15 I have problems with *mysql.user* column names. +---------------------------------------------------- + +In previous MySQL versions, the ``User`` and ``Password``columns were +named ``user`` and ``password``. Please modify your column names to +align with current standards. + +.. _faq1_16: + +1.16 I cannot upload big dump files (memory, HTTP or timeout problems). +----------------------------------------------------------------------- + +Starting with version 2.7.0, the import engine has been re–written and +these problems should not occur. If possible, upgrade your phpMyAdmin +to the latest version to take advantage of the new import features. + +The first things to check (or ask your host provider to check) are the +values of ``upload_max_filesize``, ``memory_limit`` and +``post_max_size`` in the :file:`php.ini` configuration file. All of these +three settings limit the maximum size of data that can be submitted +and handled by PHP. One user also said that ``post_max_size`` and +``memory_limit`` need to be larger than ``upload_max_filesize``. +There exist several workarounds if your upload is too big or your +hosting provider is unwilling to change the settings: + +* Look at the :config:option:`$cfg['UploadDir']` feature. This allows one to upload a file to the server + via scp, ftp, or your favorite file transfer method. PhpMyAdmin is + then able to import the files from the temporary directory. More + information is available in the :ref:`config` of this document. +* Using a utility (such as `BigDump + `_) to split the files before + uploading. We cannot support this or any third party applications, but + are aware of users having success with it. +* If you have shell (command line) access, use MySQL to import the files + directly. You can do this by issuing the "source" command from within + MySQL: + + .. code-block:: mysql + + source filename.sql; + +.. _faq1_17: + +1.17 Which MySQL versions does phpMyAdmin support? +-------------------------------------------------- + +Since phpMyAdmin 3.0.x, only MySQL 5.0.1 and newer are supported. For +older MySQL versions, you need to use the latest 2.x branch. +phpMyAdmin can connect to your MySQL server using PHP's classic `MySQL +extension `_ as well as the `improved MySQL +extension (MySQLi) `_ that is available in PHP +5.0. The latter one should be used unless you have a good reason not +to do so. When compiling PHP, we strongly recommend that you manually +link the MySQL extension of your choice to a MySQL client library of +at least the same minor version since the one that is bundled with +some PHP distributions is rather old and might cause problems see +:ref:`faq1_17a`. `MariaDB `_ is also supported +(versions 5.1 and 5.2 were tested). + +.. versionchanged:: 3.5 + Since phpMyAdmin 3.5 `Drizzle `_ is supported. + +.. _faq1_17a: + +1.17a I cannot connect to the MySQL server. It always returns the error message, "Client does not support authentication protocol requested by server; consider upgrading MySQL client" +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +You tried to access MySQL with an old MySQL client library. The +version of your MySQL client library can be checked in your phpinfo() +output. In general, it should have at least the same minor version as +your server - as mentioned in :ref:`faq1_17`. This problem is +generally caused by using MySQL version 4.1 or newer. MySQL changed +the authentication hash and your PHP is trying to use the old method. +The proper solution is to use the `mysqli extension +`_ with the proper client library to match +your MySQL installation. Your chosen extension is specified in +:config:option:`$cfg['Servers'][$i]['extension']`. More +information (and several workarounds) are located in the `MySQL +Documentation `_. + +.. _faq1_18: + +1.18 (withdrawn). +----------------- + +.. _faq1_19: + +1.19 I can't run the "display relations" feature because the script seems not to know the font face I'm using! +-------------------------------------------------------------------------------------------------------------- + +The :term:`TCPDF` library we're using for this feature requires some special +files to use font faces. Please refers to the `TCPDF manual +`_ to build these files. + +.. _faqmysql: + +1.20 I receive the error "cannot load MySQL extension, please check PHP Configuration". +--------------------------------------------------------------------------------------- + +To connect to a MySQL server, PHP needs a set of MySQL functions +called "MySQL extension". This extension may be part of the PHP +distribution (compiled-in), otherwise it needs to be loaded +dynamically. Its name is probably *mysql.so* or *php\_mysql.dll*. +phpMyAdmin tried to load the extension but failed. Usually, the +problem is solved by installing a software package called "PHP-MySQL" +or something similar. + +There are currently two interfaces PHP provides as MySQL extensions - ``mysql`` +and ``mysqli`` and you can change which of then is being used by +:config:option:`$cfg['Servers'][$i]['extension']`. + +.. _faq1_21: + +1.21 I am running the CGI version of PHP under Unix, and I cannot log in using cookie auth. +------------------------------------------------------------------------------------------- + +In :file:`php.ini`, set ``mysql.max_links`` higher than 1. + +.. _faq1_22: + +1.22 I don't see the "Location of text file" field, so I cannot upload. +----------------------------------------------------------------------- + +This is most likely because in :file:`php.ini`, your ``file_uploads`` +parameter is not set to "on". + +.. _faq1_23: + +1.23 I'm running MySQL on a Win32 machine. Each time I create a new table the table and column names are changed to lowercase! +------------------------------------------------------------------------------------------------------------------------------ + +This happens because the MySQL directive ``lower_case_table_names`` +defaults to 1 (``ON``) in the Win32 version of MySQL. You can change +this behavior by simply changing the directive to 0 (``OFF``): Just +edit your ``my.ini`` file that should be located in your Windows +directory and add the following line to the group [mysqld]: + +.. code-block:: ini + + set-variable = lower_case_table_names=0 + +Next, save the file and restart the MySQL service. You can always +check the value of this directive using the query + +.. code-block:: mysql + + SHOW VARIABLES LIKE 'lower_case_table_names'; + +.. _faq1_24: + +1.24 (withdrawn). +----------------- + +.. _faq1_25: + +1.25 I am running Apache with mod\_gzip-1.3.26.1a on Windows XP, and I get problems, such as undefined variables when I run a SQL query. +---------------------------------------------------------------------------------------------------------------------------------------- + +A tip from Jose Fandos: put a comment on the following two lines in +httpd.conf, like this: + +.. code-block:: apache + + + # mod_gzip_item_include file \.php$ + # mod_gzip_item_include mime "application/x-httpd-php.*" + +as this version of mod\_gzip on Apache (Windows) has problems handling +PHP scripts. Of course you have to restart Apache. + +.. _faq1_26: + +1.26 I just installed phpMyAdmin in my document root of IIS but I get the error "No input file specified" when trying to run phpMyAdmin. +---------------------------------------------------------------------------------------------------------------------------------------- + +This is a permission problem. Right-click on the phpmyadmin folder and +choose properties. Under the tab Security, click on "Add" and select +the user "IUSR\_machine" from the list. Now set his permissions and it +should work. + +.. _faq1_27: + +1.27 I get empty page when I want to view huge page (eg. db\_structure.php with plenty of tables). +-------------------------------------------------------------------------------------------------- + +This was caused by a `PHP bug `_ that occur when +GZIP output buffering is enabled. If you turn off it (by +:config:option:`$cfg['OBGzip']` in :file:`config.inc.php`), it should work. +This bug will has been fixed in PHP 5.0.0. + +.. _faq1_28: + +1.28 My MySQL server sometimes refuses queries and returns the message 'Errorcode: 13'. What does this mean? +------------------------------------------------------------------------------------------------------------ + +This can happen due to a MySQL bug when having database / table names +with upper case characters although ``lower_case_table_names`` is +set to 1. To fix this, turn off this directive, convert all database +and table names to lower case and turn it on again. Alternatively, +there's a bug-fix available starting with MySQL 3.23.56 / +4.0.11-gamma. + +.. _faq1_29: + +1.29 When I create a table or modify a column, I get an error and the columns are duplicated. +--------------------------------------------------------------------------------------------- + +It is possible to configure Apache in such a way that PHP has problems +interpreting .php files. + +The problems occur when two different (and conflicting) set of +directives are used: + +.. code-block:: apache + + + SetOutputFilter PHP + SetInputFilter PHP + +and + +.. code-block:: apache + + AddType application/x-httpd-php .php + +In the case we saw, one set of directives was in +``/etc/httpd/conf/httpd.conf``, while the other set was in +``/etc/httpd/conf/addon-modules/php.conf``. The recommended way is +with ``AddType``, so just comment out the first set of lines and +restart Apache: + +.. code-block:: apache + + + #SetOutputFilter PHP + #SetInputFilter PHP + +.. _faq1_30: + +1.30 I get the error "navigation.php: Missing hash". +---------------------------------------------------- + +This problem is known to happen when the server is running Turck +MMCache but upgrading MMCache to version 2.3.21 solves the problem. + +.. _faq1_31: + +1.31 Does phpMyAdmin support PHP 5? +----------------------------------- + +Yes. + +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: + +1.32 Can I use HTTP authentication with IIS? +-------------------------------------------- + +Yes. This procedure was tested with phpMyAdmin 2.6.1, PHP 4.3.9 in +:term:`ISAPI` mode under :term:`IIS` 5.1. + +#. In your :file:`php.ini` file, set ``cgi.rfc2616_headers = 0`` +#. In ``Web Site Properties -> File/Directory Security -> Anonymous + Access`` dialog box, check the ``Anonymous access`` checkbox and + uncheck any other checkboxes (i.e. uncheck ``Basic authentication``, + ``Integrated Windows authentication``, and ``Digest`` if it's + enabled.) Click ``OK``. +#. In ``Custom Errors``, select the range of ``401;1`` through ``401;5`` + and click the ``Set to Default`` button. + +.. seealso:: :rfc:`2616` + +.. _faq1_33: + +1.33 (withdrawn). +----------------- + +.. _faq1_34: + +1.34 Can I access directly to database or table pages? +------------------------------------------------------ + +Yes. Out of the box, you can use :term:`URL` like +http://server/phpMyAdmin/index.php?server=X&db=database&table=table&target=script. +For ``server`` you use the server number +which refers to the order of the server paragraph in +:file:`config.inc.php`. Table and script parts are optional. If you want +http://server/phpMyAdmin/database[/table][/script] :term:`URL`, you need to do some configuration. Following +lines apply only for `Apache `_ web server. +First make sure, that you have enabled some features within global +configuration. You need ``Options FollowSymLinks`` and ``AllowOverride +FileInfo`` enabled for directory where phpMyAdmin is installed and you +need mod\_rewrite to be enabled. Then you just need to create +following :term:`.htaccess` file in root folder of phpMyAdmin installation (don't +forget to change directory name inside of it): + +.. code-block:: apache + + + RewriteEngine On + RewriteBase /path_to_phpMyAdmin + RewriteRule ^([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)/([a-z_]+\.php)$ index.php?db=$1&table=$2&target=$3 [R] + RewriteRule ^([a-zA-Z0-9_]+)/([a-z_]+\.php)$ index.php?db=$1&target=$2 [R] + RewriteRule ^([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)$ index.php?db=$1&table=$2 [R] + RewriteRule ^([a-zA-Z0-9_]+)$ index.php?db=$1 [R] + +.. _faq1_35: + +1.35 Can I use HTTP authentication with Apache CGI? +--------------------------------------------------- + +Yes. However you need to pass authentication variable to :term:`CGI` using +following rewrite rule: + +.. code-block:: apache + + + RewriteEngine On + RewriteRule .* - [E=REMOTE_USER:%{HTTP:Authorization},L] + +.. _faq1_36: + +1.36 I get an error "500 Internal Server Error". +------------------------------------------------ + +There can be many explanations to this and a look at your server's +error log file might give a clue. + +.. _faq1_37: + +1.37 I run phpMyAdmin on cluster of different machines and password encryption in cookie auth doesn't work. +----------------------------------------------------------------------------------------------------------- + +If your cluster consist of different architectures, PHP code used for +encryption/decryption won't work correct. This is caused by use of +pack/unpack functions in code. Only solution is to use mcrypt +extension which works fine in this case. + +.. _faq1_38: + +1.38 Can I use phpMyAdmin on a server on which Suhosin is enabled? +------------------------------------------------------------------ + +Yes but the default configuration values of Suhosin are known to cause +problems with some operations, for example editing a table with many +columns and no primary key or with textual primary key. + +Suhosin configuration might lead to malfunction in some cases and it +can not be fully avoided as phpMyAdmin is kind of application which +needs to transfer big amounts of columns in single HTTP request, what +is something what Suhosin tries to prevent. Generally all +``suhosin.request.*``, ``suhosin.post.*`` and ``suhosin.get.*`` +directives can have negative effect on phpMyAdmin usability. You can +always find in your error logs which limit did cause dropping of +variable, so you can diagnose the problem and adjust matching +configuration variable. + +The default values for most Suhosin configuration options will work in +most scenarios, however you might want to adjust at least following +parameters: + +* `suhosin.request.max\_vars `_ should + be increased (eg. 2048) +* `suhosin.post.max\_vars `_ should be + increased (eg. 2048) +* `suhosin.request.max\_array\_index\_length `_ + should be increased (eg. 256) +* `suhosin.post.max\_array\_index\_length `_ + should be increased (eg. 256) +* `suhosin.request.max\_totalname\_length `_ + should be increased (eg. 8192) +* `suhosin.post.max\_totalname\_length `_ should be + increased (eg. 8192) +* `suhosin.get.max\_value\_length `_ + should be increased (eg. 1024) +* `suhosin.sql.bailout\_on\_error `_ + needs to be disabled (the default) +* `suhosin.log.\* `_ should not + include :term:`SQL`, otherwise you get big + slowdown + +You can also disable the warning using the :config:option:`$cfg['SuhosinDisableWarning']`. + +.. _faq1_39: + +1.39 When I try to connect via https, I can log in, but then my connection is redirected back to http. What can cause this behavior? +------------------------------------------------------------------------------------------------------------------------------------ + +Be sure that you have enabled ``SSLOptions`` and ``StdEnvVars`` in +your Apache configuration. + +.. seealso:: + +.. _faq1_40: + +1.40 When accessing phpMyAdmin via an Apache reverse proxy, cookie login does not work. +--------------------------------------------------------------------------------------- + +To be able to use cookie auth Apache must know that it has to rewrite +the set-cookie headers. Example from the Apache 2.2 documentation: + +.. code-block:: apache + + + ProxyPass /mirror/foo/ http://backend.example.com/ + ProxyPassReverse /mirror/foo/ http://backend.example.com/ + ProxyPassReverseCookieDomain backend.example.com public.example.com + ProxyPassReverseCookiePath / /mirror/foo/ + +Note: if the backend url looks like http://host/~user/phpmyadmin, the +tilde (~) must be url encoded as %7E in the ProxyPassReverse\* lines. +This is not specific to phpmyadmin, it's just the behavior of Apache. + +.. code-block:: apache + + + ProxyPass /mirror/foo/ http://backend.example.com/~user/phpmyadmin + ProxyPassReverse /mirror/foo/ http://backend.example.com/%7Euser/phpmyadmin + ProxyPassReverseCookiePath /%7Euser/phpmyadmin /mirror/foo + +.. seealso:: + +.. _faq1_41: + +1.41 When I view a database and ask to see its privileges, I get an error about an unknown column. +-------------------------------------------------------------------------------------------------- + +The MySQL server's privilege tables are not up to date, you need to +run the :command:`mysql_upgrade` command on the server. + +.. _faq1_42: + +1.42 How can I prevent robots from accessing phpMyAdmin? +-------------------------------------------------------- + +You can add various rules to :term:`.htaccess` to filter access based on user agent +field. This is quite easy to circumvent, but could prevent at least +some robots accessing your installation. + +.. code-block:: apache + + + RewriteEngine on + + # Allow only GET and POST verbs + RewriteCond %{REQUEST_METHOD} !^(GET|POST)$ [NC,OR] + + # Ban Typical Vulnerability Scanners and others + # Kick out Script Kiddies + RewriteCond %{HTTP_USER_AGENT} ^(java|curl|wget).* [NC,OR] + RewriteCond %{HTTP_USER_AGENT} ^.*(libwww-perl|curl|wget|python|nikto|wkito|pikto|scan|acunetix).* [NC,OR] + RewriteCond %{HTTP_USER_AGENT} ^.*(winhttp|HTTrack|clshttp|archiver|loader|email|harvest|extract|grab|miner).* [NC,OR] + + # Ban Search Engines, Crawlers to your administrative panel + # No reasons to access from bots + # Ultimately Better than the useless robots.txt + # Did google respect robots.txt? + # Try google: intitle:phpMyAdmin intext:"Welcome to phpMyAdmin *.*.*" intext:"Log in" -wiki -forum -forums -questions intext:"Cookies must be enabled" + RewriteCond %{HTTP_USER_AGENT} ^.*(AdsBot-Google|ia_archiver|Scooter|Ask.Jeeves|Baiduspider|Exabot|FAST.Enterprise.Crawler|FAST-WebCrawler|www\.neomo\.de|Gigabot|Mediapartners-Google|Google.Desktop|Feedfetcher-Google|Googlebot|heise-IT-Markt-Crawler|heritrix|ibm.com\cs/crawler|ICCrawler|ichiro|MJ12bot|MetagerBot|msnbot-NewsBlogs|msnbot|msnbot-media|NG-Search|lucene.apache.org|NutchCVS|OmniExplorer_Bot|online.link.validator|psbot0|Seekbot|Sensis.Web.Crawler|SEO.search.Crawler|Seoma.\[SEO.Crawler\]|SEOsearch|Snappy|www.urltrends.com|www.tkl.iis.u-tokyo.ac.jp/~crawler|SynooBot|crawleradmin.t-info@telekom.de|TurnitinBot|voyager|W3.SiteSearch.Crawler|W3C-checklink|W3C_Validator|www.WISEnutbot.com|yacybot|Yahoo-MMCrawler|Yahoo\!.DE.Slurp|Yahoo\!.Slurp|YahooSeeker).* [NC] + RewriteRule .* - [F] + +.. _faq1_43: + +1.43 Why can't I display the structure of my table containing hundreds of columns? +---------------------------------------------------------------------------------- + +Because your PHP's ``memory_limit`` is too low; adjust it in :file:`php.ini`. + +.. _faqconfig: + +Configuration ++++++++++++++ + +.. _faq2_1: + +2.1 The error message "Warning: Cannot add header information - headers already sent by ..." is displayed, what's the problem? +------------------------------------------------------------------------------------------------------------------------------ + +Edit your :file:`config.inc.php` file and ensure there is nothing (I.E. no +blank lines, no spaces, no characters...) neither before the ```` tag at the end. We also got a report +from a user under :term:`IIS`, that used a zipped distribution kit: the file +:file:`libraries/Config.class.php` contained an end-of-line character (hex 0A) +at the end; removing this character cleared his errors. + +.. _faq2_2: + +2.2 phpMyAdmin can't connect to MySQL. What's wrong? +---------------------------------------------------- + +Either there is an error with your PHP setup or your username/password +is wrong. Try to make a small script which uses mysql\_connect and see +if it works. If it doesn't, it may be you haven't even compiled MySQL +support into PHP. + +.. _faq2_3: + +2.3 The error message "Warning: MySQL Connection Failed: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (111) ..." is displayed. What can I do? +--------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +For RedHat users, Harald Legner suggests this on the mailing list: + +On my RedHat-Box the socket of MySQL is */var/lib/mysql/mysql.sock*. +In your :file:`php.ini` you will find a line + +.. code-block:: ini + + mysql.default_socket = /tmp/mysql.sock + +change it to + +.. code-block:: ini + + mysql.default_socket = /var/lib/mysql/mysql.sock + +Then restart apache and it will work. + +Here is a fix suggested by Brad Ummer: + +* First, you need to determine what socket is being used by MySQL. To do + this, telnet to your server and go to the MySQL bin directory. In this + directory there should be a file named *mysqladmin*. Type + ``./mysqladmin variables``, and this should give you a bunch of info + about your MySQL server, including the socket (*/tmp/mysql.sock*, for + example). +* Then, you need to tell PHP to use this socket. To do this in + phpMyAdmin, you need to complete the socket information in the + :file:`config.inc.php`. For example: + :config:option:`$cfg['Servers'][$i]['socket']` Please also make sure that + the permissions of this file allow to be readable by your webserver (i.e. + '0755'). + +Have also a look at the `corresponding section of the MySQL +documentation `_. + +.. _faq2_4: + +2.4 Nothing is displayed by my browser when I try to run phpMyAdmin, what can I do? +----------------------------------------------------------------------------------- + +Try to set the :config:option:`$cfg['OBGzip']` directive to ``false`` in the phpMyAdmin configuration +file. It helps sometime. Also have a look at your PHP version number: +if it contains "b" or "alpha" it means you're running a testing +version of PHP. That's not a so good idea, please upgrade to a plain +revision. + +.. _faq2_5: + +2.5 Each time I want to insert or change a row or drop a database or a table, an error 404 (page not found) is displayed or, with HTTP or cookie authentication, I'm asked to log in again. What's wrong? +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +Check the value you set for the :config:option:`$cfg['PmaAbsoluteUri']` directive in the phpMyAdmin +configuration file. + +.. _faq2_6: + +2.6 I get an "Access denied for user: 'root@localhost' (Using password: YES)"-error when trying to access a MySQL-Server on a host which is port-forwarded for my localhost. +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +When you are using a port on your localhost, which you redirect via +port-forwarding to another host, MySQL is not resolving the localhost +as expected. Erik Wasser explains: The solution is: if your host is +"localhost" MySQL (the command line tool :command:`mysql` as well) always +tries to use the socket connection for speeding up things. And that +doesn't work in this configuration with port forwarding. If you enter +"127.0.0.1" as hostname, everything is right and MySQL uses the +:term:`TCP` connection. + +.. _faqthemes: + +2.7 Using and creating themes +----------------------------- + +Themes are configured with :config:option:`$cfg['ThemePath']`, +:config:option:`$cfg['ThemeManager']` and :config:option:`$cfg['ThemeDefault']`. +Under :config:option:`$cfg['ThemePath']`, you should not delete the +directory ``pmahomme`` or its underlying structure, because this is the +system theme used by phpMyAdmin. ``pmahomme`` contains all images and +styles, for backwards compatibility and for all themes that would not +include images or css-files. If :config:option:`$cfg['ThemeManager']` +is enabled, you can select your favorite theme on the main page. Your selected +theme will be stored in a cookie. + +To create a theme: + +* make a new subdirectory (for example "your\_theme\_name") under :config:option:`$cfg['ThemePath']` (by + default ``themes``) +* copy the files and directories from ``pmahomme`` to "your\_theme\_name" +* edit the css-files in "your\_theme\_name/css" +* put your new images in "your\_theme\_name/img" +* edit :file:`layout.inc.php` in "your\_theme\_name" +* edit :file:`info.inc.php` in "your\_theme\_name" to contain your chosen + theme name, that will be visible in user interface +* make a new screenshot of your theme and save it under + "your\_theme\_name/screen.png" + +In theme directory there is file :file:`info.inc.php` which contains theme +verbose name, theme generation and theme version. These versions and +generations are enumerated from 1 and do not have any direct +dependence on phpMyAdmin version. Themes within same generation should +be backwards compatible - theme with version 2 should work in +phpMyAdmin requiring version 1. Themes with different generation are +incompatible. + +If you do not want to use your own symbols and buttons, remove the +directory "img" in "your\_theme\_name". phpMyAdmin will use the +default icons and buttons (from the system-theme ``pmahomme``). + +.. _faqmissingparameters: + +2.8 I get "Missing parameters" errors, what can I do? +----------------------------------------------------- + +Here are a few points to check: + +* In :file:`config.inc.php`, try to leave the :config:option:`$cfg['PmaAbsoluteUri']` directive empty. See also + :ref:`faq4_7`. +* Maybe you have a broken PHP installation or you need to upgrade your + Zend Optimizer. See . +* If you are using Hardened PHP with the ini directive + ``varfilter.max_request_variables`` set to the default (200) or + another low value, you could get this error if your table has a high + number of columns. Adjust this setting accordingly. (Thanks to Klaus + Dorninger for the hint). +* In the :file:`php.ini` directive ``arg_separator.input``, a value of ";" + will cause this error. Replace it with "&;". +* If you are using `Hardened-PHP `_, you + might want to increase `request limits `_. +* The directory specified in the :file:`php.ini` directive + ``session.save_path`` does not exist or is read-only. + +.. _faq2_9: + +2.9 Seeing an upload progress bar +--------------------------------- + +To be able to see a progress bar during your uploads, your server must +have the `APC `_ extension, the +`uploadprogress `_ one, or +you must be running PHP 5.4.0 or higher. Moreover, the JSON extension +has to be enabled in your PHP. + +If using APC, you must set ``apc.rfc1867`` to ``on`` in your :file:`php.ini`. + +If using PHP 5.4.0 or higher, you must set +``session.upload_progress.enabled`` to ``1`` in your :file:`php.ini`. However, +starting from phpMyAdmin version 4.0.4, session-based upload progress has +been temporarily deactivated due to its problematic behavior. + +.. seealso:: :rfc:`1867` + +.. _faqlimitations: + +Known limitations ++++++++++++++++++ + +.. _login_bug: + +3.1 When using HTTP authentication, a user who logged out can not log in again in with the same nick. +----------------------------------------------------------------------------------------------------- + +This is related to the authentication mechanism (protocol) used by +phpMyAdmin. To bypass this problem: just close all the opened browser +windows and then go back to phpMyAdmin. You should be able to log in +again. + +.. _faq3_2: + +3.2 When dumping a large table in compressed mode, I get a memory limit error or a time limit error. +---------------------------------------------------------------------------------------------------- + +Compressed dumps are built in memory and because of this are limited +to php's memory limit. For GZip/BZip2 exports this can be overcome +since 2.5.4 using :config:option:`$cfg['CompressOnFly']` (enabled by default). +Zip exports can not be handled this way, so if you need Zip files for larger +dump, you have to use another way. + +.. _faq3_3: + +3.3 With InnoDB tables, I lose foreign key relationships when I rename a table or a column. +------------------------------------------------------------------------------------------- + +This is an InnoDB bug, see . + +.. _faq3_4: + +3.4 I am unable to import dumps I created with the mysqldump tool bundled with the MySQL server distribution. +------------------------------------------------------------------------------------------------------------- + +The problem is that older versions of ``mysqldump`` created invalid +comments like this: + +.. code-block:: mysql + + + -- MySQL dump 8.22 + -- + -- Host: localhost Database: database + --------------------------------------------------------- + -- Server version 3.23.54 + +The invalid part of the code is the horizontal line made of dashes +that appears once in every dump created with mysqldump. If you want to +run your dump you have to turn it into valid MySQL. This means, you +have to add a whitespace after the first two dashes of the line or add +a # before it: ``-- -------------------------------------------------------`` or +``#---------------------------------------------------------`` + +.. _faq3_5: + +3.5 When using nested folders, multiple hierarchies are displayed in a wrong manner. +------------------------------------------------------------------------------------ + +Please note that you should not use the separating string multiple +times without any characters between them, or at the beginning/end of +your table name. If you have to, think about using another +TableSeparator or disabling that feature. + +.. seealso:: :config:option:`$cfg['NavigationTreeTableSeparator']` + +.. _faq3_6: + +3.6 What is currently not supported in phpMyAdmin about InnoDB? +--------------------------------------------------------------- + +In Relation view, having more than one index column in the foreign key. In Query-by- +example (Query), automatic generation of the query LEFT JOIN from the +foreign table. + +.. _faq3_7: + +3.7 I have table with many (100+) columns and when I try to browse table I get series of errors like "Warning: unable to parse url". How can this be fixed? +----------------------------------------------------------------------------------------------------------------------------------------------------------- + +Your table neither have a primary key nor an unique one, so we must +use a long expression to identify this row. This causes problems to +parse\_url function. The workaround is to create a primary or unique +key. + +.. _faq3_8: + +3.8 I cannot use (clickable) HTML-forms in columns where I put a MIME-Transformation onto! +------------------------------------------------------------------------------------------ + +Due to a surrounding form-container (for multi-row delete checkboxes), +no nested forms can be put inside the table where phpMyAdmin displays +the results. You can, however, use any form inside of a table if keep +the parent form-container with the target to tbl\_row\_delete.php and +just put your own input-elements inside. If you use a custom submit +input field, the form will submit itself to the displaying page again, +where you can validate the $HTTP\_POST\_VARS in a transformation. For +a tutorial on how to effectively use transformations, see our `Link +section `_ on the +official phpMyAdmin-homepage. + +.. _faq3_9: + +3.9 I get error messages when using "--sql\_mode=ANSI" for the MySQL server. +---------------------------------------------------------------------------- + +When MySQL is running in ANSI-compatibility mode, there are some major +differences in how :term:`SQL` is structured (see +). Most important of all, the +quote-character (") is interpreted as an identifier quote character and not as +a string quote character, which makes many internal phpMyAdmin operations into +invalid :term:`SQL` statements. There is no +workaround to this behaviour. News to this item will be posted in `Bug report +#1013 `_. + +.. _faq3_10: + +3.10 Homonyms and no primary key: When the results of a SELECT display more that one column with the same value (for example ``SELECT lastname from employees where firstname like 'A%'`` and two "Smith" values are displayed), if I click Edit I cannot be sure that I am editing the intended row. +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +Please make sure that your table has a primary key, so that phpMyAdmin +can use it for the Edit and Delete links. + +.. _faq3_11: + +3.11 The number of rows for InnoDB tables is not correct. +--------------------------------------------------------- + +phpMyAdmin uses a quick method to get the row count, and this method only +returns an approximate count in the case of InnoDB tables. See +:config:option:`$cfg['MaxExactCount']` for a way to modify those results, but +this could have a serious impact on performance. + +.. _faq3_12: + +3.12 (withdrawn). +----------------- + +.. _faq3_13: + +3.13 I get an error when entering ``USE`` followed by a db name containing an hyphen. +------------------------------------------------------------------------------------- + +The tests I have made with MySQL 5.1.49 shows that the API does not +accept this syntax for the USE command. + +.. _faq3_14: + +3.14 I am not able to browse a table when I don't have the right to SELECT one of the columns. +---------------------------------------------------------------------------------------------- + +This has been a known limitation of phpMyAdmin since the beginning and +it's not likely to be solved in the future. + +.. _faq3_15: + +3.15 (withdrawn). +----------------- + +.. _faq3_16: + +3.16 (withdrawn). +----------------- + +.. _faq3_17: + +3.17 (withdrawn). +----------------- + +.. _faq3_18: + +3.18 When I import a CSV file that contains multiple tables, they are lumped together into a single table. +---------------------------------------------------------------------------------------------------------- + +There is no reliable way to differentiate tables in :term:`CSV` format. For the +time being, you will have to break apart :term:`CSV` files containing multiple +tables. + +.. _faq3_19: + +3.19 When I import a file and have phpMyAdmin determine the appropriate data structure it only uses int, decimal, and varchar types. +------------------------------------------------------------------------------------------------------------------------------------ + +Currently, the import type-detection system can only assign these +MySQL types to columns. In future, more will likely be added but for +the time being you will have to edit the structure to your liking +post-import. Also, you should note the fact that phpMyAdmin will use +the size of the largest item in any given column as the column size +for the appropriate type. If you know you will be adding larger items +to that column then you should manually adjust the column sizes +accordingly. This is done for the sake of efficiency. + +.. _faq3_20: + +3.20 After upgrading, some bookmarks are gone or their content cannot be shown. +------------------------------------------------------------------------------- + +At some point, the character set used to store bookmark content has changed. +It's better to recreate your bookmark from the newer phpMyAdmin version. + +.. _faqmultiuser: + +ISPs, multi-user installations +++++++++++++++++++++++++++++++ + +.. _faq4_1: + +4.1 I'm an ISP. Can I setup one central copy of phpMyAdmin or do I need to install it for each customer? +-------------------------------------------------------------------------------------------------------- + +Since version 2.0.3, you can setup a central copy of phpMyAdmin for all your +users. The development of this feature was kindly sponsored by NetCologne GmbH. +This requires a properly setup MySQL user management and phpMyAdmin +:term:`HTTP` or cookie authentication. + +.. seealso:: :ref:`authentication_modes` + +.. _faq4_2: + +4.2 What's the preferred way of making phpMyAdmin secure against evil access? +----------------------------------------------------------------------------- + +This depends on your system. If you're running a server which cannot be +accessed by other people, it's sufficient to use the directory protection +bundled with your webserver (with Apache you can use :term:`.htaccess` files, +for example). If other people have telnet access to your server, you should use +phpMyAdmin's :term:`HTTP` or cookie authentication features. + +Suggestions: + +* Your :file:`config.inc.php` file should be ``chmod 660``. +* All your phpMyAdmin files should be chown -R phpmy.apache, where phpmy + is a user whose password is only known to you, and apache is the group + under which Apache runs. +* Follow security recommendations for PHP and your webserver. + +.. _faq4_3: + +4.3 I get errors about not being able to include a file in */lang* or in */libraries*. +-------------------------------------------------------------------------------------- + +Check :file:`php.ini`, or ask your sysadmin to check it. The +``include_path`` must contain "." somewhere in it, and +``open_basedir``, if used, must contain "." and "./lang" to allow +normal operation of phpMyAdmin. + +.. _faq4_4: + +4.4 phpMyAdmin always gives "Access denied" when using HTTP authentication. +--------------------------------------------------------------------------- + +This could happen for several reasons: + +* :config:option:`$cfg['Servers'][$i]['controluser']` and/or :config:option:`$cfg['Servers'][$i]['controlpass']` are wrong. +* The username/password you specify in the login dialog are invalid. +* You have already setup a security mechanism for the phpMyAdmin- + directory, eg. a :term:`.htaccess` file. This would interfere with phpMyAdmin's + authentication, so remove it. + +.. _faq4_5: + +4.5 Is it possible to let users create their own databases? +----------------------------------------------------------- + +Starting with 2.2.5, in the user management page, you can enter a +wildcard database name for a user (for example "joe%"), and put the +privileges you want. For example, adding ``SELECT, INSERT, UPDATE, +DELETE, CREATE, DROP, INDEX, ALTER`` would let a user create/manage +his/her database(s). + +.. _faq4_6: + +4.6 How can I use the Host-based authentication additions? +---------------------------------------------------------- + +If you have existing rules from an old :term:`.htaccess` file, you can take them and +add a username between the ``'deny'``/``'allow'`` and ``'from'`` +strings. Using the username wildcard of ``'%'`` would be a major +benefit here if your installation is suited to using it. Then you can +just add those updated lines into the +:config:option:`$cfg['Servers'][$i]['AllowDeny']['rules']` array. + +If you want a pre-made sample, you can try this fragment. It stops the +'root' user from logging in from any networks other than the private +network :term:`IP` blocks. + +.. code-block:: php + + + //block root from logging in except from the private networks + $cfg['Servers'][$i]['AllowDeny']['order'] = 'deny,allow'; + $cfg['Servers'][$i]['AllowDeny']['rules'] = array( + 'deny root from all', + 'allow root from localhost', + 'allow root from 10.0.0.0/8', + 'allow root from 192.168.0.0/16', + 'allow root from 172.16.0.0/12', + ); + +.. _faq4_7: + +4.7 Authentication window is displayed more than once, why? +----------------------------------------------------------- + +This happens if you are using a :term:`URL` to start phpMyAdmin which is +different than the one set in your :config:option:`$cfg['PmaAbsoluteUri']`. For +example, a missing "www", or entering with an :term:`IP` address while a domain +name is defined in the config file. + +.. _faq4_8: + +4.8 Which parameters can I use in the URL that starts phpMyAdmin? +----------------------------------------------------------------- + +When starting phpMyAdmin, you can use the ``db``, ``pma_username``, +``pma_password`` and ``server`` parameters. This last one can contain +either the numeric host index (from ``$i`` of the configuration file) +or one of the host names present in the configuration file. Using +``pma_username`` and ``pma_password`` has been tested along with the +usage of 'cookie' ``auth_type``. + +.. _faqbrowsers: + +Browsers or client OS ++++++++++++++++++++++ + +.. _faq5_1: + +5.1 I get an out of memory error, and my controls are non-functional, when trying to create a table with more than 14 columns. +------------------------------------------------------------------------------------------------------------------------------ + +We could reproduce this problem only under Win98/98SE. Testing under +WinNT4 or Win2K, we could easily create more than 60 columns. A +workaround is to create a smaller number of columns, then come back to +your table properties and add the other columns. + +.. _faq5_2: + +5.2 With Xitami 2.5b4, phpMyAdmin won't process form fields. +------------------------------------------------------------ + +This is not a phpMyAdmin problem but a Xitami known bug: you'll face +it with each script/website that use forms. Upgrade or downgrade your +Xitami server. + +.. _faq5_3: + +5.3 I have problems dumping tables with Konqueror (phpMyAdmin 2.2.2). +--------------------------------------------------------------------- + +With Konqueror 2.1.1: plain dumps, zip and GZip dumps work ok, except +that the proposed file name for the dump is always 'tbl\_dump.php'. +Bzip2 dumps don't seem to work. With Konqueror 2.2.1: plain dumps +work; zip dumps are placed into the user's temporary directory, so +they must be moved before closing Konqueror, or else they disappear. +GZip dumps give an error message. Testing needs to be done for +Konqueror 2.2.2. + +.. _faq5_4: + +5.4 I can't use the cookie authentication mode because Internet Explorer never stores the cookies. +-------------------------------------------------------------------------------------------------- + +MS Internet Explorer seems to be really buggy about cookies, at least +till version 6. + +.. _faq5_5: + +5.5 In Internet Explorer 5.0, I get JavaScript errors when browsing my rows. +---------------------------------------------------------------------------- + +Upgrade to at least Internet Explorer 5.5 SP2. + +.. _faq5_6: + +5.6 In Internet Explorer 5.0, 5.5 or 6.0, I get an error (like "Page not found") when trying to modify a row in a table with many columns, or with a text column. +----------------------------------------------------------------------------------------------------------------------------------------------------------------- + +Your table neither have a primary key nor an unique one, so we must use a long +:term:`URL` to identify this row. There is a limit on the length of the +:term:`URL` in those browsers, and this not happen in Netscape, for example. +The workaround is to create a primary or unique key, or use another browser. + +.. _faq5_7: + +5.7 I refresh (reload) my browser, and come back to the welcome page. +--------------------------------------------------------------------- + +Some browsers support right-clicking into the frame you want to +refresh, just do this in the right frame. + +.. _faq5_8: + +5.8 With Mozilla 0.9.7 I have problems sending a query modified in the query box. +--------------------------------------------------------------------------------- + +Looks like a Mozilla bug: 0.9.6 was OK. We will keep an eye on future +Mozilla versions. + +.. _faq5_9: + +5.9 With Mozilla 0.9.? to 1.0 and Netscape 7.0-PR1 I can't type a whitespace in the SQL-Query edit area: the page scrolls down. +------------------------------------------------------------------------------------------------------------------------------- + +This is a Mozilla bug (see bug #26882 at `BugZilla +`_). + +.. _faq5_10: + +5.10 With Netscape 4.75 I get empty rows between each row of data in a CSV exported file. +----------------------------------------------------------------------------------------- + +This is a known Netscape 4.75 bug: it adds some line feeds when +exporting data in octet-stream mode. Since we can't detect the +specific Netscape version, we cannot workaround this bug. + +.. _faq5_11: + +5.11 Extended-ASCII characters like German umlauts are displayed wrong. +----------------------------------------------------------------------- + +Please ensure that you have set your browser's character set to the +one of the language file you have selected on phpMyAdmin's start page. +Alternatively, you can try the auto detection mode that is supported +by the recent versions of the most browsers. + +.. _faq5_12: + +5.12 Mac OS X Safari browser changes special characters to "?". +--------------------------------------------------------------- + +This issue has been reported by a :term:`Mac OS X` user, who adds that Chimera, +Netscape and Mozilla do not have this problem. + +.. _faq5_13: + +5.13 With Internet Explorer 5.5 or 6, and HTTP authentication type, I cannot manage two servers: I log in to the first one, then the other one, but if I switch back to the first, I have to log in on each operation. +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +This is a bug in Internet Explorer, other browsers do not behave this +way. + +.. _faq5_14: + +5.14 Using Opera6, I can manage to get to the authentication, but nothing happens after that, only a blank screen. +------------------------------------------------------------------------------------------------------------------ + +Please upgrade to Opera7 at least. + +.. _faq5_15: + +5.15 I have display problems with Safari. +----------------------------------------- + +Please upgrade to at least version 1.2.3. + +.. _faq5_16: + +5.16 With Internet Explorer, I get "Access is denied" Javascript errors. Or I cannot make phpMyAdmin work under Windows. +------------------------------------------------------------------------------------------------------------------------ + +Please check the following points: + +* Maybe you have defined your :config:option:`$cfg['PmaAbsoluteUri']` setting in + :file:`config.inc.php` to an :term:`IP` address and you are starting phpMyAdmin + with a :term:`URL` containing a domain name, or the reverse situation. +* Security settings in IE and/or Microsoft Security Center are too high, + thus blocking scripts execution. +* The Windows Firewall is blocking Apache and MySQL. You must allow + :term:`HTTP` ports (80 or 443) and MySQL + port (usually 3306) in the "in" and "out" directions. + +.. _faq5_17: + +5.17 With Firefox, I cannot delete rows of data or drop a database. +------------------------------------------------------------------- + +Many users have confirmed that the Tabbrowser Extensions plugin they +installed in their Firefox is causing the problem. + +.. _faq5_18: + +5.18 With Konqueror 4.2.x an invalid ``LIMIT`` clause is generated when I browse a table. +----------------------------------------------------------------------------------------- + +This happens only when both of these conditions are met: using the +``http`` authentication mode and ``register_globals`` being set to +``On`` on the server. It seems to be a browser-specific problem; +meanwhile use the ``cookie`` authentication mode. + +.. _faq5_19: + +5.19 I get JavaScript errors in my browser. +------------------------------------------- + +Issues have been reported with some combinations of browser +extensions. To troubleshoot, disable all extensions then clear your +browser cache to see if the problem goes away. + +.. _faqusing: + +Using phpMyAdmin +++++++++++++++++ + +.. _faq6_1: + +6.1 I can't insert new rows into a table / I can't create a table - MySQL brings up a SQL error. +------------------------------------------------------------------------------------------------ + +Examine the :term:`SQL` error with care. +Often the problem is caused by specifying a wrong column-type. Common +errors include: + +* Using ``VARCHAR`` without a size argument +* Using ``TEXT`` or ``BLOB`` with a size argument + +Also, look at the syntax chapter in the MySQL manual to confirm that +your syntax is correct. + +.. _faq6_2: + +6.2 When I create a table, I set an index for two columns and phpMyAdmin generates only one index with those two columns. +------------------------------------------------------------------------------------------------------------------------- + +This is the way to create a multi-columns index. If you want two +indexes, create the first one when creating the table, save, then +display the table properties and click the Index link to create the +other index. + +.. _faq6_3: + +6.3 How can I insert a null value into my table? +------------------------------------------------ + +Since version 2.2.3, you have a checkbox for each column that can be +null. Before 2.2.3, you had to enter "null", without the quotes, as +the column's value. Since version 2.5.5, you have to use the checkbox +to get a real NULL value, so if you enter "NULL" this means you want a +literal NULL in the column, and not a NULL value (this works in PHP4). + +.. _faq6_4: + +6.4 How can I backup my database or table? +------------------------------------------ + +Click on a database or table name in the navigation panel, the properties will +be displayed. Then on the menu, click "Export", you can dump the structure, the +data, or both. This will generate standard :term:`SQL` statements that can be +used to recreate your database/table. You will need to choose "Save as file", +so that phpMyAdmin can transmit the resulting dump to your station. Depending +on your PHP configuration, you will see options to compress the dump. See also +the :config:option:`$cfg['ExecTimeLimit']` configuration variable. For +additional help on this subject, look for the word "dump" in this document. + +.. _faq6_5: + +6.5 How can I restore (upload) my database or table using a dump? How can I run a ".sql" file? +---------------------------------------------------------------------------------------------- + +Click on a database name in the navigation panel, the properties will +be displayed. Select "Import" from the list of tabs in the right–hand +frame (or ":term:`SQL`" if your phpMyAdmin +version is previous to 2.7.0). In the "Location of the text file" +section, type in the path to your dump filename, or use the Browse +button. Then click Go. With version 2.7.0, the import engine has been +re–written, if possible it is suggested that you upgrade to take +advantage of the new features. For additional help on this subject, +look for the word "upload" in this document. + +.. _faq6_6: + +6.6 How can I use the relation table in Query-by-example? +--------------------------------------------------------- + +Here is an example with the tables persons, towns and countries, all +located in the database "mydb". If you don't have a ``pma__relation`` +table, create it as explained in the configuration section. Then +create the example tables: + +.. code-block:: mysql + + + CREATE TABLE REL_countries ( + country_code char(1) NOT NULL default '', + description varchar(10) NOT NULL default '', + PRIMARY KEY (country_code) + ) TYPE=MyISAM; + + INSERT INTO REL_countries VALUES ('C', 'Canada'); + + CREATE TABLE REL_persons ( + id tinyint(4) NOT NULL auto_increment, + person_name varchar(32) NOT NULL default '', + town_code varchar(5) default '0', + country_code char(1) NOT NULL default '', + PRIMARY KEY (id) + ) TYPE=MyISAM; + + INSERT INTO REL_persons VALUES (11, 'Marc', 'S', ''); + INSERT INTO REL_persons VALUES (15, 'Paul', 'S', 'C'); + + CREATE TABLE REL_towns ( + town_code varchar(5) NOT NULL default '0', + description varchar(30) NOT NULL default '', + PRIMARY KEY (town_code) + ) TYPE=MyISAM; + + INSERT INTO REL_towns VALUES ('S', 'Sherbrooke'); + INSERT INTO REL_towns VALUES ('M', 'Montréal'); + +To setup appropriate links and display information: + +* on table "REL\_persons" click Structure, then Relation view +* for "town\_code", choose from dropdowns, "mydb", "REL\_towns", "code" + for foreign database, table and column respectively +* for "country\_code", choose from dropdowns, "mydb", "REL\_countries", + "country\_code" for foreign database, table and column respectively +* on table "REL\_towns" click Structure, then Relation view +* in "Choose column to display", choose "description" +* repeat the two previous steps for table "REL\_countries" + +Then test like this: + +* Click on your db name in the navigation panel +* Choose "Query" +* Use tables: persons, towns, countries +* Click "Update query" +* In the columns row, choose persons.person\_name and click the "Show" + tickbox +* Do the same for towns.description and countries.descriptions in the + other 2 columns +* Click "Update query" and you will see in the query box that the + correct joins have been generated +* Click "Submit query" + +.. _faqdisplay: + +6.7 How can I use the "display column" feature? +----------------------------------------------- + +Starting from the previous example, create the ``pma__table_info`` as +explained in the configuration section, then browse your persons +table, and move the mouse over a town code or country code. See also +:ref:`faq6_21` for an additional feature that "display column" +enables: drop-down list of possible values. + +.. _faqpdf: + +6.8 How can I produce a PDF schema of my database? +-------------------------------------------------- + +First the configuration variables "relation", "table\_coords" and +"pdf\_pages" have to be filled in. Then you need to think about your +schema layout. Which tables will go on which pages? + +* Select your database in the navigation panel. +* Choose "Operations" in the navigation bar at the top. +* Choose "Edit :term:`PDF` Pages" near the + bottom of the page. +* Enter a name for the first :term:`PDF` page + and click Go. If you like, you can use the "automatic layout," which + will put all your linked tables onto the new page. +* Select the name of the new page (making sure the Edit radio button is + selected) and click Go. +* Select a table from the list, enter its coordinates and click Save. + Coordinates are relative; your diagram will be automatically scaled to + fit the page. When initially placing tables on the page, just pick any + coordinates -- say, 50x50. After clicking Save, you can then use the + :ref:`wysiwyg` to position the element correctly. +* When you'd like to look at your :term:`PDF`, first be sure to click the Save + button beneath the list of tables and coordinates, to save any changes you + made there. Then scroll all the way down, select the :term:`PDF` options you + want, and click Go. +* Internet Explorer for Windows may suggest an incorrect filename when + you try to save a generated :term:`PDF`. + When saving a generated :term:`PDF`, be + sure that the filename ends in ".pdf", for example "schema.pdf". + Browsers on other operating systems, and other browsers on Windows, do + not have this problem. + +.. _faq6_9: + +6.9 phpMyAdmin is changing the type of one of my columns! +--------------------------------------------------------- + +No, it's MySQL that is doing `silent column type changing +`_. + +.. _underscore: + +6.10 When creating a privilege, what happens with underscores in the database name? +----------------------------------------------------------------------------------- + +If you do not put a backslash before the underscore, this is a +wildcard grant, and the underscore means "any character". So, if the +database name is "john\_db", the user would get rights to john1db, +john2db ... If you put a backslash before the underscore, it means +that the database name will have a real underscore. + +.. _faq6_11: + +6.11 What is the curious symbol ø in the statistics pages? +---------------------------------------------------------- + +It means "average". + +.. _faqexport: + +6.12 I want to understand some Export options. +---------------------------------------------- + +**Structure:** + +* "Add DROP TABLE" will add a line telling MySQL to `drop the table + `_, if it already + exists during the import. It does NOT drop the table after your + export, it only affects the import file. +* "If Not Exists" will only create the table if it doesn't exist. + Otherwise, you may get an error if the table name exists but has a + different structure. +* "Add AUTO\_INCREMENT value" ensures that AUTO\_INCREMENT value (if + any) will be included in backup. +* "Enclose table and column names with backquotes" ensures that column + and table names formed with special characters are protected. +* "Add into comments" includes column comments, relations, and MIME + types set in the pmadb in the dump as :term:`SQL` comments + (*/\* xxx \*/*). + +**Data:** + +* "Complete inserts" adds the column names on every INSERT command, for + better documentation (but resulting file is bigger). +* "Extended inserts" provides a shorter dump file by using only once the + INSERT verb and the table name. +* "Delayed inserts" are best explained in the `MySQL manual - INSERT DELAYED Syntax + `_. +* "Ignore inserts" treats errors as a warning instead. Again, more info + is provided in the `MySQL manual - INSERT Syntax + `_, but basically with + this selected, invalid values are adjusted and inserted rather than + causing the entire statement to fail. + +.. _faq6_13: + +6.13 I would like to create a database with a dot in its name. +-------------------------------------------------------------- + +This is a bad idea, because in MySQL the syntax "database.table" is +the normal way to reference a database and table name. Worse, MySQL +will usually let you create a database with a dot, but then you cannot +work with it, nor delete it. + +.. _faqsqlvalidator: + +6.14 How do I set up the SQL Validator? +--------------------------------------- + +To use SQL Validator, you need PHP with :term:`XML`, :term:`PCRE` and +:term:`PEAR` support. In addition you need a :term:`SOAP` support, either as a +PHP extension or as a PEAR SOAP module. + +To install :term:`PEAR` :term:`SOAP` module, run :command:`pear install +Net_Socket Net_URL HTTP_Request Mail_Mime Net_DIME SOAP` to get the necessary +:term:`PEAR` modules for usage. + +If you use the Validator, you should be aware that any :term:`SQL` statement +you submit will be stored anonymously (database/table/column names, strings, +numbers replaced with generic values). The Mimer :term:`SQL` Validator itself, +is © 2001 Upright Database Technology. We utilize it as free SOAP service. + +.. _faq6_15: + +6.15 I want to add a BLOB column and put an index on it, but MySQL says "BLOB column '...' used in key specification without a key length". +------------------------------------------------------------------------------------------------------------------------------------------- + +The right way to do this, is to create the column without any indexes, +then display the table structure and use the "Create an index" dialog. +On this page, you will be able to choose your BLOB column, and set a +size to the index, which is the condition to create an index on a BLOB +column. + +.. _faq6_16: + +6.16 How can I simply move in page with plenty editing fields? +-------------------------------------------------------------- + +You can use :kbd:`Ctrl+arrows` (:kbd:`Option+Arrows` in Safari) for moving on +most pages with many editing fields (table structure changes, row editing, +etc.). + +.. _faq6_17: + +6.17 Transformations: I can't enter my own mimetype! WTF is this feature then useful for? +----------------------------------------------------------------------------------------- + +Slow down :). Defining mimetypes is of no use, if you can't put +transformations on them. Otherwise you could just put a comment on the +column. Because entering your own mimetype will cause serious syntax +checking issues and validation, this introduces a high-risk false- +user-input situation. Instead you have to initialize mimetypes using +functions or empty mimetype definitions. + +Plus, you have a whole overview of available mimetypes. Who knows all those +mimetypes by heart so he/she can enter it at will? + +.. _faqbookmark: + +6.18 Bookmarks: Where can I store bookmarks? Why can't I see any bookmarks below the query box? What is this variable for? +-------------------------------------------------------------------------------------------------------------------------- + +Any query you have executed can be stored as a bookmark on the page +where the results are displayed. You will find a button labeled +'Bookmark this query' just at the end of the page. As soon as you have +stored a bookmark, it is related to the database you run the query on. +You can now access a bookmark dropdown on each page, the query box +appears on for that database. + +You can also have, inside the query, a placeholder for a variable. +This is done by inserting into the query a SQL comment between ``/*`` and +``*/``. Inside the comment, the special string ``[VARIABLE]`` is used. +Be aware that the whole query minus the SQL comment must be +valid by itself, otherwise you won't be able to store it as a bookmark. + +When you execute the bookmark, everything typed into the *value* +input box on the query box page will replace the string ``/*[VARIABLE]*/`` in +your stored query. + +Also remember, that everything else inside the ``/*[VARIABLE]*/`` string for +your query will remain the way it is, but will be stripped of the ``/**/`` +chars. So you can use: + +.. code-block:: mysql + + /*, [VARIABLE] AS myname */ + +which will be expanded to + +.. code-block:: mysql + + , VARIABLE as myname + +in your query, where VARIABLE is the string you entered in the input box. If an +empty string is provided, no replacements are made. + +A more complex example. Say you have stored +this query: + +.. code-block:: mysql + + SELECT Name, Address FROM addresses WHERE 1 /* AND Name LIKE '%[VARIABLE]%' */ + +Say, you now enter "phpMyAdmin" as the variable for the stored query, the full +query will be: + +.. code-block:: mysql + + SELECT Name, Address FROM addresses WHERE 1 AND Name LIKE '%phpMyAdmin%' + +You can use multiple occurrences of ``/*[VARIABLE]*/`` in a single query +(that is, multiple occurrences of the *same* variable). + +**NOTE THE ABSENCE OF SPACES** inside the ``/**/`` construct. Any spaces +inserted there will be later also inserted as spaces in your query and may lead +to unexpected results especially when using the variable expansion inside of a +"LIKE ''" expression. + +Your initial query which is going to be stored as a bookmark has to yield at +least one result row so you can store the bookmark. You may have that to work +around using well positioned ``/**/`` comments. + +.. _faq6_19: + +6.19 How can I create simple LATEX document to include exported table? +---------------------------------------------------------------------- + +You can simply include table in your LATEX documents, +minimal sample document should look like following one (assuming you +have table exported in file :file:`table.tex`): + +.. code-block:: latex + + + \documentclass{article} % or any class you want + \usepackage{longtable} % for displaying table + \begin{document} % start of document + \include{table} % including exported table + \end{document} % end of document + +.. _faq6_20: + +6.20 I see a lot of databases which are not mine, and cannot access them. +------------------------------------------------------------------------- + +You have one of these global privileges: CREATE TEMPORARY TABLES, SHOW +DATABASES, LOCK TABLES. Those privileges also enable users to see all the +database names. So if your users do not need those privileges, you can remove +them and their databases list will shorten. + +.. seealso:: + +.. _faq6_21: + +6.21 In edit/insert mode, how can I see a list of possible values for a column, based on some foreign table? +------------------------------------------------------------------------------------------------------------ + +You have to setup appropriate links between the tables, and also setup +the "display column" in the foreign table. See :ref:`faq6_6` for an +example. Then, if there are 100 values or less in the foreign table, a +drop-down list of values will be available. You will see two lists of +values, the first list containing the key and the display column, the +second list containing the display column and the key. The reason for +this is to be able to type the first letter of either the key or the +display column. For 100 values or more, a distinct window will appear, +to browse foreign key values and choose one. To change the default +limit of 100, see :config:option:`$cfg['ForeignKeyMaxLimit']`. + + +.. _faq6_22: + +6.22 Bookmarks: Can I execute a default bookmark automatically when entering Browse mode for a table? +----------------------------------------------------------------------------------------------------- + +Yes. If a bookmark has the same label as a table name and it's not a +public bookmark, it will be executed. + +.. _faq6_23: + +6.23 Export: I heard phpMyAdmin can export Microsoft Excel files? +----------------------------------------------------------------- + +You can use :term:`CSV` for Microsoft Excel, +which works out of the box. + +.. versionchanged:: 3.4.5 + Since phpMyAdmin 3.4.5 support for direct export to Microsoft Excel version + 97 and newer was dropped. + +.. _faq6_24: + +6.24 Now that phpMyAdmin supports native MySQL 4.1.x column comments, what happens to my column comments stored in pmadb? +------------------------------------------------------------------------------------------------------------------------- + +Automatic migration of a table's pmadb-style column comments to the +native ones is done whenever you enter Structure page for this table. + +.. _faq6_25: + +6.25 (withdrawn). +----------------- + +.. _faq6_26: + +6.26 How can I select a range of rows? +-------------------------------------- + +Click the first row of the range, hold the shift key and click the +last row of the range. This works everywhere you see rows, for example +in Browse mode or on the Structure page. + +.. _faq6_27: + +6.27 What format strings can I use? +----------------------------------- + +In all places where phpMyAdmin accepts format strings, you can use +``@VARIABLE@`` expansion and `strftime `_ +format strings. The expanded variables depend on a context (for +example, if you haven't chosen a table, you can not get the table +name), but the following variables can be used: + +``@HTTP_HOST@`` + HTTP host that runs phpMyAdmin +``@SERVER@`` + MySQL server name +``@VERBOSE@`` + Verbose MySQL server name as defined in :config:option:`$cfg['Servers'][$i]['verbose']` +``@VSERVER@`` + Verbose MySQL server name if set, otherwise normal +``@DATABASE@`` + Currently opened database +``@TABLE@`` + Currently opened table +``@COLUMNS@`` + Columns of the currently opened table +``@PHPMYADMIN@`` + phpMyAdmin with version + +.. _wysiwyg: + +6.28 How can I easily edit relational schema for export? +-------------------------------------------------------- + +By clicking on the button 'toggle scratchboard' on the page where you +edit x/y coordinates of those elements you can activate a scratchboard +where all your elements are placed. By clicking on an element, you can +move them around in the pre-defined area and the x/y coordinates will +get updated dynamically. Likewise, when entering a new position +directly into the input field, the new position in the scratchboard +changes after your cursor leaves the input field. + +You have to click on the 'OK'-button below the tables to save the new +positions. If you want to place a new element, first add it to the +table of elements and then you can drag the new element around. + +By changing the paper size and the orientation you can change the size +of the scratchboard as well. You can do so by just changing the +dropdown field below, and the scratchboard will resize automatically, +without interfering with the current placement of the elements. + +If ever an element gets out of range you can either enlarge the paper +size or click on the 'reset' button to place all elements below each +other. + +.. _faq6_29: + +6.29 Why can't I get a chart from my query result table? +-------------------------------------------------------- + +Not every table can be put to the chart. Only tables with one, two or +three columns can be visualised as a chart. Moreover the table must be +in a special format for chart script to understand it. Currently +supported formats can be found in the `wiki `_. + +.. _faq6_30: + +6.30 Import: How can I import ESRI Shapefiles? +---------------------------------------------- + +An ESRI Shapefile is actually a set of several files, where .shp file +contains geometry data and .dbf file contains data related to those +geometry data. To read data from .dbf file you need to have PHP +compiled with the dBase extension (--enable-dbase). Otherwise only +geometry data will be imported. + +To upload these set of files you can use either of the following +methods: + +Configure upload directory with :config:option:`$cfg['UploadDir']`, upload both .shp and .dbf files with +the same filename and chose the .shp file from the import page. + +Create a Zip archive with .shp and .dbf files and import it. For this +to work, you need to set :config:option:`$cfg['TempDir']` to a place where the web server user can +write (for example ``'./tmp'``). + +To create the temporary directory on a UNIX-based system, you can do: + +.. code-block:: sh + + cd phpMyAdmin + mkdir tmp + chmod o+rwx tmp + +.. _faq6_31: + +6.31 How do I create a relation in designer? +-------------------------------------------- + +To select relation, click: The display column is shown in pink. To +set/unset a column as the display column, click the "Choose column to +display" icon, then click on the appropriate column name. + +.. _faq6_32: + +6.32 How can I use the zoom search feature? +------------------------------------------- + +The Zoom search feature is an alternative to table search feature. It allows +you to explore a table by representing its data in a scatter plot. You can +locate this feature by selecting a table and clicking the :guilabel:`Search` +tab. One of the sub-tabs in the :guilabel:`Table Search` page is +:guilabel:`Zoom Search`. + +Consider the table REL\_persons in :ref:`faq6_6` for +an example. To use zoom search, two columns need to be selected, for +example, id and town\_code. The id values will be represented on one +axis and town\_code values on the other axis. Each row will be +represented as a point in a scatter plot based on its id and +town\_code. You can include two additional search criteria apart from +the two fields to display. + +You can choose which field should be +displayed as label for each point. If a display column has been set +for the table (see :ref:`faqdisplay`), it is taken as the label unless +you specify otherwise. You can also select the maximum number of rows +you want to be displayed in the plot by specifing it in the 'Max rows +to plot' field. Once you have decided over your criteria, click 'Go' +to display the plot. + +After the plot is generated, you can use the +mousewheel to zoom in and out of the plot. In addition, panning +feature is enabled to navigate through the plot. You can zoom-in to a +certail level of detail and use panning to locate your area of +interest. Clicking on a point opens a dialogue box, displaying field +values of the data row represented by the point. You can edit the +values if required and click on submit to issue an update query. Basic +instructions on how to use can be viewed by clicking the 'How to use?' +link located just above the plot. + +.. _faq6_33: + +6.33 When browsing a table, how can I copy a column name? +--------------------------------------------------------- + +Selecting the name of the column within the browse table header cell +for copying is difficult, as the columns support reordering by +dragging the header cells as well as sorting by clicking on the linked +column name. To copy a column name, double-click on the empty area +next to the column name, when the tooltip tells you to do so. This +will show you an input box with the column name. You may right-click +the column name within this input box to copy it to your clipboard. + +.. _faqproject: + +phpMyAdmin project +++++++++++++++++++ + +.. _faq7_1: + +7.1 I have found a bug. How do I inform developers? +--------------------------------------------------- + +Our Bug Tracker is located at under the +Bugs section. But please first discuss your bug with other users: +. + +.. _faq7_2: + +7.2 I want to translate the messages to a new language or upgrade an existing language, where do I start? +--------------------------------------------------------------------------------------------------------- + +Translations are very welcome and all you need to have are the +language skills. The easiest way is to use our `online translation +service `_. You can check +out all the possibilities to translate in the `translate section on +our website `_. + +.. _faq7_3: + +7.3 I would like to help out with the development of phpMyAdmin. How should I proceed? +-------------------------------------------------------------------------------------- + +We welcome every contribution to the development of phpMyAdmin. You +can check out all the possibilities to contribute in the `contribute +section on our website +`_. + +.. seealso:: :ref:`developers` + +.. _faqsecurity: + +Security +++++++++ + +.. _faq8_1: + +8.1 Where can I get information about the security alerts issued for phpMyAdmin? +-------------------------------------------------------------------------------- + +Please refer to . + +.. _faq8_2: + +8.2 How can I protect phpMyAdmin against brute force attacks? +------------------------------------------------------------- + +If you use Apache web server, phpMyAdmin exports information about +authentication to the Apache environment and it can be used in Apache +logs. Currently there are two variables available: + + +``userID`` + User name of currently active user (he does not have to be logged in). +``userStatus`` + Status of currently active user, one of ``ok`` (user is logged in), + ``mysql-denied`` (MySQL denied user login), ``allow-denied`` (user denied + by allow/deny rules), ``root-denied`` (root is denied in configuration), + ``empty-denied`` (empty password is denied). + +``LogFormat`` directive for Apache can look like following: + +.. code-block:: apache + + LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %{userID}n %{userStatus}n" pma_combined + +You can then use any log analyzing tools to detect possible break-in +attempts. + +.. _faqsynchronization: + +Synchronization ++++++++++++++++ + +.. _faq9_1: + +9.1 (withdrawn). +---------------- + +.. _faq9_2: + +9.2 (withdrawn). +---------------- + diff --git a/phpMyAdmin/doc/glossary.rst b/phpMyAdmin/doc/glossary.rst new file mode 100644 index 0000000..d558b44 --- /dev/null +++ b/phpMyAdmin/doc/glossary.rst @@ -0,0 +1,406 @@ +.. _glossary: + +Glossary +======== + +From Wikipedia, the free encyclopedia + +.. glossary:: + + .htaccess + the default name of Apache's directory-level configuration file. + + .. seealso:: + + ACL + Access Contol List + + Blowfish + a keyed, symmetric block cipher, designed in 1993 by Bruce Schneier. + + .. seealso:: + + Browser + a software application that enables a user to display and interact with text, images, and other information typically located on a web page at a website on the World Wide Web. + + .. seealso:: + + bzip2 + a free software/open source data compression algorithm and program developed by Julian Seward. + + .. seealso:: + + CGI + Common Gateway Interface is an important World Wide Web technology that + enables a client web browser to request data from a program executed on + the Web server. + + .. seealso:: + + Changelog + a log or record of changes made to a project. + + .. seealso:: + + Client + a computer system that accesses a (remote) service on another computer by some kind of network. + + .. seealso:: + + column + a set of data values of a particular simple type, one for each row of the table. + + .. seealso:: + + Cookie + a packet of information sent by a server to a World Wide Web browser and then sent back by the browser each time it accesses that server. + + .. seealso:: + + CSV + Comma- separated values + + .. seealso:: + + DB + look at :term:`database` + + database + an organized collection of data. + + .. seealso:: + + Engine + look at :term:`storage engines` + + extension + a PHP module that extends PHP with additional functionality. + + .. seealso:: + + FAQ + Frequently Asked Questions is a list of commonly asked question and there + answers. + + .. seealso:: + + Field + one part of divided data/columns. + + .. seealso:: + + foreign key + a column or group of columns in a database row that point to a key column + or group of columns forming a key of another database row in some + (usually different) table. + + .. seealso:: + + FPDF + the free :term:`PDF` library + + .. seealso:: + + GD + Graphics Library by Thomas Boutell and others for dynamically manipulating images. + + .. seealso:: + + GD2 + look at :term:`gd` + + gzip + gzip is short for GNU zip, a GNU free software file compression program. + + .. seealso:: + + host + any machine connected to a computer network, a node that has a hostname. + + .. seealso:: + + hostname + the unique name by which a network attached device is known on a network. + + .. seealso:: + + HTTP + HyperText Transfer Protocol is the primary method used to transfer or + convey information on the World Wide Web. + + .. seealso:: + + https + a :term:`HTTP`-connection with additional security measures. + + .. seealso:: + + IEC + International Electrotechnical Commission + + IIS + Internet Information Services is a set of Internet-based services for + servers using Microsoft Windows. + + .. seealso:: + + Index + a feature that allows quick access to the rows in a table. + + .. seealso:: + + IP + Internet Protocol is a data-oriented protocol used by source and + destination hosts for communicating data across a packet-switched + internetwork. + + .. seealso:: + + IP Address + a unique number that devices use in order to identify and communicate with each other on a network utilizing the Internet Protocol standard. + + .. seealso:: + + IPv6 + IPv6 (Internet Protocol version 6) is the latest revision of the + Internet Protocol (:term:`IP`), designed to deal with the + long-anticipated problem of its precedessor IPv4 running out of addresses. + + .. seealso:: + + ISAPI + Internet Server Application Programming Interface is the API of Internet Information Services (IIS). + + .. seealso:: + + ISP + Internet service provider is a business or organization that offers users + access to the Internet and related services. + + .. seealso:: + + ISO + International Standards Organisation + + JPEG + a most commonly used standard method of lossy compression for photographic images. + + .. seealso:: + + JPG + look at :term:`jpeg` + + Key + look at :term:`index` + + LATEX + a document preparation system for the TEX typesetting program. + + .. seealso:: + + Mac + Apple Macintosh is line of personal computers is designed, developed, manufactured, and marketed by Apple Computer. + + .. seealso:: + + Mac OS X + the operating system which is included with all currently shipping Apple Macintosh computers in the consumer and professional markets. + + .. seealso:: + + MCrypt + a cryptographic library. + + .. seealso:: + + mcrypt + the MCrypt PHP extension. + + .. seealso:: + + MIME + Multipurpose Internet Mail Extensions is + an Internet Standard for the format of e-mail. + + .. seealso:: + + module + some sort of extension for the Apache Webserver. + + .. seealso:: + + MySQL + a multithreaded, multi-user, SQL (Structured Query Language) Database Management System (DBMS). + + .. seealso:: + + mysqli + the improved MySQL client PHP extension. + + .. seealso:: + + mysql + the MySQL client PHP extension. + + .. seealso:: + + OpenDocument + open standard for office documents. + + .. seealso:: + + OS X + look at :term:`Mac OS X`. + + .. seealso:: + + PDF + Portable Document Format is a file format developed by Adobe Systems for + representing two dimensional documents in a device independent and + resolution independent format. + + .. seealso:: + + PEAR + the PHP Extension and Application Repository. + + .. seealso:: + + PCRE + Perl Compatible Regular Expressions is the perl-compatible regular + expression functions for PHP + + .. seealso:: + + PHP + short for "PHP: Hypertext Preprocessor", is an open-source, reflective + programming language used mainly for developing server-side applications + and dynamic web content, and more recently, a broader range of software + applications. + + .. seealso:: + + port + a connection through which data is sent and received. + + .. seealso:: + + RFC + Request for Comments (RFC) documents are a series of memoranda + encompassing new research, innovations, and methodologies applicable to + Internet technologies. + + .. seealso:: + + RFC 1952 + GZIP file format specification version 4.3 + + .. seealso:: :rfc:`1952` + + Row (record, tuple) + represents a single, implicitly structured data item in a table. + + .. seealso:: + + Server + a computer system that provides services to other computing systems over a network. + + .. seealso:: + + Storage Engines + handlers for different table types + + .. seealso:: + + SOAP + Simple Object Access Protocol is a protocol specification for exchanging + structured information in the implementation of Web Services in computer + networks. + + .. seealso:: + + socket + a form of inter-process communication. + + .. seealso:: + + SSL + Secure Sockets Layer is a cryptographic protocol which provides secure + communication on the Internet. + + .. seealso:: + + Stored procedure + a subroutine available to applications accessing a relational database system + + .. seealso:: + + SQL + Structured Query Language + + .. seealso:: + + table + a set of data elements (cells) that is organized, defined and stored as + horizontal rows and vertical columns where each item can be uniquely + identified by a label or key or by it?s position in relation to other + items. + + .. seealso:: + + tar + a type of archive file format: the Tape ARchive format. + + .. seealso:: + + TCP + Transmission Control Protocol is one of the core protocols of the + Internet protocol suite. + + .. seealso:: + + TCPDF + Rewrite of :term:`UFPDF` with various improvements. + + .. seealso:: + + trigger + a procedural code that is automatically executed in response to certain events on a particular table or view in a database + + .. seealso:: + + UFPDF + Unicode/UTF-8 extension for :term:`FPDF` + + .. seealso:: + + URL + Uniform Resource Locator is a sequence of characters, conforming to a + standardized format, that is used for referring to resources, such as + documents and images on the Internet, by their location. + + .. seealso:: + + Webserver + A computer (program) that is responsible for accepting HTTP requests from clients and serving them Web pages. + + .. seealso:: + + XML + Extensible Markup Language is a W3C-recommended general- purpose markup + language for creating special-purpose markup languages, capable of + describing many different kinds of data. + + .. seealso:: + + ZIP + a popular data compression and archival format. + + .. seealso:: + + zlib + an open-source, cross- platform data compression library by Jean-loup Gailly and Mark Adler. + + .. seealso:: + + diff --git a/phpMyAdmin/doc/html/.buildinfo b/phpMyAdmin/doc/html/.buildinfo new file mode 100644 index 0000000..b56b700 --- /dev/null +++ b/phpMyAdmin/doc/html/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 661dfadb8b10bc8a0f43a21cb0b27db8 +tags: fbb0d17656682115ca4d033fb2f83ba1 diff --git a/phpMyAdmin/doc/html/_sources/config.txt b/phpMyAdmin/doc/html/_sources/config.txt new file mode 100644 index 0000000..c8c04b2 --- /dev/null +++ b/phpMyAdmin/doc/html/_sources/config.txt @@ -0,0 +1,2813 @@ +.. index:: config.inc.php + +.. _config: + +Configuration +============= + +Almost all configurable data is placed in :file:`config.inc.php`. If this file +does not exist, please refer to the :ref:`setup` section to create one. This +file only needs to contain the parameters you want to change from their +corresponding default value in :file:`libraries/config.default.php`. + +If a directive is missing from your file, you can just add another line with +the file. This file is for over-writing the defaults; if you wish to use the +default value there's no need to add a line here. + +The parameters which relate to design (like colors) are placed in +:file:`themes/themename/layout.inc.php`. You might also want to create +:file:`config.footer.inc.php` and :file:`config.header.inc.php` files to add +your site specific code to be included on start and end of each page. + +.. note:: + + Some distributions (eg. Debian or Ubuntu) store :file:`config.inc.php` in + ``/etc/phpmyadmin`` instead of within phpMyAdmin sources. + +.. warning:: + + :term:`Mac` users should note that if you are on a version before + :term:`Mac OS X`, PHP does not seem to + like :term:`Mac` end of lines character (``\r``). So + ensure you choose the option that allows to use the \*nix end of line + character (``\n``) in your text editor before saving a script you have + modified. + +Basic settings +-------------- + +.. config:option:: $cfg['PmaAbsoluteUri'] + + :type: string + :default: ``''`` + + Sets here the complete :term:`URL` (with full path) to your phpMyAdmin + installation's directory. E.g. + ``http://www.example.net/path_to_your_phpMyAdmin_directory/``. Note also + that the :term:`URL` on most of web servers are case–sensitive. Don’t + forget the trailing slash at the end. + + Starting with version 2.3.0, it is advisable to try leaving this blank. In + most cases phpMyAdmin automatically detects the proper setting. Users of + port forwarding will need to set :config:option:`$cfg['PmaAbsoluteUri']` + (`more info `_). + + A good test is to browse a table, edit a row and save it. There should be + an error message if phpMyAdmin is having trouble auto–detecting the correct + value. If you get an error that this must be set or if the autodetect code + fails to detect your path, please post a bug report on our bug tracker so + we can improve the code. + + .. seealso:: :ref:`faq1_40` + +.. config:option:: $cfg['PmaNoRelation_DisableWarning'] + + :type: boolean + :default: false + + Starting with version 2.3.0 phpMyAdmin offers a lot of features to + work with master / foreign – tables (see :config:option:`$cfg['Servers'][$i]['pmadb']`). + + If you tried to set this + up and it does not work for you, have a look on the :guilabel:`Structure` page + of one database where you would like to use it. You will find a link + that will analyze why those features have been disabled. + + If you do not want to use those features set this variable to ``true`` to + stop this message from appearing. + +.. config:option:: $cfg['SuhosinDisableWarning'] + + :type: boolean + :default: false + + A warning is displayed on the main page if Suhosin is detected. + + You can set this parameter to ``true`` to stop this message from appearing. + +.. config:option:: $cfg['McryptDisableWarning'] + + :type: boolean + :default: false + + Disable the default warning that is displayed if mcrypt is missing for + cookie authentication. + + You can set this parameter to ``true`` to stop this message from appearing. + +.. config:option:: $cfg['ServerLibraryDifference_DisableWarning'] + + :type: boolean + :default: false + + A warning is displayed on the main page if there is a difference + between the MySQL library and server version. + + You can set this parameter to ``true`` to stop this message from appearing. + +.. config:option:: $cfg['ReservedWordDisableWarning'] + + :type: boolean + :default: false + + This warning is displayed on the Structure page of a table if one or more + column names match with words which are MySQL reserved. + + If you want to turn off this warning, you can set it to ``true`` and + warning will no longer be displayed. + +.. config:option:: $cfg['TranslationWarningThreshold'] + + :type: integer + :default: 80 + + Show warning about incomplete translations on certain threshold. + +.. config:option:: $cfg['SendErrorReports'] + + :type: string + :default: ``'ask'`` + + Sets the default behavior for JavaScript error reporting. + + Whenever an error is detected in the JavaScript execution, an error report + may be sent to the phpMyAdmin team if the user agrees. + + The default setting of ``'ask'`` will ask the user everytime there is a new + error report. However you can set this parameter to ``'always'`` to send error + reports without asking for confirmation or you can set it to ``'never'`` to + never send error reports. + + This directive is available both in the configuration file and in users + preferences. If the person in charge of a multi-user installation prefers + to disable this feature for all users, a value of ``'never'`` should be + set, and the :config:option:`$cfg['UserprefsDisallow']` directive should + contain ``'SendErrorReports'`` in one of its array values. + +.. config:option:: $cfg['AllowThirdPartyFraming'] + + :type: boolean + :default: false + + Setting this to ``true`` allows phpMyAdmin to be included inside a frame, + and is a potential security hole allowing cross-frame scripting attacks or + clickjacking. + +Server connection settings +-------------------------- + +.. config:option:: $cfg['Servers'] + + :type: array + :default: one server array with settings listed bellow + + Since version 1.4.2, phpMyAdmin supports the administration of multiple + MySQL servers. Therefore, a :config:option:`$cfg['Servers']`-array has been + added which contains the login information for the different servers. The + first :config:option:`$cfg['Servers'][$i]['host']` contains the hostname of + the first server, the second :config:option:`$cfg['Servers'][$i]['host']` + the hostname of the second server, etc. In + :file:`libraries/config.default.php`, there is only one section for server + definition, however you can put as many as you need in + :file:`config.inc.php`, copy that block or needed parts (you don't have to + define all settings, just those you need to change). + + .. note:: + + The :config:option:`$cfg['Servers']` array starts with + $cfg['Servers'][1]. Do not use $cfg['Servers'][0]. If you want more + than one server, just copy following section (including $i + incrementation) serveral times. There is no need to define full server + array, just define values you need to change. + + +.. config:option:: $cfg['Servers'][$i]['host'] + + :type: string + :default: ``'localhost'`` + + The hostname or :term:`IP` address of your $i-th MySQL-server. E.g. + ``localhost``. + + Possible values are: + + * hostname, e.g., ``'localhost'`` or ``'mydb.example.org'`` + * IP address, e.g., ``'127.0.0.1'`` or ``'192.168.10.1'`` + * dot - ``'.'``, i.e., use named pipes on windows systems + * empty - ``''``, disables this server + + .. note:: + + phpMyAdmin supports connecting to MySQL servers reachable via IPv6 only. + To connect to an IPv6 MySQL server, enter its IPv6 address in this field. + +.. config:option:: $cfg['Servers'][$i]['port'] + + :type: string + :default: ``''`` + + The port-number of your $i-th MySQL-server. Default is 3306 (leave + blank). + + .. note:: + + If you use ``localhost`` as the hostname, MySQL ignores this port number + and connects with the socket, so if you want to connect to a port + different from the default port, use ``127.0.0.1`` or the real hostname + in :config:option:`$cfg['Servers'][$i]['host']`. + +.. config:option:: $cfg['Servers'][$i]['socket'] + + :type: string + :default: ``''`` + + The path to the socket to use. Leave blank for default. To determine + the correct socket, check your MySQL configuration or, using the + :command:`mysql` command–line client, issue the ``status`` command. Among the + resulting information displayed will be the socket used. + +.. config:option:: $cfg['Servers'][$i]['ssl'] + + :type: boolean + :default: false + + Whether to enable SSL for the connection between phpMyAdmin and the MySQL server. + + When using :config:option:`$cfg['Servers'][$i]['extension']` = ``'mysql'``, + none of the remaining ``'ssl...'`` configuration options apply. + + We strongly recommend using :config:option:`$cfg['Servers'][$i]['extension']` = ``'mysqli'`` + when using this option. + +.. config:option:: $cfg['Servers'][$i]['ssl_key'] + + :type: string + :default: NULL + + Path to the key file when using SSL for connecting to the MySQL server. + + For example: + + .. code-block:: php + + $cfg['Servers'][$i]['ssl_key'] = '/etc/mysql/server-key.pem'; + +.. config:option:: $cfg['Servers'][$i]['ssl_cert'] + + :type: string + :default: NULL + + Path to the cert file when using SSL for connecting to the MySQL server. + +.. config:option:: $cfg['Servers'][$i]['ssl_ca'] + + :type: string + :default: NULL + + Path to the CA file when using SSL for connecting to the MySQL server. + +.. config:option:: $cfg['Servers'][$i]['ssl_ca_path'] + + :type: string + :default: NULL + + Directory containing trusted SSL CA certificates in PEM format. + +.. config:option:: $cfg['Servers'][$i]['ssl_ciphers'] + + :type: string + :default: NULL + + List of allowable ciphers for SSL connections to the MySQL server. + +.. config:option:: $cfg['Servers'][$i]['connect_type'] + + :type: string + :default: ``'tcp'`` + + What type connection to use with the MySQL server. Your options are + ``'socket'`` and ``'tcp'``. It defaults to tcp as that is nearly guaranteed + to be available on all MySQL servers, while sockets are not supported on + some platforms. To use the socket mode, your MySQL server must be on the + same machine as the Web server. + +.. config:option:: $cfg['Servers'][$i]['extension'] + + :type: string + :default: ``'mysqli'`` + + What php MySQL extension to use for the connection. Valid options are: + + ``mysql`` + The classic MySQL extension. + + ``mysqli`` + The improved MySQL extension. This extension became available with PHP + 5.0.0 and is the recommended way to connect to a server running MySQL + 4.1.x or newer. + +.. config:option:: $cfg['Servers'][$i]['compress'] + + :type: boolean + :default: false + + Whether to use a compressed protocol for the MySQL server connection + or not (experimental). + +.. _controlhost: +.. config:option:: $cfg['Servers'][$i]['controlhost'] + + :type: string + :default: ``''`` + + Permits to use an alternate host to hold the configuration storage + data. + +.. _controlport: +.. config:option:: $cfg['Servers'][$i]['controlport'] + + :type: string + :default: ``''`` + + Permits to use an alternate port to connect to the host that + holds the configuration storage. + +.. _controluser: +.. config:option:: $cfg['Servers'][$i]['controluser'] + + :type: string + :default: ``''`` + +.. config:option:: $cfg['Servers'][$i]['controlpass'] + + :type: string + :default: ``''`` + + This special account is used for 2 distinct purposes: to make possible all + relational features (see :config:option:`$cfg['Servers'][$i]['pmadb']`) and, + for a MySQL server running with ``--skip-show-database``, to enable a + multi-user installation (:term:`HTTP` or cookie + authentication mode). + + When using :term:`HTTP` or + cookie authentication modes (or 'config' authentication mode since phpMyAdmin + 2.2.1), you need to supply the details of a MySQL account that has ``SELECT`` + privilege on the *mysql.user (all columns except "Password")*, *mysql.db (all + columns)* and *mysql.tables\_priv (all columns except "Grantor" and + "Timestamp")* tables. This account is used to check what databases the user + will see at login. + + .. versionchanged:: 2.2.5 + those were called ``stduser`` and ``stdpass`` + + .. seealso:: :ref:`setup`, :ref:`authentication_modes` + +.. config:option:: $cfg['Servers'][$i]['auth_type'] + + :type: string + :default: ``'cookie'`` + + Whether config or cookie or :term:`HTTP` or signon authentication should be + used for this server. + + * 'config' authentication (``$auth_type = 'config'``) is the plain old + way: username and password are stored in :file:`config.inc.php`. + * 'cookie' authentication mode (``$auth_type = 'cookie'``) as + introduced in 2.2.3 allows you to log in as any valid MySQL user with + the help of cookies. Username and password are stored in cookies + during the session and password is deleted when it ends. This can also + allow you to log in in arbitrary server if :config:option:`$cfg['AllowArbitraryServer']` enabled. + * 'http' authentication (was + called 'advanced' in previous versions and can be written also as + 'http') (``$auth_type = 'http';'``) as introduced in 1.3.0 allows you to log in as any + valid MySQL user via HTTP-Auth. + * 'signon' authentication mode (``$auth_type = 'signon'``) as + introduced in 2.10.0 allows you to log in from prepared PHP session + data or using supplied PHP script. This is useful for implementing + single signon from another application. Sample way how to seed session + is in signon example: :file:`examples/signon.php`. There is also + alternative example using OpenID - :file:`examples/openid.php` and example + for scripts based solution - :file:`examples/signon-script.php`. You need + to configure :config:option:`$cfg['Servers'][$i]['SignonSession']` or + :config:option:`$cfg['Servers'][$i]['SignonScript']` and + :config:option:`$cfg['Servers'][$i]['SignonURL']` to use this authentication + method. + + .. seealso:: :ref:`authentication_modes` + +.. _servers_auth_http_realm: +.. config:option:: $cfg['Servers'][$i]['auth_http_realm'] + + :type: string + :default: ``''`` + + When using auth\_type = ``http``, this field allows to define a custom + :term:`HTTP` Basic Auth Realm which will be displayed to the user. If not + explicitly specified in your configuration, a string combined of + "phpMyAdmin " and either :config:option:`$cfg['Servers'][$i]['verbose']` or + :config:option:`$cfg['Servers'][$i]['host']` will be used. + +.. _servers_auth_swekey_config: +.. config:option:: $cfg['Servers'][$i]['auth_swekey_config'] + + :type: string + :default: ``''`` + + The name of the file containing :ref:`swekey` ids and login names for hardware + authentication. Leave empty to deactivate this feature. + +.. _servers_user: +.. config:option:: $cfg['Servers'][$i]['user'] + + :type: string + :default: ``'root'`` + +.. config:option:: $cfg['Servers'][$i]['password'] + + :type: string + :default: ``''`` + + When using :config:option:`$cfg['Servers'][$i]['auth_type']` set to + 'config', this is the user/password-pair which phpMyAdmin will use to + connect to the MySQL server. This user/password pair is not needed when + :term:`HTTP` or cookie authentication is used + and should be empty. + +.. _servers_nopassword: +.. config:option:: $cfg['Servers'][$i]['nopassword'] + + :type: boolean + :default: false + + Allow attempt to log in without password when a login with password + fails. This can be used together with http authentication, when + authentication is done some other way and phpMyAdmin gets user name + from auth and uses empty password for connecting to MySQL. Password + login is still tried first, but as fallback, no password method is + tried. + +.. _servers_only_db: +.. config:option:: $cfg['Servers'][$i]['only_db'] + + :type: string or array + :default: ``''`` + + If set to a (an array of) database name(s), only this (these) + database(s) will be shown to the user. Since phpMyAdmin 2.2.1, + this/these database(s) name(s) may contain MySQL wildcards characters + ("\_" and "%"): if you want to use literal instances of these + characters, escape them (I.E. use ``'my\_db'`` and not ``'my_db'``). + + This setting is an efficient way to lower the server load since the + latter does not need to send MySQL requests to build the available + database list. But **it does not replace the privileges rules of the + MySQL database server**. If set, it just means only these databases + will be displayed but **not that all other databases can't be used.** + + An example of using more that one database: + + .. code-block:: php + + $cfg['Servers'][$i]['only_db'] = array('db1', 'db2'); + + .. versionchanged:: 4.0.0 + Previous versions permitted to specify the display order of + the database names via this directive. + +.. config:option:: $cfg['Servers'][$i]['hide_db'] + + :type: string + :default: ``''`` + + Regular expression for hiding some databases from unprivileged users. + This only hides them from listing, but a user is still able to access + them (using, for example, the SQL query area). To limit access, use + the MySQL privilege system. For example, to hide all databases + starting with the letter "a", use + + .. code-block:: php + + $cfg['Servers'][$i]['hide_db'] = '^a'; + + and to hide both "db1" and "db2" use + + .. code-block:: php + + $cfg['Servers'][$i]['hide_db'] = '^(db1|db2)$'; + + More information on regular expressions can be found in the `PCRE + pattern syntax + `_ portion + of the PHP reference manual. + +.. config:option:: $cfg['Servers'][$i]['verbose'] + + :type: string + :default: ``''`` + + Only useful when using phpMyAdmin with multiple server entries. If + set, this string will be displayed instead of the hostname in the + pull-down menu on the main page. This can be useful if you want to + show only certain databases on your system, for example. For HTTP + auth, all non-US-ASCII characters will be stripped. + +.. config:option:: $cfg['Servers'][$i]['pmadb'] + + :type: string + :default: ``''`` + + The name of the database containing the phpMyAdmin configuration + storage. + + See the :ref:`linked-tables` section in this document to see the benefits of + this feature, and for a quick way of creating this database and the needed + tables. + + If you are the only user of this phpMyAdmin installation, you can use your + current database to store those special tables; in this case, just put your + current database name in :config:option:`$cfg['Servers'][$i]['pmadb']`. For a + multi-user installation, set this parameter to the name of your central + database containing the phpMyAdmin configuration storage. + +.. _bookmark: +.. config:option:: $cfg['Servers'][$i]['bookmarktable'] + + :type: string + :default: ``''`` + + Since release 2.2.0 phpMyAdmin allows users to bookmark queries. This + can be useful for queries you often run. To allow the usage of this + functionality: + + * set up :config:option:`$cfg['Servers'][$i]['pmadb']` and the phpMyAdmin configuration storage + * enter the table name in :config:option:`$cfg['Servers'][$i]['bookmarktable']` + + +.. _relation: +.. config:option:: $cfg['Servers'][$i]['relation'] + + :type: string + :default: ``''`` + + Since release 2.2.4 you can describe, in a special 'relation' table, + which column is a key in another table (a foreign key). phpMyAdmin + currently uses this to: + + * make clickable, when you browse the master table, the data values that + point to the foreign table; + * display in an optional tool-tip the "display column" when browsing the + master table, if you move the mouse to a column containing a foreign + key (use also the 'table\_info' table); (see :ref:`faqdisplay`) + * in edit/insert mode, display a drop-down list of possible foreign keys + (key value and "display column" are shown) (see :ref:`faq6_21`) + * display links on the table properties page, to check referential + integrity (display missing foreign keys) for each described key; + * in query-by-example, create automatic joins (see :ref:`faq6_6`) + * enable you to get a :term:`PDF` schema of + your database (also uses the table\_coords table). + + The keys can be numeric or character. + + To allow the usage of this functionality: + + * set up :config:option:`$cfg['Servers'][$i]['pmadb']` and the phpMyAdmin configuration storage + * put the relation table name in :config:option:`$cfg['Servers'][$i]['relation']` + * now as normal user open phpMyAdmin and for each one of your tables + where you want to use this feature, click :guilabel:`Structure/Relation view/` + and choose foreign columns. + + .. note:: + + In the current version, ``master_db`` must be the same as ``foreign_db``. + Those columns have been put in future development of the cross-db + relations. + +.. _table_info: +.. config:option:: $cfg['Servers'][$i]['table_info'] + + :type: string + :default: ``''`` + + Since release 2.3.0 you can describe, in a special 'table\_info' + table, which column is to be displayed as a tool-tip when moving the + cursor over the corresponding key. This configuration variable will + hold the name of this special table. To allow the usage of this + functionality: + + * set up :config:option:`$cfg['Servers'][$i]['pmadb']` and the phpMyAdmin configuration storage + * put the table name in :config:option:`$cfg['Servers'][$i]['table\_info']` (e.g. + ``pma__table_info``) + * then for each table where you want to use this feature, click + "Structure/Relation view/Choose column to display" to choose the + column. + + .. seealso:: :ref:`faqdisplay` + +.. _table_coords: +.. config:option:: $cfg['Servers'][$i]['table_coords'] + + :type: string + :default: ``''`` + +.. config:option:: $cfg['Servers'][$i]['pdf_pages'] + + :type: string + :default: ``''`` + + Since release 2.3.0 you can have phpMyAdmin create :term:`PDF` pages + showing the relations between your tables. To do this it needs two tables + "pdf\_pages" (storing information about the available :term:`PDF` pages) + and "table\_coords" (storing coordinates where each table will be placed on + a :term:`PDF` schema output). You must be using the "relation" feature. + + To allow the usage of this functionality: + + * set up :config:option:`$cfg['Servers'][$i]['pmadb']` and the phpMyAdmin configuration storage + * put the correct table names in + :config:option:`$cfg['Servers'][$i]['table\_coords']` and + :config:option:`$cfg['Servers'][$i]['pdf\_pages']` + + .. seealso:: :ref:`faqpdf`. + +.. _col_com: +.. config:option:: $cfg['Servers'][$i]['column_info'] + + :type: string + :default: ``''`` + + This part requires a content update! Since release 2.3.0 you can + store comments to describe each column for each table. These will then + be shown on the "printview". + + Starting with release 2.5.0, comments are consequently used on the table + property pages and table browse view, showing up as tool-tips above the + column name (properties page) or embedded within the header of table in + browse view. They can also be shown in a table dump. Please see the + relevant configuration directives later on. + + Also new in release 2.5.0 is a MIME- transformation system which is also + based on the following table structure. See :ref:`transformations` for + further information. To use the MIME- transformation system, your + column\_info table has to have the three new columns 'mimetype', + 'transformation', 'transformation\_options'. + + + To allow the usage of this functionality: + + * set up :config:option:`$cfg['Servers'][$i]['pmadb']` and the phpMyAdmin configuration storage + * put the table name in :config:option:`$cfg['Servers'][$i]['column\_info']` (e.g. + ``pma__column_info``) + * to update your PRE-2.5.0 Column\_comments Table use this: and + remember that the Variable in :file:`config.inc.php` has been renamed from + :config:option:`$cfg['Servers'][$i]['column\_comments']` to + :config:option:`$cfg['Servers'][$i]['column\_info']` + + .. code-block:: mysql + + ALTER TABLE `pma__column_comments` + ADD `mimetype` VARCHAR( 255 ) NOT NULL, + ADD `transformation` VARCHAR( 255 ) NOT NULL, + ADD `transformation_options` VARCHAR( 255 ) NOT NULL; + +.. _history: +.. config:option:: $cfg['Servers'][$i]['history'] + + :type: string + :default: ``''`` + + Since release 2.5.0 you can store your :term:`SQL` history, which means all + queries you entered manually into the phpMyAdmin interface. If you don't + want to use a table-based history, you can use the JavaScript-based + history. + + Using that, all your history items are deleted when closing the window. + Using :config:option:`$cfg['QueryHistoryMax']` you can specify an amount of + history items you want to have on hold. On every login, this list gets cut + to the maximum amount. + + The query history is only available if JavaScript is enabled in + your browser. + + To allow the usage of this functionality: + + * set up :config:option:`$cfg['Servers'][$i]['pmadb']` and the phpMyAdmin configuration storage + * put the table name in :config:option:`$cfg['Servers'][$i]['history']` (e.g. + ``pma__history``) + +.. _recent: +.. config:option:: $cfg['Servers'][$i]['recent'] + + :type: string + :default: ``''`` + + Since release 3.5.0 you can show recently used tables in the + navigation panel. It helps you to jump across table directly, without + the need to select the database, and then select the table. Using + :config:option:`$cfg['NumRecentTables']` you can configure the maximum number + of recent tables shown. When you select a table from the list, it will jump to + the page specified in :config:option:`$cfg['NavigationTreeDefaultTabTable']`. + + + Without configuring the storage, you can still access the recently used tables, + but it will disappear after you logout. + + To allow the usage of this functionality persistently: + + * set up :config:option:`$cfg['Servers'][$i]['pmadb']` and the phpMyAdmin configuration storage + * put the table name in :config:option:`$cfg['Servers'][$i]['recent']` (e.g. + ``pma__recent``) + +.. _table_uiprefs: +.. config:option:: $cfg['Servers'][$i]['table_uiprefs'] + + :type: string + :default: ``''`` + + Since release 3.5.0 phpMyAdmin can be configured to remember several + things (sorted column :config:option:`$cfg['RememberSorting']`, column order, + and column visibility from a database table) for browsing tables. Without + configuring the storage, these features still can be used, but the values will + disappear after you logout. + + To allow the usage of these functionality persistently: + + * set up :config:option:`$cfg['Servers'][$i]['pmadb']` and the phpMyAdmin configuration storage + * put the table name in :config:option:`$cfg['Servers'][$i]['table\_uiprefs']` (e.g. + ``pma__table_uiprefs``) + +.. _configurablemenus: +.. config:option:: $cfg['Servers'][$i]['users'] + + :type: string + :default: ``''`` + +.. config:option:: $cfg['Servers'][$i]['usergroups'] + + :type: string + :default: ``''`` + + Since release 4.1.0 you can create different user groups with menu items + attached to them. Users can be assigned to these groups and the logged in + user would only see menu items configured to the usergroup he is assigned to. + To do this it needs two tables "usergroups" (storing allowed menu items for each + user group) and "users" (storing users and their assignments to user groups). + + To allow the usage of this functionality: + + * set up :config:option:`$cfg['Servers'][$i]['pmadb']` and the phpMyAdmin configuration storage + * put the correct table names in + :config:option:`$cfg['Servers'][$i]['users']` (e.g. ``pma__users``) and + :config:option:`$cfg['Servers'][$i]['usergroups']` (e.g. ``pma__usergroups``) + +.. _navigationhiding: +.. config:option:: $cfg['Servers'][$i]['navigationhiding'] + + :type: string + :default: ``''`` + + Since release 4.1.0 you can hide/show items in the navigation tree. + + To allow the usage of this functionality: + + * set up :config:option:`$cfg['Servers'][$i]['pmadb']` and the phpMyAdmin configuration storage + * put the table name in :config:option:`$cfg['Servers'][$i]['navigationhiding']` (e.g. + ``pma__navigationhiding``) + +.. _tracking: +.. config:option:: $cfg['Servers'][$i]['tracking'] + + :type: string + :default: ``''`` + + Since release 3.3.x a tracking mechanism is available. It helps you to + track every :term:`SQL` command which is + executed by phpMyAdmin. The mechanism supports logging of data + manipulation and data definition statements. After enabling it you can + create versions of tables. + + The creation of a version has two effects: + + * phpMyAdmin saves a snapshot of the table, including structure and + indexes. + * phpMyAdmin logs all commands which change the structure and/or data of + the table and links these commands with the version number. + + Of course you can view the tracked changes. On the :guilabel:`Tracking` + page a complete report is available for every version. For the report you + can use filters, for example you can get a list of statements within a date + range. When you want to filter usernames you can enter \* for all names or + you enter a list of names separated by ','. In addition you can export the + (filtered) report to a file or to a temporary database. + + To allow the usage of this functionality: + + * set up :config:option:`$cfg['Servers'][$i]['pmadb']` and the phpMyAdmin configuration storage + * put the table name in :config:option:`$cfg['Servers'][$i]['tracking']` (e.g. + ``pma__tracking``) + + +.. _tracking2: +.. config:option:: $cfg['Servers'][$i]['tracking_version_auto_create'] + + :type: boolean + :default: false + + Whether the tracking mechanism creates versions for tables and views + automatically. + + If this is set to true and you create a table or view with + + * CREATE TABLE ... + * CREATE VIEW ... + + and no version exists for it, the mechanism will create a version for + you automatically. + +.. _tracking3: +.. config:option:: $cfg['Servers'][$i]['tracking_default_statements'] + + :type: string + :default: ``'CREATE TABLE,ALTER TABLE,DROP TABLE,RENAME TABLE,CREATE INDEX,DROP INDEX,INSERT,UPDATE,DELETE,TRUNCATE,REPLACE,CREATE VIEW,ALTER VIEW,DROP VIEW,CREATE DATABASE,ALTER DATABASE,DROP DATABASE'`` + + Defines the list of statements the auto-creation uses for new + versions. + +.. _tracking4: +.. config:option:: $cfg['Servers'][$i]['tracking_add_drop_view'] + + :type: boolean + :default: true + + Whether a DROP VIEW IF EXISTS statement will be added as first line to + the log when creating a view. + +.. _tracking5: +.. config:option:: $cfg['Servers'][$i]['tracking_add_drop_table'] + + :type: boolean + :default: true + + Whether a DROP TABLE IF EXISTS statement will be added as first line + to the log when creating a table. + +.. _tracking6: +.. config:option:: $cfg['Servers'][$i]['tracking_add_drop_database'] + + :type: boolean + :default: true + + Whether a DROP DATABASE IF EXISTS statement will be added as first + line to the log when creating a database. + +.. _userconfig: +.. config:option:: $cfg['Servers'][$i]['userconfig'] + + :type: string + :default: ``''`` + + Since release 3.4.x phpMyAdmin allows users to set most preferences by + themselves and store them in the database. + + If you don't allow for storing preferences in + :config:option:`$cfg['Servers'][$i]['pmadb']`, users can still personalize + phpMyAdmin, but settings will be saved in browser's local storage, or, it + is is unavailable, until the end of session. + + To allow the usage of this functionality: + + * set up :config:option:`$cfg['Servers'][$i]['pmadb']` and the phpMyAdmin configuration storage + * put the table name in :config:option:`$cfg['Servers'][$i]['userconfig']` + + + +.. _designer_coords: +.. config:option:: $cfg['Servers'][$i]['designer_coords'] + + :type: string + :default: ``''`` + + Since release 2.10.0 a Designer interface is available; it permits to + visually manage the relations. + + To allow the usage of this functionality: + + * set up :config:option:`$cfg['Servers'][$i]['pmadb']` and the phpMyAdmin configuration storage + * put the table name in :config:option:`$cfg['Servers'][$i]['designer\_coords']` + (e.g. ``pma__designer_coords``) + + + +.. config:option:: $cfg['Servers'][$i]['MaxTableUiprefs'] + + :type: integer + :default: 100 + + Maximum number of rows saved in + :config:option:`$cfg['Servers'][$i]['table_uiprefs']` table. + + When tables are dropped or renamed, + :config:option:`$cfg['Servers'][$i]['table_uiprefs']` may contain invalid data + (referring to tables which no longer exist). We only keep this number of newest + rows in :config:option:`$cfg['Servers'][$i]['table_uiprefs']` and automatically + delete older rows. + +.. config:option:: $cfg['Servers'][$i]['AllowRoot'] + + :type: boolean + :default: true + + Whether to allow root access. This is just a shortcut for the + :config:option:`$cfg['Servers'][$i]['AllowDeny']['rules']` below. + +.. config:option:: $cfg['Servers'][$i]['AllowNoPassword'] + + :type: boolean + :default: false + + Whether to allow logins without a password. The default value of + ``false`` for this parameter prevents unintended access to a MySQL + server with was left with an empty password for root or on which an + anonymous (blank) user is defined. + +.. _servers_allowdeny_order: +.. config:option:: $cfg['Servers'][$i]['AllowDeny']['order'] + + :type: string + :default: ``''`` + + If your rule order is empty, then :term:`IP` + authorization is disabled. + + If your rule order is set to + ``'deny,allow'`` then the system applies all deny rules followed by + allow rules. Access is allowed by default. Any client which does not + match a Deny command or does match an Allow command will be allowed + access to the server. + + If your rule order is set to ``'allow,deny'`` + then the system applies all allow rules followed by deny rules. Access + is denied by default. Any client which does not match an Allow + directive or does match a Deny directive will be denied access to the + server. + + If your rule order is set to ``'explicit'``, authorization is + performed in a similar fashion to rule order 'deny,allow', with the + added restriction that your host/username combination **must** be + listed in the *allow* rules, and not listed in the *deny* rules. This + is the **most** secure means of using Allow/Deny rules, and was + available in Apache by specifying allow and deny rules without setting + any order. + + Please also see :config:option:`$cfg['TrustedProxies']` for + detecting IP address behind proxies. + +.. _servers_allowdeny_rules: +.. config:option:: $cfg['Servers'][$i]['AllowDeny']['rules'] + + :type: array of strings + :default: array() + + The general format for the rules is as such: + + .. code-block:: none + + <'allow' | 'deny'> [from] + + If you wish to match all users, it is possible to use a ``'%'`` as a + wildcard in the *username* field. + + There are a few shortcuts you can + use in the *ipmask* field as well (please note that those containing + SERVER\_ADDRESS might not be available on all webservers): + + .. code-block:: none + + + 'all' -> 0.0.0.0/0 + 'localhost' -> 127.0.0.1/8 + 'localnetA' -> SERVER_ADDRESS/8 + 'localnetB' -> SERVER_ADDRESS/16 + 'localnetC' -> SERVER_ADDRESS/24 + + Having an empty rule list is equivalent to either using ``'allow % + from all'`` if your rule order is set to ``'deny,allow'`` or ``'deny % + from all'`` if your rule order is set to ``'allow,deny'`` or + ``'explicit'``. + + For the :term:`IP address` matching + system, the following work: + + * ``xxx.xxx.xxx.xxx`` (an exact :term:`IP address`) + * ``xxx.xxx.xxx.[yyy-zzz]`` (an :term:`IP address` range) + * ``xxx.xxx.xxx.xxx/nn`` (CIDR, Classless Inter-Domain Routing type :term:`IP` addresses) + + But the following does not work: + + * ``xxx.xxx.xxx.xx[yyy-zzz]`` (partial :term:`IP` address range) + + For :term:`IPv6` addresses, the following work: + + * ``xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx`` (an exact :term:`IPv6` address) + * ``xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:[yyyy-zzzz]`` (an :term:`IPv6` address range) + * ``xxxx:xxxx:xxxx:xxxx/nn`` (CIDR, Classless Inter-Domain Routing type :term:`IPv6` addresses) + + But the following does not work: + + * ``xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xx[yyy-zzz]`` (partial :term:`IPv6` address range) + +.. config:option:: $cfg['Servers'][$i]['SignonScript'] + + :type: string + :default: ``''`` + + Name of PHP script to be sourced and executed to obtain login + credentials. This is alternative approach to session based single + signon. The script needs to provide function + ``get_login_credentials`` which returns list of username and + password, accepting single parameter of existing username (can be + empty). See :file:`examples/signon-script.php` for an example. + +.. config:option:: $cfg['Servers'][$i]['SignonSession'] + + :type: string + :default: ``''`` + + Name of session which will be used for signon authentication method. + You should use something different than ``phpMyAdmin``, because this + is session which phpMyAdmin uses internally. Takes effect only if + :config:option:`$cfg['Servers'][$i]['SignonScript']` is not configured. + +.. config:option:: $cfg['Servers'][$i]['SignonURL'] + + :type: string + :default: ``''`` + + :term:`URL` where user will be redirected + to log in for signon authentication method. Should be absolute + including protocol. + +.. config:option:: $cfg['Servers'][$i]['LogoutURL'] + + :type: string + :default: ``''`` + + :term:`URL` where user will be redirected + after logout (doesn't affect config authentication method). Should be + absolute including protocol. + +.. config:option:: $cfg['Servers'][$i]['StatusCacheDatabases'] + + :type: array of strings + :default: array() + + Enables caching of ``TABLE STATUS`` outputs for specific databases on + this server (in some cases ``TABLE STATUS`` can be very slow, so you + may want to cache it). APC is used (if the PHP extension is available, + if not, this setting is ignored silently). You have to provide + :config:option:`$cfg['Servers'][$i]['StatusCacheLifetime']`. + +.. config:option:: $cfg['Servers'][$i]['StatusCacheLifetime'] + + :type: integer + :default: 0 + + Lifetime in seconds of the ``TABLE STATUS`` cache if + :config:option:`$cfg['Servers'][$i]['StatusCacheDatabases']` is used. + +Generic settings +---------------- + +.. config:option:: $cfg['ServerDefault'] + + :type: integer + :default: 1 + + If you have more than one server configured, you can set + :config:option:`$cfg['ServerDefault']` to any one of them to autoconnect to that + server when phpMyAdmin is started, or set it to 0 to be given a list + of servers without logging in. + + If you have only one server configured, + :config:option:`$cfg['ServerDefault']` MUST be set to that server. + +.. config:option:: $cfg['VersionCheck'] + + :type: boolean + :default: true + + Enables check for latest versions using javascript on main phpMyAdmin + page. + + .. note:: + + This setting can be adjusted by your vendor. + +.. config:option:: $cfg['ProxyUrl'] + + :type: string + :default: "" + + The url of the proxy to be used when phpmyadmin needs to access the outside + intenet such as when retrieving the latest version info or submitting error + reports. You need this if the server where phpMyAdmin is installed does not + have direct access to the internet. + The format is: "hostname:portnumber" + +.. config:option:: $cfg['ProxyUser'] + + :type: string + :default: "" + + The username for authenticating with the proxy. By default, no + authentication is performed. If a username is supplied, Basic + Authentication will be performed. No other types of authentication + are currently supported. + +.. config:option:: $cfg['ProxyPass'] + + :type: string + :default: "" + + The password for authenticating with the proxy. + +.. config:option:: $cfg['MaxDbList'] + + :type: integer + :default: 100 + + The maximum number of database names to be displayed in the main panel's + database list. + +.. config:option:: $cfg['MaxTableList'] + + :type: integer + :default: 250 + + The maximum number of table names to be displayed in the main panel's + list (except on the Export page). This limit is also enforced in the + navigation panel when in Light mode. + +.. config:option:: $cfg['ShowHint'] + + :type: boolean + :default: true + + Whether or not to show hints (for example, hints when hovering over + table headers). + +.. config:option:: $cfg['MaxCharactersInDisplayedSQL'] + + :type: integer + :default: 1000 + + The maximum number of characters when a :term:`SQL` query is displayed. The + default limit of 1000 should be correct to avoid the display of tons of + hexadecimal codes that represent BLOBs, but some users have real + :term:`SQL` queries that are longer than 1000 characters. Also, if a + query's length exceeds this limit, this query is not saved in the history. + +.. config:option:: $cfg['PersistentConnections'] + + :type: boolean + :default: false + + Whether `persistent connections `_ should be used or not. Works with + following extensions: + + * mysql (`mysql\_pconnect `_), + * mysqli (requires PHP 5.3.0 or newer, `more information + `_). + +.. config:option:: $cfg['ForceSSL'] + + :type: boolean + :default: false + + Whether to force using https while accessing phpMyAdmin. + + .. note:: + + In some setups (like separate SSL proxy or load balancer) you might + have to set :config:option:`$cfg['PmaAbsoluteUri']` for correct + redirection. + +.. config:option:: $cfg['ExecTimeLimit'] + + :type: integer [number of seconds] + :default: 300 + + Set the number of seconds a script is allowed to run. If seconds is + set to zero, no time limit is imposed. This setting is used while + importing/exporting dump files but has + no effect when PHP is running in safe mode. + +.. config:option:: $cfg['SessionSavePath'] + + :type: string + :default: ``''`` + + Path for storing session data (`session\_save\_path PHP parameter + `_). + +.. config:option:: $cfg['MemoryLimit'] + + :type: string [number of bytes] + :default: ``'-1'`` + + Set the number of bytes a script is allowed to allocate. If set to + ``'-1'``, no limit is imposed. + + This setting is used while importing/exporting dump files and at some other + places in phpMyAdmin so you definitely don't want to put here a too low + value. It has no effect when PHP is running in safe mode. + + You can also use any string as in :file:`php.ini`, eg. '16M'. Ensure you + don't omit the suffix (16 means 16 bytes!) + +.. config:option:: $cfg['SkipLockedTables'] + + :type: boolean + :default: false + + Mark used tables and make it possible to show databases with locked + tables (since MySQL 3.23.30). + +.. config:option:: $cfg['ShowSQL'] + + :type: boolean + :default: true + + Defines whether :term:`SQL` queries + generated by phpMyAdmin should be displayed or not. + +.. config:option:: $cfg['RetainQueryBox'] + + :type: boolean + :default: false + + Defines whether the :term:`SQL` query box + should be kept displayed after its submission. + +.. config:option:: $cfg['CodemirrorEnable'] + + :type: boolean + :default: true + + Defines whether to use a Javascript code editor for SQL query boxes. + CodeMirror provides syntax highlighting and line numbers. However, + middle-clicking for pasting the clipboard contents in some Linux + distributions (such as Ubuntu) is not supported by all browsers. + +.. config:option:: $cfg['AllowUserDropDatabase'] + + :type: boolean + :default: false + + Defines whether normal users (non-administrator) are allowed to delete + their own database or not. If set as false, the link :guilabel:`Drop + Database` will not be shown, and even a ``DROP DATABASE mydatabase`` will + be rejected. Quite practical for :term:`ISP` 's with many customers. + + .. note:: + + This limitation of :term:`SQL` queries is not + as strict as when using MySQL privileges. This is due to nature of + :term:`SQL` queries which might be quite + complicated. So this choice should be viewed as help to avoid accidental + dropping rather than strict privilege limitation. + +.. config:option:: $cfg['Confirm'] + + :type: boolean + :default: true + + Whether a warning ("Are your really sure...") should be displayed when + you're about to lose data. + +.. config:option:: $cfg['UseDbSearch'] + + :type: boolean + :default: true + + Define whether the "search string inside database" is enabled or not. + +.. config:option:: $cfg['IgnoreMultiSubmitErrors'] + + :type: boolean + :default: false + + Define whether phpMyAdmin will continue executing a multi-query + statement if one of the queries fails. Default is to abort execution. + +Cookie authentication options +----------------------------- + +.. config:option:: $cfg['blowfish_secret'] + + :type: string + :default: ``''`` + + The "cookie" auth\_type uses blowfish algorithm to encrypt the + password. If you are using the "cookie" auth\_type, enter here a + random passphrase of your choice. It will be used internally by the + blowfish algorithm: you won’t be prompted for this passphrase. There + is no maximum length for this secret. + + .. versionchanged:: 3.1.0 + Since version 3.1.0 phpMyAdmin can generate this on the fly, but it + makes a bit weaker security as this generated secret is stored in + session and furthermore it makes impossible to recall user name from + cookie. + +.. config:option:: $cfg['LoginCookieRecall'] + + :type: boolean + :default: true + + Define whether the previous login should be recalled or not in cookie + authentication mode. + + This is automatically disabled if you do not have + configured :config:option:`$cfg['blowfish_secret']`. + +.. config:option:: $cfg['LoginCookieValidity'] + + :type: integer [number of seconds] + :default: 1440 + + Define how long a login cookie is valid. Please note that php + configuration option `session.gc\_maxlifetime + `_ might limit session validity and if the session is lost, + the login cookie is also invalidated. So it is a good idea to set + ``session.gc_maxlifetime`` at least to the same value of + :config:option:`$cfg['LoginCookieValidity']`. + +.. config:option:: $cfg['LoginCookieStore'] + + :type: integer [number of seconds] + :default: 0 + + Define how long login cookie should be stored in browser. Default 0 + means that it will be kept for existing session. This is recommended + for not trusted environments. + +.. config:option:: $cfg['LoginCookieDeleteAll'] + + :type: boolean + :default: true + + If enabled (default), logout deletes cookies for all servers, + otherwise only for current one. Setting this to false makes it easy to + forget to log out from other server, when you are using more of them. + +.. _AllowArbitraryServer: +.. config:option:: $cfg['AllowArbitraryServer'] + + :type: boolean + :default: false + + If enabled, allows you to log in to arbitrary servers using cookie + authentication. + + .. note:: + + Please use this carefully, as this may allow users access to MySQL servers + behind the firewall where your :term:`HTTP` + server is placed. + +.. config:option:: $cfg['CaptchaLoginPublicKey'] + + :type: string + :default: ``''`` + + The public key for the reCaptcha service that can be obtain from + http://www.google.com/recaptcha. + + reCaptcha will be then used in :ref:`cookie`. + +.. config:option:: $cfg['CaptchaLoginPrivateKey'] + + :type: string + :default: ``''`` + + The private key for the reCaptcha service that can be obtain from + http://www.google.com/recaptcha. + + reCaptcha will be then used in :ref:`cookie`. + +Navigation panel setup +---------------------- + +.. config:option:: $cfg['MaxNavigationItems'] + + :type: integer + :default: 250 + + The number of items that can be displayed on each page of the + navigation tree. + +.. config:option:: $cfg['NavigationTreeEnableGrouping'] + + :type: boolean + :default: true + + Defines whether to group the databases based on a common prefix + in their name :config:option:`$cfg['NavigationTreeDbSeparator']`. + +.. config:option:: $cfg['NavigationTreeDbSeparator'] + + :type: string or array + :default: ``'_'`` + + The string used to separate the parts of the database name when + showing them in a tree. Alternatively you can specify more strings in + an array and all of them will be used as a separator. + +.. config:option:: $cfg['NavigationTreeTableSeparator'] + + :type: string or array + :default: ``'__'`` + + Defines a string to be used to nest table spaces. This means if you have + tables like ``first__second__third`` this will be shown as a three-level + hierarchy like: first > second > third. If set to false or empty, the + feature is disabled. NOTE: You should not use this separator at the + beginning or end of a table name or multiple times after another without + any other characters in between. + +.. config:option:: $cfg['NavigationTreeTableLevel'] + + :type: integer + :default: 1 + + Defines how many sublevels should be displayed when splitting up + tables by the above separator. + +.. config:option:: $cfg['NumRecentTables'] + + :type: integer + :default: 10 + + The maximum number of recently used tables shown in the navigation + panel. Set this to 0 (zero) to disable the listing of recent tables. + +.. config:option:: $cfg['NavigationDisplayLogo'] + + :type: boolean + :default: true + + Defines whether or not to display the phpMyAdmin logo at the top of + the navigation panel. + +.. config:option:: $cfg['NavigationLogoLink'] + + :type: string + :default: ``'index.php'`` + + Enter :term:`URL` where logo in the + navigation panel will point to. For use especially with self made + theme which changes this. + +.. config:option:: $cfg['NavigationLogoLinkWindow'] + + :type: string + :default: ``'main'`` + + Whether to open the linked page in the main window (``main``) or in a + new one (``new``). Note: use ``new`` if you are linking to + ``phpmyadmin.net``. + +.. config:option:: $cfg['NavigationTreeDisplayItemFilterMinimum'] + + :type: integer + :default: 30 + + Defines the minimum number of items (tables, views, routines and + events) to display a JavaScript filter box above the list of items in + the navigation tree. + + To disable the filter completely some high number can be used (e.g. 9999) + +.. config:option:: $cfg['NavigationTreeDisplayDbFilterMinimum'] + + :type: integer + :default: 30 + + Defines the minimum number of databases to display a JavaScript filter + box above the list of databases in the navigation tree. + + To disable the filter completely some high number can be used + (e.g. 9999) + +.. config:option:: $cfg['NavigationDisplayServers'] + + :type: boolean + :default: true + + Defines whether or not to display a server choice at the top of the + navigation panel. + +.. config:option:: $cfg['DisplayServersList'] + + :type: boolean + :default: false + + Defines whether to display this server choice as links instead of in a + drop-down. + +.. config:option:: $cfg['NavigationTreeDefaultTabTable'] + + :type: string + :default: ``'tbl_structure.php'`` + + Defines the tab displayed by default when clicking the small icon next + to each table name in the navigation panel. Possible values: + + * ``tbl_structure.php`` + * ``tbl_sql.php`` + * ``tbl_select.php`` + * ``tbl_change.php`` + * ``sql.php`` + +Main panel +---------- + +.. config:option:: $cfg['ShowStats'] + + :type: boolean + :default: true + + Defines whether or not to display space usage and statistics about + databases and tables. Note that statistics requires at least MySQL + 3.23.3 and that, at this date, MySQL doesn't return such information + for Berkeley DB tables. + +.. config:option:: $cfg['ShowServerInfo'] + + :type: boolean + :default: true + + Defines whether to display detailed server information on main page. + You can additionally hide more information by using + :config:option:`$cfg['Servers'][$i]['verbose']`. + +.. config:option:: $cfg['ShowPhpInfo'] + + :type: boolean + :default: false + +.. config:option:: $cfg['ShowChgPassword'] + + :type: boolean + :default: true + +.. config:option:: $cfg['ShowCreateDb'] + + :type: boolean + :default: true + + Defines whether to display the :guilabel:`PHP information` and + :guilabel:`Change password` links and form for creating database or not at + the starting main (right) frame. This setting does not check MySQL commands + entered directly. + + Please note that to block the usage of ``phpinfo()`` in scripts, you have to + put this in your :file:`php.ini`: + + .. code-block:: ini + + disable_functions = phpinfo() + + Also note that enabling the :guilabel:`Change password` link has no effect + with config authentication mode: because of the hard coded password value + in the configuration file, end users can't be allowed to change their + passwords. + +Database structure +------------------ + +.. config:option:: $cfg['ShowDbStructureCreation'] + + :type: boolean + :default: false + + Defines whether the database structure page (tables list) has a + "Creation" column that displays when each table was created. + +.. config:option:: $cfg['ShowDbStructureLastUpdate'] + + :type: boolean + :default: false + + Defines whether the database structure page (tables list) has a "Last + update" column that displays when each table was last updated. + +.. config:option:: $cfg['ShowDbStructureLastCheck'] + + :type: boolean + :default: false + + Defines whether the database structure page (tables list) has a "Last + check" column that displays when each table was last checked. + +.. config:option:: $cfg['HideStructureActions'] + + :type: boolean + :default: true + + Defines whether the table structure actions are hidden under a "More" + drop-down. + +Browse mode +----------- + +.. config:option:: $cfg['TableNavigationLinksMode'] + + :type: string + :default: ``'icons'`` + + Defines whether the table navigation links contain ``'icons'``, ``'text'`` + or ``'both'``. + +.. config:option:: $cfg['ShowAll'] + + :type: boolean + :default: false + + Defines whether a user should be displayed a "Show all" button in browse + mode or not in all cases. By default it is shown only on small tables (less + than 500 rows) to avoid performance issues while getting too many rows. + +.. config:option:: $cfg['MaxRows'] + + :type: integer + :default: 25 + + Number of rows displayed when browsing a result set and no LIMIT + clause is used. If the result set contains more rows, "Previous" and + "Next" links will be shown. Possible values: 25,50,100,250,500. + +.. config:option:: $cfg['Order'] + + :type: string + :default: ``'SMART'`` + + Defines whether columns are displayed in ascending (``ASC``) order, in + descending (``DESC``) order or in a "smart" (``SMART``) order - I.E. + descending order for columns of type TIME, DATE, DATETIME and + TIMESTAMP, ascending order else- by default. + +.. config:option:: $cfg['DisplayBinaryAsHex'] + + :type: boolean + :default: true + + Defines whether the "Show binary contents as HEX" browse option is + ticked by default. + +.. config:option:: $cfg['GridEditing'] + + :type: string + :default: ``'double-click'`` + + Defines which action (``double-click`` or ``click``) triggers grid + editing. Can be deactived with the ``disabled`` value. + +.. config:option:: $cfg['SaveCellsAtOnce'] + + :type: boolean + :default: false + + Defines whether or not to save all edited cells at once for grid + editing. + +Editing mode +------------ + +.. config:option:: $cfg['ProtectBinary'] + + :type: boolean or string + :default: ``'blob'`` + + Defines whether ``BLOB`` or ``BINARY`` columns are protected from + editing when browsing a table's content. Valid values are: + + * ``false`` to allow editing of all columns; + * ``'blob'`` to allow editing of all columns except ``BLOBS``; + * ``'noblob'`` to disallow editing of all columns except ``BLOBS`` (the + opposite of ``'blob'``); + * ``'all'`` to disallow editing of all ``BINARY`` or ``BLOB`` columns. + +.. config:option:: $cfg['ShowFunctionFields'] + + :type: boolean + :default: true + + Defines whether or not MySQL functions fields should be initially + displayed in edit/insert mode. Since version 2.10, the user can toggle + this setting from the interface. + +.. config:option:: $cfg['ShowFieldTypesInDataEditView'] + + :type: boolean + :default: true + + Defines whether or not type fields should be initially displayed in + edit/insert mode. The user can toggle this setting from the interface. + +.. config:option:: $cfg['InsertRows'] + + :type: integer + :default: 2 + + Defines the maximum number of concurrent entries for the Insert page. + +.. config:option:: $cfg['ForeignKeyMaxLimit'] + + :type: integer + :default: 100 + + If there are fewer items than this in the set of foreign keys, then a + drop-down box of foreign keys is presented, in the style described by + the :config:option:`$cfg['ForeignKeyDropdownOrder']` setting. + +.. config:option:: $cfg['ForeignKeyDropdownOrder'] + + :type: array + :default: array('content-id', 'id-content') + + For the foreign key drop-down fields, there are several methods of + display, offering both the key and value data. The contents of the + array should be one or both of the following strings: ``content-id``, + ``id-content``. + +Export and import settings +-------------------------- + +.. config:option:: $cfg['ZipDump'] + + :type: boolean + :default: true + +.. config:option:: $cfg['GZipDump'] + + :type: boolean + :default: true + +.. config:option:: $cfg['BZipDump'] + + :type: boolean + :default: true + + Defines whether to allow the use of zip/GZip/BZip2 compression when + creating a dump file + +.. config:option:: $cfg['CompressOnFly'] + + :type: boolean + :default: true + + Defines whether to allow on the fly compression for GZip/BZip2 + compressed exports. This doesn't affect smaller dumps and allows users + to create larger dumps that won't otherwise fit in memory due to php + memory limit. Produced files contain more GZip/BZip2 headers, but all + normal programs handle this correctly. + +.. config:option:: $cfg['Export'] + + :type: array + :default: array(...) + + In this array are defined default parameters for export, names of + items are similar to texts seen on export page, so you can easily + identify what they mean. + +.. config:option:: $cfg['Export']['method'] + + :type: string + :default: ``'quick'`` + + Defines how the export form is displayed when it loads. Valid values + are: + + * ``quick`` to display the minimum number of options to configure + * ``custom`` to display every available option to configure + * ``custom-no-form`` same as ``custom`` but does not display the option + of using quick export + + + +.. config:option:: $cfg['Import'] + + :type: array + :default: array(...) + + In this array are defined default parameters for import, names of + items are similar to texts seen on import page, so you can easily + identify what they mean. + + +Tabs display settings +--------------------- + +.. config:option:: $cfg['TabsMode'] + + :type: string + :default: ``'both'`` + + Defines whether the menu tabs contain ``'icons'``, ``'text'`` or ``'both'``. + +.. config:option:: $cfg['ActionLinksMode'] + + :type: string + :default: ``'both'`` + + If set to ``icons``, will display icons instead of text for db and table + properties links (like :guilabel:`Browse`, :guilabel:`Select`, + :guilabel:`Insert`, ...). Can be set to ``'both'`` + if you want icons AND text. When set to ``text``, will only show text. + +.. config:option:: $cfg['PropertiesNumColumns'] + + :type: integer + :default: 1 + + How many columns will be utilized to display the tables on the database + property view? When setting this to a value larger than 1, the type of the + database will be omitted for more display space. + +.. config:option:: $cfg['DefaultTabServer'] + + :type: string + :default: ``'index.php'`` + + Defines the tab displayed by default on server view. Possible values: + + * ``main.php`` (recommended for multi-user setups) + * ``server_databases.php``, + * ``server_status.php`` + * ``server_variables.php`` + * ``server_privileges.php`` + +.. config:option:: $cfg['DefaultTabDatabase'] + + :type: string + :default: ``'db_structure.php'`` + + Defines the tab displayed by default on database view. Possible + values: + + * ``db_structure.php`` + * ``db_sql.php`` + * ``db_search.php``. + +.. config:option:: $cfg['DefaultTabTable'] + + :type: string + :default: ``'sql.php'`` + + Defines the tab displayed by default on table view. Possible values: + + * ``tbl_structure.php`` + * ``tbl_sql.php`` + * ``tbl_select.php`` + * ``tbl_change.php`` + * ``sql.php`` + +PDF Options +----------- + +.. config:option:: $cfg['PDFPageSizes'] + + :type: array + :default: ``array('A3', 'A4', 'A5', 'letter', 'legal')`` + + Array of possible paper sizes for creating PDF pages. + + You should never need to change this. + +.. config:option:: $cfg['PDFDefaultPageSize'] + + :type: string + :default: ``'A4'`` + + Default page size to use when creating PDF pages. Valid values are any + listed in :config:option:`$cfg['PDFPageSizes']`. + +Languages +--------- + +.. config:option:: $cfg['DefaultLang'] + + :type: string + :default: ``'en'`` + + Defines the default language to use, if not browser-defined or user- + defined. The corresponding language file needs to be in + locale/*code*/LC\_MESSAGES/phpmyadmin.mo. + +.. config:option:: $cfg['DefaultConnectionCollation'] + + :type: string + :default: ``'utf8_general_ci'`` + + Defines the default connection collation to use, if not user-defined. + See the `MySQL documentation `_ for list of possible values. This setting is + ignored when connected to Drizzle server. + +.. config:option:: $cfg['Lang'] + + :type: string + :default: not set + + Force language to use. The corresponding language file needs to be in + locale/*code*/LC\_MESSAGES/phpmyadmin.mo. + +.. config:option:: $cfg['FilterLanguages'] + + :type: string + :default: ``''`` + + Limit list of available languages to those matching the given regular + expression. For example if you want only Czech and English, you should + set filter to ``'^(cs|en)'``. + +.. config:option:: $cfg['RecodingEngine'] + + :type: string + :default: ``'auto'`` + + You can select here which functions will be used for character set + conversion. Possible values are: + + * auto - automatically use available one (first is tested iconv, then + recode) + * iconv - use iconv or libiconv functions + * recode - use recode\_string function + * mb - use mbstring extension + * none - disable encoding conversion + + Enabled charset conversion activates a pull-down menu in the Export + and Import pages, to choose the character set when exporting a file. + The default value in this menu comes from + :config:option:`$cfg['Export']['charset']` and :config:option:`$cfg['Import']['charset']`. + +.. config:option:: $cfg['IconvExtraParams'] + + :type: string + :default: ``'//TRANSLIT'`` + + Specify some parameters for iconv used in charset conversion. See + `iconv documentation `_ for details. By default + ``//TRANSLIT`` is used, so that invalid characters will be + transliterated. + +.. config:option:: $cfg['AvailableCharsets'] + + :type: array + :default: array(..._ + + Available character sets for MySQL conversion. You can add your own + (any of supported by recode/iconv) or remove these which you don't + use. Character sets will be shown in same order as here listed, so if + you frequently use some of these move them to the top. + +Web server settings +------------------- + +.. config:option:: $cfg['OBGzip'] + + :type: string/boolean + :default: ``'auto'`` + + Defines whether to use GZip output buffering for increased speed in + :term:`HTTP` transfers. Set to + true/false for enabling/disabling. When set to 'auto' (string), + phpMyAdmin tries to enable output buffering and will automatically + disable it if your browser has some problems with buffering. IE6 with + a certain patch is known to cause data corruption when having enabled + buffering. + +.. config:option:: $cfg['TrustedProxies'] + + :type: array + :default: array() + + Lists proxies and HTTP headers which are trusted for + :config:option:`$cfg['Servers'][$i]['AllowDeny']['order']`. This list is by + default empty, you need to fill in some trusted proxy servers if you + want to use rules for IP addresses behind proxy. + + The following example specifies that phpMyAdmin should trust a + HTTP\_X\_FORWARDED\_FOR (``X -Forwarded-For``) header coming from the proxy + 1.2.3.4: + + .. code-block:: php + + $cfg['TrustedProxies'] = array('1.2.3.4' => 'HTTP_X_FORWARDED_FOR'); + + The :config:option:`$cfg['Servers'][$i]['AllowDeny']['rules']` directive uses the + client's IP address as usual. + +.. config:option:: $cfg['GD2Available'] + + :type: string + :default: ``'auto'`` + + Specifies whether GD >= 2 is available. If yes it can be used for MIME + transformations. Possible values are: + + * auto - automatically detect + * yes - GD 2 functions can be used + * no - GD 2 function cannot be used + +.. config:option:: $cfg['CheckConfigurationPermissions'] + + :type: boolean + :default: true + + We normally check the permissions on the configuration file to ensure + it's not world writable. However, phpMyAdmin could be installed on a + NTFS filesystem mounted on a non-Windows server, in which case the + permissions seems wrong but in fact cannot be detected. In this case a + sysadmin would set this parameter to ``false``. + +.. config:option:: $cfg['LinkLengthLimit'] + + :type: integer + :default: 1000 + + Limit for length of :term:`URL` in links. When length would be above this + limit, it is replaced by form with button. This is required as some web + servers (:term:`IIS`) have problems with long :term:`URL` . + +.. config:option:: $cfg['CSPAllow'] + + :type: string + :default: ``''`` + + Additional string to include in allowed script and image sources in Content + Security Policy header. + + This can be useful when you want to include some external javascript files + in :file:`config.footer.inc.php` or :file:`config.header.inc.php`, which + would be normally not allowed by Content Security Policy. + + To allow some sites, just list them within the string: + + .. code-block:: php + + $cfg['CSPAllow'] = 'example.com example.net'; + + .. versionadded:: 4.0.4 + +.. config:option:: $cfg['DisableMultiTableMaintenance'] + + :type: boolean + :default: false + + In the database Structure page, it's possible to mark some tables then + choose an operation like optimizing for many tables. This can slow + down a server; therefore, setting this to ``true`` prevents this kind + of multiple maintenance operation. + +Theme settings +-------------- + +.. config:option:: $cfg['NaviWidth'] + + :type: integer + :default: + + Navigation panel width in pixels. See + :file:`themes/themename/layout.inc.php`. + +.. config:option:: $cfg['NaviBackground'] + + :type: string [CSS color for background] + :default: + +.. config:option:: $cfg['MainBackground'] + + :type: string [CSS color for background] + :default: + + The background styles used for both the frames. See + :file:`themes/themename/layout.inc.php`. + +.. config:option:: $cfg['NaviPointerBackground'] + + :type: string [CSS color for background] + :default: + +.. config:option:: $cfg['NaviPointerColor'] + + :type: string [CSS color] + :default: + + The style used for the pointer in the navigation panel. See + :file:`themes/themename/layout.inc.php`. + +.. config:option:: $cfg['Border'] + + :type: integer + :default: + + The size of a table's border. See :file:`themes/themename/layout.inc.php`. + +.. config:option:: $cfg['ThBackground'] + + :type: string [CSS color for background] + :default: + +.. config:option:: $cfg['ThColor'] + + :type: string [CSS color] + :default: + + The style used for table headers. See + :file:`themes/themename/layout.inc.php`. + +.. _cfg_BgcolorOne: +.. config:option:: $cfg['BgOne'] + + :type: string [CSS color] + :default: + + The color (HTML) #1 for table rows. See + :file:`themes/themename/layout.inc.php`. + +.. _cfg_BgcolorTwo: +.. config:option:: $cfg['BgTwo'] + + :type: string [CSS color] + :default: + + The color (HTML) #2 for table rows. See + :file:`themes/themename/layout.inc.php`. + +.. config:option:: $cfg['BrowsePointerBackground'] + + :type: string [CSS color] + :default: + +.. config:option:: $cfg['BrowsePointerColor'] + + :type: string [CSS color] + :default: + +.. config:option:: $cfg['BrowseMarkerBackground'] + + :type: string [CSS color] + :default: + +.. config:option:: $cfg['BrowseMarkerColor'] + + :type: string [CSS color] + :default: + + The colors (HTML) uses for the pointer and the marker in browse mode. + The former feature highlights the row over which your mouse is passing + and the latter lets you visually mark/unmark rows by clicking on the + corresponding checkbox. Highlighting / marking a column is done by + hovering over / clicking the column's header (outside of the text). + See :file:`themes/themename/layout.inc.php`. + +.. config:option:: $cfg['FontFamily'] + + :type: string + :default: + + You put here a valid CSS font family value, for example ``arial, sans- + serif``. See :file:`themes/themename/layout.inc.php`. + +.. config:option:: $cfg['FontFamilyFixed'] + + :type: string + :default: + + You put here a valid CSS font family value, for example ``monospace``. + This one is used in textarea. See :file:`themes/themename/layout.inc.php`. + +Design customization +-------------------- + +.. config:option:: $cfg['NavigationTreePointerEnable'] + + :type: boolean + :default: true + + A value of ``true`` activates the navi pointer. + +.. config:option:: $cfg['BrowsePointerEnable'] + + :type: boolean + :default: true + + Whether to activate the browse pointer or not. + +.. config:option:: $cfg['BrowseMarkerEnable'] + + :type: boolean + :default: true + + Whether to activate the browse marker or not. + +.. config:option:: $cfg['LimitChars'] + + :type: integer + :default: 50 + + Maximum number of characters shown in any non-numeric field on browse + view. Can be turned off by a toggle button on the browse page. + +.. config:option:: $cfg['RowActionLinks'] + + :type: string + :default: ``'left'`` + + Defines the place where table row links (Edit, Copy, Delete) would be + put when tables contents are displayed (you may have them displayed at + the left side, right side, both sides or nowhere). "left" and "right" + are parsed as "top" and "bottom" with vertical display mode. + +.. config:option:: $cfg['DefaultDisplay'] + + :type: string + :default: ``'horizonta'`` + + There are 3 display modes: horizontal, horizontalflipped and vertical. + Define which one is displayed by default. The first mode displays each + row on a horizontal line, the second rotates the headers by 90 + degrees, so you can use descriptive headers even though columns only + contain small values and still print them out. The vertical mode sorts + each row on a vertical lineup. + +.. config:option:: $cfg['RememberSorting'] + + :type: boolean + :default: true + + If enabled, remember the sorting of each table when browsing them. + +.. config:option:: $cfg['HeaderFlipType'] + + :type: string + :default: ``'auto'`` + + The HeaderFlipType can be set to 'auto', 'css' or 'fake'. When using + 'css' the rotation of the header for horizontalflipped is done via + CSS. The CSS transformation currently works only in Internet + Explorer.If set to 'fake' PHP does the transformation for you, but of + course this does not look as good as CSS. The 'auto' option enables + CSS transformation when browser supports it and use PHP based one + otherwise. + +.. config:option:: $cfg['ShowBrowseComments'] + + :type: boolean + :default: true + +.. config:option:: $cfg['ShowPropertyComments'] + + :type: boolean + :default: true + + By setting the corresponding variable to ``true`` you can enable the + display of column comments in Browse or Property display. In browse + mode, the comments are shown inside the header. In property mode, + comments are displayed using a CSS-formatted dashed-line below the + name of the column. The comment is shown as a tool-tip for that + column. + +Text fields +----------- + +.. config:option:: $cfg['CharEditing'] + + :type: string + :default: ``'input'`` + + Defines which type of editing controls should be used for CHAR and + VARCHAR columns. Possible values are: + + * input - this allows to limit size of text to size of columns in MySQL, + but has problems with newlines in columns + * textarea - no problems with newlines in columns, but also no length + limitations + +.. config:option:: $cfg['MinSizeForInputField'] + + :type: integer + :default: 4 + + Defines the minimum size for input fields generated for CHAR and + VARCHAR columns. + +.. config:option:: $cfg['MaxSizeForInputField'] + + :type: integer + :default: 60 + + Defines the maximum size for input fields generated for CHAR and + VARCHAR columns. + +.. config:option:: $cfg['TextareaCols'] + + :type: integer + :default: 40 + +.. config:option:: $cfg['TextareaRows'] + + :type: integer + :default: 15 + +.. config:option:: $cfg['CharTextareaCols'] + + :type: integer + :default: 40 + +.. config:option:: $cfg['CharTextareaRows'] + + :type: integer + :default: 2 + + Number of columns and rows for the textareas. This value will be + emphasized (\*2) for :term:`SQL` query + textareas and (\*1.25) for :term:`SQL` + textareas inside the query window. + + The Char\* values are used for CHAR + and VARCHAR editing (if configured via :config:option:`$cfg['CharEditing']`). + +.. config:option:: $cfg['LongtextDoubleTextarea'] + + :type: boolean + :default: true + + Defines whether textarea for LONGTEXT columns should have double size. + +.. config:option:: $cfg['TextareaAutoSelect'] + + :type: boolean + :default: false + + Defines if the whole textarea of the query box will be selected on + click. + + +SQL query box settings +---------------------- + +.. config:option:: $cfg['SQLQuery']['Edit'] + + :type: boolean + :default: true + + Whether to display an edit link to change a query in any SQL Query + box. + +.. config:option:: $cfg['SQLQuery']['Explain'] + + :type: boolean + :default: true + + Whether to display a link to explain a SELECT query in any SQL Query + box. + +.. config:option:: $cfg['SQLQuery']['ShowAsPHP'] + + :type: boolean + :default: true + + Whether to display a link to wrap a query in PHP code in any SQL Query + box. + +.. config:option:: $cfg['SQLQuery']['Validate'] + + :type: boolean + :default: false + + Whether to display a link to validate a query in any SQL Query box. + + .. seealso:: :config:option:`$cfg['SQLValidator']` + +.. config:option:: $cfg['SQLQuery']['Refresh'] + + :type: boolean + :default: true + + Whether to display a link to refresh a query in any SQL Query box. + +Web server upload/save/import directories +----------------------------------------- + +.. config:option:: $cfg['UploadDir'] + + :type: string + :default: ``''`` + + The name of the directory where :term:`SQL` files have been uploaded by + other means than phpMyAdmin (for example, ftp). Those files are available + under a drop-down box when you click the database or table name, then the + Import tab. + + If + you want different directory for each user, %u will be replaced with + username. + + Please note that the file names must have the suffix ".sql" + (or ".sql.bz2" or ".sql.gz" if support for compressed formats is + enabled). + + This feature is useful when your file is too big to be + uploaded via :term:`HTTP`, or when file + uploads are disabled in PHP. + + .. note:: + + If PHP is running in safe mode, this directory must be owned by the same + user as the owner of the phpMyAdmin scripts. See also :ref:`faq1_16` for + alternatives. + +.. config:option:: $cfg['SaveDir'] + + :type: string + :default: ``''`` + + The name of the directory where dumps can be saved. + + If you want different directory for each user, %u will be replaced with + username. + + Please note that the directory must exist and has to be writable for + the user running webserver. + + .. note:: + + If PHP is running in safe mode, this directory must be owned by the same + user as the owner of the phpMyAdmin scripts. + +.. config:option:: $cfg['TempDir'] + + :type: string + :default: ``''`` + + The name of the directory where temporary files can be stored. + + This is needed for importing ESRI Shapefiles, see :ref:`faq6_30` and to + work around limitations of ``open_basedir`` for uploaded files, see + :ref:`faq1_11`. + + If the directory where phpMyAdmin is installed is + subject to an ``open_basedir`` restriction, you need to create a + temporary directory in some directory accessible by the web server. + However for security reasons, this directory should be outside the + tree published by webserver. If you cannot avoid having this directory + published by webserver, place at least an empty :file:`index.html` file + there, so that directory listing is not possible. + + This directory should have as strict permissions as possible as the only + user required to access this directory is the one who runs the webserver. + If you have root privileges, simply make this user owner of this directory + and make it accessible only by it: + + .. code-block:: sh + + + chown www-data:www-data tmp + chmod 700 tmp + + If you cannot change owner of the directory, you can achieve a similar + setup using :term:`ACL`: + + .. code-block:: sh + + chmod 700 tmp + setfacl -m "g:www-data:rwx" tmp + setfacl -d -m "g:www-data:rwx" tmp + + If neither of above works for you, you can still make the directory + :command:`chmod 777`, but it might impose risk of other users on system + reading and writing data in this directory. + +Various display setting +----------------------- + +.. config:option:: $cfg['ShowDisplayDirection'] + + :type: boolean + :default: false + + Defines whether or not type display direction option is shown when + browsing a table. + +.. config:option:: $cfg['RepeatCells'] + + :type: integer + :default: 100 + + Repeat the headers every X cells, or 0 to deactivate. + +.. config:option:: $cfg['EditInWindow'] + + :type: boolean + :default: true + +.. config:option:: $cfg['QueryWindowWidth'] + + :type: integer + :default: 550 + +.. config:option:: $cfg['QueryWindowHeight'] + + :type: integer + :default: 310 + +.. config:option:: $cfg['QueryHistoryDB'] + + :type: boolean + :default: false + +.. config:option:: $cfg['QueryWindowDefTab'] + + :type: string + :default: ``'sql'`` + +.. config:option:: $cfg['QueryHistoryMax'] + + :type: integer + :default: 25 + + All those variables affect the query window feature. A :term:`SQL` link or + icon is always displayed in the navigation panel. If JavaScript is enabled + in your browser, a click on this opens a distinct query window, which is a + direct interface to enter :term:`SQL` queries. Otherwise, the right panel + changes to display a query box. + + The size of this query window can be customized with + :config:option:`$cfg['QueryWindowWidth']` and + :config:option:`$cfg['QueryWindowHeight']` - both integers for the size in + pixels. Note that normally, those parameters will be modified in + :file:`layout.inc.php`` for the theme you are using. + + If :config:option:`$cfg['EditInWindow']` is set to true, a click on [Edit] + from the results page (in the :guilabel:`Showing Rows` section) opens the + query window and puts the current query inside it. If set to false, + clicking on the link puts the :term:`SQL` query + in the right panel's query box. + + If :config:option:`$cfg['QueryHistoryDB']` is set to ``true``, all your + Queries are logged to a table, which has to be created by you (see + :config:option:`$cfg['Servers'][$i]['history']`). If set to false, all your + queries will be appended to the form, but only as long as your window is + opened they remain saved. + + When using the JavaScript based query window, it will always get updated + when you click on a new table/db to browse and will focus if you click on + :guilabel:`Edit SQL` after using a query. You can suppress updating the + query window by checking the box :guilabel:`Do not overwrite this query + from outside the window` below the query textarea. Then you can browse + tables/databases in the background without losing the contents of the + textarea, so this is especially useful when composing a query with tables + you first have to look in. The checkbox will get automatically checked + whenever you change the contents of the textarea. Please uncheck the button + whenever you definitely want the query window to get updated even though + you have made alterations. + + If :config:option:`$cfg['QueryHistoryDB']` is set to ``true`` you can + specify the amount of saved history items using + :config:option:`$cfg['QueryHistoryMax']`. + + The query window also has a custom tabbed look to group the features. + Using the variable :config:option:`$cfg['QueryWindowDefTab']` you can + specify the default tab to be used when opening the query window. It can be + set to either ``sql``, ``files``, ``history`` or ``full``. + +.. config:option:: $cfg['BrowseMIME'] + + :type: boolean + :default: true + + Enable :ref:`transformations`. + +.. config:option:: $cfg['MaxExactCount'] + + :type: integer + :default: 0 + + For InnoDB tables, determines for how large tables phpMyAdmin should + get the exact row count using ``SELECT COUNT``. If the approximate row + count as returned by ``SHOW TABLE STATUS`` is smaller than this value, + ``SELECT COUNT`` will be used, otherwise the approximate count will be + used. + +.. config:option:: $cfg['MaxExactCountViews'] + + :type: integer + :default: 0 + + For VIEWs, since obtaining the exact count could have an impact on + performance, this value is the maximum to be displayed, using a + ``SELECT COUNT ... LIMIT``. Setting this to 0 bypasses any row + counting. + +.. config:option:: $cfg['NaturalOrder'] + + :type: boolean + :default: true + + Sorts database and table names according to natural order (for + example, t1, t2, t10). Currently implemented in the navigation panel + and in Database view, for the table list. + +.. config:option:: $cfg['InitialSlidersState'] + + :type: string + :default: ``'closed'`` + + If set to ``'closed'``, the visual sliders are initially in a closed + state. A value of ``'open'`` does the reverse. To completely disable + all visual sliders, use ``'disabled'``. + +.. config:option:: $cfg['UserprefsDisallow'] + + :type: array + :default: array() + + Contains names of configuration options (keys in ``$cfg`` array) that + users can't set through user preferences. For possible values, refer + to :file:`libraries/config/user_preferences.forms.php`. + +.. config:option:: $cfg['UserprefsDeveloperTab'] + + :type: boolean + :default: false + + Activates in the user preferences a tab containing options for + developers of phpMyAdmin. + +Page titles +----------- + +.. config:option:: $cfg['TitleTable'] + + :type: string + :default: ``'@HTTP_HOST@ / @VSERVER@ / @DATABASE@ / @TABLE@ | @PHPMYADMIN@'`` + +.. config:option:: $cfg['TitleDatabase'] + + :type: string + :default: ``'@HTTP_HOST@ / @VSERVER@ / @DATABASE@ | @PHPMYADMIN@'`` + +.. config:option:: $cfg['TitleServer'] + + :type: string + :default: ``'@HTTP_HOST@ / @VSERVER@ | @PHPMYADMIN@'`` + +.. config:option:: $cfg['TitleDefault'] + + :type: string + :default: ``'@HTTP_HOST@ | @PHPMYADMIN@'`` + + Allows you to specify window's title bar. You can use :ref:`faq6_27`. + +Theme manager settings +---------------------- + +.. config:option:: $cfg['ThemePath'] + + :type: string + :default: ``'./themes'`` + + If theme manager is active, use this as the path of the subdirectory + containing all the themes. + +.. config:option:: $cfg['ThemeManager'] + + :type: boolean + :default: true + + Enables user-selectable themes. See :ref:`faqthemes`. + +.. config:option:: $cfg['ThemeDefault'] + + :type: string + :default: ``'pmahomme'`` + + The default theme (a subdirectory under :config:option:`$cfg['ThemePath']`). + +.. config:option:: $cfg['ThemePerServer'] + + :type: boolean + :default: false + + Whether to allow different theme for each server. + +Default queries +--------------- + +.. config:option:: $cfg['DefaultQueryTable'] + + :type: string + :default: ``'SELECT * FROM @TABLE@ WHERE 1'`` + +.. config:option:: $cfg['DefaultQueryDatabase'] + + :type: string + :default: ``''`` + + Default queries that will be displayed in query boxes when user didn't + specify any. You can use standard :ref:`faq6_27`. + +SQL validator settings +---------------------- + +.. config:option:: $cfg['SQLValidator'] + + :type: array + :default: array(...) + + + +.. config:option:: $cfg['SQLValidator']['use'] + + :type: boolean + :default: false + + phpMyAdmin now supports use of the `Mimer SQL Validator + `_ service, as originally + published on `Slashdot + `_. For + help in setting up your system to use the service, see the + :ref:`faqsqlvalidator`. + +.. config:option:: $cfg['SQLValidator']['username'] + + :type: string + :default: ``''`` + +.. config:option:: $cfg['SQLValidator']['password'] + + :type: string + :default: ``''`` + + The SOAP service allows you to log in with ``anonymous`` and any password, + so we use those by default. Instead, if you have an account with them, you + can put your login details here, and it will be used in place of the + anonymous login. + +MySQL settings +-------------- + +.. config:option:: $cfg['DefaultFunctions'] + + :type: array + :default: array(...) + + Functions selected by default when inserting/changing row, Functions + are defined for meta types as (FUNC\_NUMBER, FUNC\_DATE, FUNC\_CHAR, + FUNC\_SPATIAL, FUNC\_UUID) and for ``first_timestamp``, which is used + for first timestamp column in table. + + +Developer +--------- + +.. warning:: + + These settings might have huge effect on performance or security. + +.. config:option:: $cfg['DBG'] + + :type: array + :default: array(...) + +.. config:option:: $cfg['DBG']['sql'] + + :type: boolean + :default: false + + Enable logging queries and execution times to be + displayed in the bottom of main page (right frame). + +.. config:option:: $cfg['DBG']['demo'] + + :type: boolean + :default: false + + Enable to let server present itself as demo server. + This is used for . + +.. config:option:: $cfg['Error_Handler']['display'] + + :type: boolean + :default: false + + Whether to display errors from PHP or not. + diff --git a/phpMyAdmin/doc/html/_sources/copyright.txt b/phpMyAdmin/doc/html/_sources/copyright.txt new file mode 100644 index 0000000..cfcb863 --- /dev/null +++ b/phpMyAdmin/doc/html/_sources/copyright.txt @@ -0,0 +1,30 @@ +.. _copyright: + +Copyright +========= + +.. code-block:: none + + Copyright (C) 1998-2000 Tobias Ratschiller + Copyright (C) 2001-2013 Marc Delisle + Olivier Müller + Robin Johnson + Alexander M. Turek + Michal ÄŒihaÅ™ + Garvin Hicking + Michael Keck + Sebastian Mendel + [check credits for more details] + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2, as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see `http://www.gnu.org/licenses/ +`_. diff --git a/phpMyAdmin/doc/html/_sources/credits.txt b/phpMyAdmin/doc/html/_sources/credits.txt new file mode 100644 index 0000000..61c7758 --- /dev/null +++ b/phpMyAdmin/doc/html/_sources/credits.txt @@ -0,0 +1,626 @@ +.. _credits: + +Credits +======= + + +Credits, in chronological order ++++++++++++++++++++++++++++++++ + +* Tobias Ratschiller + + * creator of the phpmyadmin project + + * maintainer from 1998 to summer 2000 + +* Marc Delisle + + * multi-language version in December 1998 + + * various fixes and improvements + + * :term:`SQL` analyser (most of it) + + * current project maintainer + + * maintains content on our website + +* Olivier Müller + + * started SourceForge phpMyAdmin project in March 2001 + + * sync'ed different existing CVS trees with new features and bugfixes + + * multi-language improvements, dynamic language selection + + * many bugfixes and improvements + +* Loïc Chapeaux + + * rewrote and optimized javascript, DHTML and DOM stuff + + * rewrote the scripts so they fit the :term:`PEAR` coding standards and + generate XHTML1.0 and CSS2 compliant codes + + * improved the language detection system + + * many bugfixes and improvements + +* Robin Johnson + + * database maintenance controls + + * table type code + + * Host authentication :term:`IP` Allow/Deny + + * DB-based configuration (Not completed) + + * :term:`SQL` parser and pretty-printer + + * :term:`SQL` validator + + * many bugfixes and improvements + +* Armel Fauveau + + * bookmarks feature + + * multiple dump feature + + * gzip dump feature + + * zip dump feature + +* Geert Lund + + * various fixes + + * moderator of the phpMyAdmin former users forum at phpwizard.net + +* Korakot Chaovavanich + + * "insert as new row" feature + +* Pete Kelly + + * rewrote and fix dump code + + * bugfixes + +* Steve Alberty + + * rewrote dump code for PHP4 + + * mySQL table statistics + + * bugfixes + +* Benjamin Gandon + + * main author of the version 2.1.0.1 + + * bugfixes + +* Alexander M. Turek + + * MySQL 4.0 / 4.1 / 5.0 compatibility + + * abstract database interface (PMA\_DBI) with MySQLi support + + * privileges administration + + * :term:`XML` exports + + * various features and fixes + + * German language file updates + +* Mike Beck + + * automatic joins in QBE + + * links column in printview + + * Relation view + +* Michal ÄŒihaÅ™ + + * enhanced index creation/display feature + + * feature to use a different charset for HTML than for MySQL + + * improvements of export feature + + * various features and fixes + + * Czech language file updates + + * created current website for phpMyAdmin + +* Christophe Gesché from the "MySQL Form Generator for PHPMyAdmin" + (http://sf.net/projects/phpmysqlformgen/) + + * suggested the patch for multiple table printviews + +* Garvin Hicking + + * built the patch for vertical display of table rows + + * built the Javascript based Query window + :term:`SQL` history + + * Improvement of column/db comments + + * (MIME)-Transformations for columns + + * Use custom alias names for Databases in left frame + + * hierarchical/nested table display + + * :term:`PDF`-scratchboard for WYSIWYG- + distribution of :term:`PDF` relations + + * new icon sets + + * vertical display of column properties page + + * some bugfixes, features, support, German language additions + +* Yukihiro Kawada + + * japanese kanji encoding conversion feature + +* Piotr Roszatycki and Dan Wilson + + * the Cookie authentication mode + +* Axel Sander + + * table relation-links feature + +* Maxime Delorme + + * :term:`PDF` schema output, thanks also to + Olivier Plathey for the "FPDF" library (see ), Steven + Wittens for the "UFPDF" library (see ) and + Nicola Asuni for the "TCPDF" library (see ). + +* Olof Edlund + + * :term:`SQL` validator server + +* Ivan R. Lanin + + * phpMyAdmin logo (until June 2004) + +* Mike Cochrane + + * blowfish library from the Horde project (withdrawn in release 4.0) + +* Marcel Tschopp + + * mysqli support + + * many bugfixes and improvements + +* Nicola Asuni (Tecnick.com) + + * TCPDF library (`http://www.tcpdf.org `_) + +* Michael Keck + + * redesign for 2.6.0 + + * phpMyAdmin sailboat logo (June 2004) + +* Mathias Landhäußer + + * Representation at conferences + +* Sebastian Mendel + + * interface improvements + + * various bugfixes + +* Ivan A Kirillov + + * new relations Designer + +* Raj Kissu Rajandran (Google Summer of Code 2008) + + * BLOBstreaming support (withdrawn in release 4.0) + +* Piotr Przybylski (Google Summer of Code 2008, 2010 and 2011) + + * improved setup script + + * user preferences + + * Drizzle support + +* Derek Schaefer (Google Summer of Code 2009) + + * Improved the import system + +* Alexander Rutkowski (Google Summer of Code 2009) + + * Tracking mechanism + +* Zahra Naeem (Google Summer of Code 2009) + + * Synchronization feature (removed in release 4.0) + +* Tomáš Srnka (Google Summer of Code 2009) + + * Replication support + +* Muhammad Adnan (Google Summer of Code 2010) + + * Relation schema export to multiple formats + +* Lori Lee (Google Summer of Code 2010) + + * User interface improvements + + * ENUM/SET editor + + * Simplified interface for export/import + +* Ninad Pundalik (Google Summer of Code 2010) + + * AJAXifying the interface + +* Martynas MickeviÄius (Google Summer of Code 2010) + + * Charts + +* Barrie Leslie + + * BLOBstreaming support with PBMS PHP extension (withdrawn in release + 4.0) + +* Ankit Gupta (Google Summer of Code 2010) + + * Visual query builder + +* Madhura Jayaratne (Google Summer of Code 2011) + + * OpenGIS support + +* Ammar Yasir (Google Summer of Code 2011) + + * Zoom search + +* Aris Feryanto (Google Summer of Code 2011) + + * Browse-mode improvements + +* Thilanka Kaushalya (Google Summer of Code 2011) + + * AJAXification + +* Tyron Madlener (Google Summer of Code 2011) + + * Query statistics and charts for the status page + +* Zarubin Stas (Google Summer of Code 2011) + + * Automated testing + +* Rouslan Placella (Google Summer of Code 2011 and 2012) + + * Improved support for Stored Routines, Triggers and Events + + * Italian translation updates + + * Removal of frames, new navigation + +* Dieter Adriaenssens + + * Various bugfixes + + * Dutch translation updates + +* Alex Marin (Google Summer of Code 2012) + + * New plugins and properties system + +* Thilina Buddika Abeyrathna (Google Summer of Code 2012) + + * Refactoring + +* Atul Pratap Singh (Google Summer of Code 2012) + + * Refactoring + +* Chanaka Indrajith (Google Summer of Code 2012) + + * Refactoring + +* Yasitha Pandithawatta (Google Summer of Code 2012) + + * Automated testing + +* Jim Wigginton (phpseclib.sourceforge.net) + + * phpseclib + +* Bin Zu (Google Summer of Code 2013) + + * Refactoring + +* Supun Nakandala (Google Summer of Code 2013) + + * Refactoring + +* Mohamed Ashraf (Google Summer of Code 2013) + + * AJAX error reporting + +* Adam Kang (Google Summer of Code 2013) + + * Automated testing + +* Ayush Chaudhary (Google Summer of Code 2013) + + * Automated testing + +* Kasun Chathuranga (Google Summer of Code 2013) + + * Interface 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: + +Bora Alioglu, Ricardo ?, Sven-Erik Andersen, Alessandro Astarita, +Péter Bakondy, Borges Botelho, Olivier Bussier, Neil Darlow, Mats +Engstrom, Ian Davidson, Laurent Dhima, Kristof Hamann, Thomas Kläger, +Lubos Klokner, Martin Marconcini, Girish Nair, David Nordenberg, +Andreas Pauley, Bernard M. Piller, Laurent Haas, "Sakamoto", Yuval +Sarna, www.securereality.com.au, Alexis Soulard, Alvar Soome, Siu Sun, +Peter Svec, Michael Tacelosky, Rachim Tamsjadi, Kositer Uros, Luís V., +Martijn W. van der Lee, Algis Vainauskas, Daniel Villanueva, Vinay, +Ignacio Vazquez-Abrams, Chee Wai, Jakub Wilk, Thomas Michael +Winningham, Vilius Zigmantas, "Manuzhai". + + +Translators ++++++++++++ + +Following people have contributed to translation of phpMyAdmin: + +* Arabic + + * Abdullah Al-Saedi + +* Bulgarian + + * stoyanster + +* Catalan + + * Xavier Navarro + +* Czech + + * Michal ÄŒihaÅ™ + +* Danish + + * opensource + * Jørgen Thomsen + +* German + + * mrbendig + * torsten.funck + * Sven Strickroth + * typo3 + * Jo Michael + +* Greek + + * Panagiotis Papazoglou + +* English (United Kingdom) + + * Robert Readman + +* Spanish + + * Matías Bellone + +* French + + * Marc Delisle + +* Hindi + + * u4663530 + * rsedwardian + +* Hungarian + + * gergo314 + +* Italian + + * Rouslan Placella + +* Japanese + + * Yuichiro + +* Lithuanian + + * KÄ™stutis + +* Norwegian BokmÃ¥l + + * Sven-Erik Andersen + +* Dutch + + * Dieter Adriaenssens + * Herman van Rink + +* Polish + + * StanisÅ‚aw Krukowski + * Marcin KozioÅ‚ + +* Portuguese + + * JoaoTMDias + +* Portuguese (Brazil) + + * wiltave + * emerson4br + +* Romanian + + * alexukf + +* Russian + + * Victor Volkov + +* Sinhala + + * Madhura Jayaratne + +* Slovak + + * Martin Lacina + +* Slovenian + + * Domen + +* Swedish + + * stefan + +* Tamil + + * ysajeepan + +* Telugu + + * veeven + +* Thai + + * kanitchet + +* Turkish + + * Burak Yavuz + +* Uighur + + * gheni + +* Ukrainian + + * typim + * oleg-ilnytskyi + +* Urdu + + * Mehbooob Khan + +* Simplified Chinese + + * shanyan baishui + +* Traditional Chinese + + * star + +Documentation translators ++++++++++++++++++++++++++ + +Following people have contributed to translation of phpMyAdmin documentation: + +* Czech + + * Michal ÄŒihaÅ™ + +* Greek + + * Panagiotis Papazoglou + +* English (United Kingdom) + + * Robert Readman + +* French + + * Cédric Corazza + +* Japanese + + * Yuichiro Takahashi + +* Polish + + * StanisÅ‚aw Krukowski + +* Portuguese (Brazil) + + * mjaning + +* Slovenian + + * Domen + +Original Credits of Version 2.1.0 ++++++++++++++++++++++++++++++++++ + +This work is based on Peter Kuppelwieser's MySQL-Webadmin. It was his +idea to create a web-based interface to MySQL using PHP3. Although I +have not used any of his source-code, there are some concepts I've +borrowed from him. phpMyAdmin was created because Peter told me he +wasn't going to further develop his (great) tool. + +Thanks go to + +* Amalesh Kempf who contributed the + code for the check when dropping a table or database. He also + suggested that you should be able to specify the primary key on + tbl\_create.php3. To version 1.1.1 he contributed the ldi\_\*.php3-set + (Import text-files) as well as a bug-report. Plus many smaller + improvements. +* Jan Legenhausen : He made many of the changes that + were introduced in 1.3.0 (including quite significant ones like the + authentication). For 1.4.1 he enhanced the table-dump feature. Plus + bug-fixes and help. +* Marc Delisle made phpMyAdmin + language-independent by outsourcing the strings to a separate file. He + also contributed the French translation. +* Alexandr Bravo who contributed + tbl\_select.php3, a feature to display only some columns from a table. +* Chris Jackson added support for MySQL functions + in tbl\_change.php3. He also added the "Query by Example" feature in + 2.0. +* Dave Walton added support for multiple + servers and is a regular contributor for bug-fixes. +* Gabriel Ash contributed the random access + features for 2.0.6. + +The following people have contributed minor changes, enhancements, +bugfixes or support for a new language: + +Jim Kraai, Jordi Bruguera, Miquel Obrador, Geert Lund, Thomas +Kleemann, Alexander Leidinger, Kiko Albiol, Daniel C. Chao, Pavel +Piankov, Sascha Kettler, Joe Pruett, Renato Lins, Mark Kronsbein, +Jannis Hermanns, G. Wieggers. + +And thanks to everyone else who sent me email with suggestions, bug- +reports and or just some feedback. + diff --git a/phpMyAdmin/doc/html/_sources/developers.txt b/phpMyAdmin/doc/html/_sources/developers.txt new file mode 100644 index 0000000..5574527 --- /dev/null +++ b/phpMyAdmin/doc/html/_sources/developers.txt @@ -0,0 +1,12 @@ +.. _developers: + +Developers Information +====================== + +phpMyAdmin is Open Source, so you're invited to contribute to it. Many +great features have been written by other people and you too can help +to make phpMyAdmin a useful tool. + +You can check out all the possibilities to contribute in the +`contribute section on our website +`_. \ No newline at end of file diff --git a/phpMyAdmin/doc/html/_sources/faq.txt b/phpMyAdmin/doc/html/_sources/faq.txt new file mode 100644 index 0000000..4265c5b --- /dev/null +++ b/phpMyAdmin/doc/html/_sources/faq.txt @@ -0,0 +1,2015 @@ +.. _faq: + +FAQ - Frequently Asked Questions +================================ + +Please have a look at our `Link section +`_ on the official +phpMyAdmin homepage for in-depth coverage of phpMyAdmin's features and +or interface. + +.. _faqserver: + +Server +++++++ + +.. _faq1_1: + +1.1 My server is crashing each time a specific action is required or phpMyAdmin sends a blank page or a page full of cryptic characters to my browser, what can I do? +--------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +Try to set the :config:option:`$cfg['OBGzip']` directive to ``false`` in your +:file:`config.inc.php` file and the ``zlib.output_compression`` directive to +``Off`` in your php configuration file. + +.. _faq1_2: + +1.2 My Apache server crashes when using phpMyAdmin. +--------------------------------------------------- + +You should first try the latest versions of Apache (and possibly MySQL). If +your server keeps crashing, please ask for help in the various Apache support +groups. + +.. seealso:: :ref:`faq1_1` + +.. _faq1_3: + +1.3 (withdrawn). +---------------- + +.. _faq1_4: + +1.4 Using phpMyAdmin on IIS, I'm displayed the error message: "The specified CGI application misbehaved by not returning a complete set of HTTP headers ...". +------------------------------------------------------------------------------------------------------------------------------------------------------------- + +You just forgot to read the *install.txt* file from the PHP +distribution. Have a look at the last message in this `PHP bug report #12061 +`_ from the official PHP bug +database. + +.. _faq1_5: + +1.5 Using phpMyAdmin on IIS, I'm facing crashes and/or many error messages with the HTTP. +----------------------------------------------------------------------------------------- + +This is a known problem with the PHP :term:`ISAPI` filter: it's not so stable. +Please use instead the cookie authentication mode. + +.. _faq1_6: + +1.6 I can't use phpMyAdmin on PWS: nothing is displayed! +-------------------------------------------------------- + +This seems to be a PWS bug. Filippo Simoncini found a workaround (at +this time there is no better fix): remove or comment the ``DOCTYPE`` +declarations (2 lines) from the scripts :file:`libraries/Header.class.php` +and :file:`index.php`. + +.. _faq1_7: + +1.7 How can I GZip a dump or a CSV export? It does not seem to work. +-------------------------------------------------------------------- + +This feature is based on the ``gzencode()`` +PHP function to be more independent of the platform (Unix/Windows, +Safe Mode or not, and so on). So, you must have Zlib support +(``--with-zlib``). + +.. _faq1_8: + +1.8 I cannot insert a text file in a table, and I get an error about safe mode being in effect. +----------------------------------------------------------------------------------------------- + +Your uploaded file is saved by PHP in the "upload dir", as defined in +:file:`php.ini` by the variable ``upload_tmp_dir`` (usually the system +default is */tmp*). We recommend the following setup for Apache +servers running in safe mode, to enable uploads of files while being +reasonably secure: + +* create a separate directory for uploads: :command:`mkdir /tmp/php` +* give ownership to the Apache server's user.group: :command:`chown + apache.apache /tmp/php` +* give proper permission: :command:`chmod 600 /tmp/php` +* put ``upload_tmp_dir = /tmp/php`` in :file:`php.ini` +* restart Apache + +.. _faq1_9: + +1.9 (withdrawn). +---------------- + +.. _faq1_10: + +1.10 I'm having troubles when uploading files with phpMyAdmin running on a secure server. My browser is Internet Explorer and I'm using the Apache server. +---------------------------------------------------------------------------------------------------------------------------------------------------------- + +As suggested by "Rob M" in the phpWizard forum, add this line to your +*httpd.conf*: + +.. code-block:: apache + + SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown + +It seems to clear up many problems between Internet Explorer and SSL. + +.. _faq1_11: + +1.11 I get an 'open\_basedir restriction' while uploading a file from the query box. +------------------------------------------------------------------------------------ + +Since version 2.2.4, phpMyAdmin supports servers with open\_basedir +restrictions. However you need to create temporary directory and configure it +as :config:option:`$cfg['TempDir']`. The uploaded files will be moved there, +and after execution of your :term:`SQL` commands, removed. + +.. _faq1_12: + +1.12 I have lost my MySQL root password, what can I do? +------------------------------------------------------- + +The MySQL manual explains how to `reset the permissions +`_. + +.. _faq1_13: + +1.13 (withdrawn). +----------------- + +.. _faq1_14: + +1.14 (withdrawn). +----------------- + +.. _faq1_15: + +1.15 I have problems with *mysql.user* column names. +---------------------------------------------------- + +In previous MySQL versions, the ``User`` and ``Password``columns were +named ``user`` and ``password``. Please modify your column names to +align with current standards. + +.. _faq1_16: + +1.16 I cannot upload big dump files (memory, HTTP or timeout problems). +----------------------------------------------------------------------- + +Starting with version 2.7.0, the import engine has been re–written and +these problems should not occur. If possible, upgrade your phpMyAdmin +to the latest version to take advantage of the new import features. + +The first things to check (or ask your host provider to check) are the +values of ``upload_max_filesize``, ``memory_limit`` and +``post_max_size`` in the :file:`php.ini` configuration file. All of these +three settings limit the maximum size of data that can be submitted +and handled by PHP. One user also said that ``post_max_size`` and +``memory_limit`` need to be larger than ``upload_max_filesize``. +There exist several workarounds if your upload is too big or your +hosting provider is unwilling to change the settings: + +* Look at the :config:option:`$cfg['UploadDir']` feature. This allows one to upload a file to the server + via scp, ftp, or your favorite file transfer method. PhpMyAdmin is + then able to import the files from the temporary directory. More + information is available in the :ref:`config` of this document. +* Using a utility (such as `BigDump + `_) to split the files before + uploading. We cannot support this or any third party applications, but + are aware of users having success with it. +* If you have shell (command line) access, use MySQL to import the files + directly. You can do this by issuing the "source" command from within + MySQL: + + .. code-block:: mysql + + source filename.sql; + +.. _faq1_17: + +1.17 Which MySQL versions does phpMyAdmin support? +-------------------------------------------------- + +Since phpMyAdmin 3.0.x, only MySQL 5.0.1 and newer are supported. For +older MySQL versions, you need to use the latest 2.x branch. +phpMyAdmin can connect to your MySQL server using PHP's classic `MySQL +extension `_ as well as the `improved MySQL +extension (MySQLi) `_ that is available in PHP +5.0. The latter one should be used unless you have a good reason not +to do so. When compiling PHP, we strongly recommend that you manually +link the MySQL extension of your choice to a MySQL client library of +at least the same minor version since the one that is bundled with +some PHP distributions is rather old and might cause problems see +:ref:`faq1_17a`. `MariaDB `_ is also supported +(versions 5.1 and 5.2 were tested). + +.. versionchanged:: 3.5 + Since phpMyAdmin 3.5 `Drizzle `_ is supported. + +.. _faq1_17a: + +1.17a I cannot connect to the MySQL server. It always returns the error message, "Client does not support authentication protocol requested by server; consider upgrading MySQL client" +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +You tried to access MySQL with an old MySQL client library. The +version of your MySQL client library can be checked in your phpinfo() +output. In general, it should have at least the same minor version as +your server - as mentioned in :ref:`faq1_17`. This problem is +generally caused by using MySQL version 4.1 or newer. MySQL changed +the authentication hash and your PHP is trying to use the old method. +The proper solution is to use the `mysqli extension +`_ with the proper client library to match +your MySQL installation. Your chosen extension is specified in +:config:option:`$cfg['Servers'][$i]['extension']`. More +information (and several workarounds) are located in the `MySQL +Documentation `_. + +.. _faq1_18: + +1.18 (withdrawn). +----------------- + +.. _faq1_19: + +1.19 I can't run the "display relations" feature because the script seems not to know the font face I'm using! +-------------------------------------------------------------------------------------------------------------- + +The :term:`TCPDF` library we're using for this feature requires some special +files to use font faces. Please refers to the `TCPDF manual +`_ to build these files. + +.. _faqmysql: + +1.20 I receive the error "cannot load MySQL extension, please check PHP Configuration". +--------------------------------------------------------------------------------------- + +To connect to a MySQL server, PHP needs a set of MySQL functions +called "MySQL extension". This extension may be part of the PHP +distribution (compiled-in), otherwise it needs to be loaded +dynamically. Its name is probably *mysql.so* or *php\_mysql.dll*. +phpMyAdmin tried to load the extension but failed. Usually, the +problem is solved by installing a software package called "PHP-MySQL" +or something similar. + +There are currently two interfaces PHP provides as MySQL extensions - ``mysql`` +and ``mysqli`` and you can change which of then is being used by +:config:option:`$cfg['Servers'][$i]['extension']`. + +.. _faq1_21: + +1.21 I am running the CGI version of PHP under Unix, and I cannot log in using cookie auth. +------------------------------------------------------------------------------------------- + +In :file:`php.ini`, set ``mysql.max_links`` higher than 1. + +.. _faq1_22: + +1.22 I don't see the "Location of text file" field, so I cannot upload. +----------------------------------------------------------------------- + +This is most likely because in :file:`php.ini`, your ``file_uploads`` +parameter is not set to "on". + +.. _faq1_23: + +1.23 I'm running MySQL on a Win32 machine. Each time I create a new table the table and column names are changed to lowercase! +------------------------------------------------------------------------------------------------------------------------------ + +This happens because the MySQL directive ``lower_case_table_names`` +defaults to 1 (``ON``) in the Win32 version of MySQL. You can change +this behavior by simply changing the directive to 0 (``OFF``): Just +edit your ``my.ini`` file that should be located in your Windows +directory and add the following line to the group [mysqld]: + +.. code-block:: ini + + set-variable = lower_case_table_names=0 + +Next, save the file and restart the MySQL service. You can always +check the value of this directive using the query + +.. code-block:: mysql + + SHOW VARIABLES LIKE 'lower_case_table_names'; + +.. _faq1_24: + +1.24 (withdrawn). +----------------- + +.. _faq1_25: + +1.25 I am running Apache with mod\_gzip-1.3.26.1a on Windows XP, and I get problems, such as undefined variables when I run a SQL query. +---------------------------------------------------------------------------------------------------------------------------------------- + +A tip from Jose Fandos: put a comment on the following two lines in +httpd.conf, like this: + +.. code-block:: apache + + + # mod_gzip_item_include file \.php$ + # mod_gzip_item_include mime "application/x-httpd-php.*" + +as this version of mod\_gzip on Apache (Windows) has problems handling +PHP scripts. Of course you have to restart Apache. + +.. _faq1_26: + +1.26 I just installed phpMyAdmin in my document root of IIS but I get the error "No input file specified" when trying to run phpMyAdmin. +---------------------------------------------------------------------------------------------------------------------------------------- + +This is a permission problem. Right-click on the phpmyadmin folder and +choose properties. Under the tab Security, click on "Add" and select +the user "IUSR\_machine" from the list. Now set his permissions and it +should work. + +.. _faq1_27: + +1.27 I get empty page when I want to view huge page (eg. db\_structure.php with plenty of tables). +-------------------------------------------------------------------------------------------------- + +This was caused by a `PHP bug `_ that occur when +GZIP output buffering is enabled. If you turn off it (by +:config:option:`$cfg['OBGzip']` in :file:`config.inc.php`), it should work. +This bug will has been fixed in PHP 5.0.0. + +.. _faq1_28: + +1.28 My MySQL server sometimes refuses queries and returns the message 'Errorcode: 13'. What does this mean? +------------------------------------------------------------------------------------------------------------ + +This can happen due to a MySQL bug when having database / table names +with upper case characters although ``lower_case_table_names`` is +set to 1. To fix this, turn off this directive, convert all database +and table names to lower case and turn it on again. Alternatively, +there's a bug-fix available starting with MySQL 3.23.56 / +4.0.11-gamma. + +.. _faq1_29: + +1.29 When I create a table or modify a column, I get an error and the columns are duplicated. +--------------------------------------------------------------------------------------------- + +It is possible to configure Apache in such a way that PHP has problems +interpreting .php files. + +The problems occur when two different (and conflicting) set of +directives are used: + +.. code-block:: apache + + + SetOutputFilter PHP + SetInputFilter PHP + +and + +.. code-block:: apache + + AddType application/x-httpd-php .php + +In the case we saw, one set of directives was in +``/etc/httpd/conf/httpd.conf``, while the other set was in +``/etc/httpd/conf/addon-modules/php.conf``. The recommended way is +with ``AddType``, so just comment out the first set of lines and +restart Apache: + +.. code-block:: apache + + + #SetOutputFilter PHP + #SetInputFilter PHP + +.. _faq1_30: + +1.30 I get the error "navigation.php: Missing hash". +---------------------------------------------------- + +This problem is known to happen when the server is running Turck +MMCache but upgrading MMCache to version 2.3.21 solves the problem. + +.. _faq1_31: + +1.31 Does phpMyAdmin support PHP 5? +----------------------------------- + +Yes. + +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: + +1.32 Can I use HTTP authentication with IIS? +-------------------------------------------- + +Yes. This procedure was tested with phpMyAdmin 2.6.1, PHP 4.3.9 in +:term:`ISAPI` mode under :term:`IIS` 5.1. + +#. In your :file:`php.ini` file, set ``cgi.rfc2616_headers = 0`` +#. In ``Web Site Properties -> File/Directory Security -> Anonymous + Access`` dialog box, check the ``Anonymous access`` checkbox and + uncheck any other checkboxes (i.e. uncheck ``Basic authentication``, + ``Integrated Windows authentication``, and ``Digest`` if it's + enabled.) Click ``OK``. +#. In ``Custom Errors``, select the range of ``401;1`` through ``401;5`` + and click the ``Set to Default`` button. + +.. seealso:: :rfc:`2616` + +.. _faq1_33: + +1.33 (withdrawn). +----------------- + +.. _faq1_34: + +1.34 Can I access directly to database or table pages? +------------------------------------------------------ + +Yes. Out of the box, you can use :term:`URL` like +http://server/phpMyAdmin/index.php?server=X&db=database&table=table&target=script. +For ``server`` you use the server number +which refers to the order of the server paragraph in +:file:`config.inc.php`. Table and script parts are optional. If you want +http://server/phpMyAdmin/database[/table][/script] :term:`URL`, you need to do some configuration. Following +lines apply only for `Apache `_ web server. +First make sure, that you have enabled some features within global +configuration. You need ``Options FollowSymLinks`` and ``AllowOverride +FileInfo`` enabled for directory where phpMyAdmin is installed and you +need mod\_rewrite to be enabled. Then you just need to create +following :term:`.htaccess` file in root folder of phpMyAdmin installation (don't +forget to change directory name inside of it): + +.. code-block:: apache + + + RewriteEngine On + RewriteBase /path_to_phpMyAdmin + RewriteRule ^([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)/([a-z_]+\.php)$ index.php?db=$1&table=$2&target=$3 [R] + RewriteRule ^([a-zA-Z0-9_]+)/([a-z_]+\.php)$ index.php?db=$1&target=$2 [R] + RewriteRule ^([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)$ index.php?db=$1&table=$2 [R] + RewriteRule ^([a-zA-Z0-9_]+)$ index.php?db=$1 [R] + +.. _faq1_35: + +1.35 Can I use HTTP authentication with Apache CGI? +--------------------------------------------------- + +Yes. However you need to pass authentication variable to :term:`CGI` using +following rewrite rule: + +.. code-block:: apache + + + RewriteEngine On + RewriteRule .* - [E=REMOTE_USER:%{HTTP:Authorization},L] + +.. _faq1_36: + +1.36 I get an error "500 Internal Server Error". +------------------------------------------------ + +There can be many explanations to this and a look at your server's +error log file might give a clue. + +.. _faq1_37: + +1.37 I run phpMyAdmin on cluster of different machines and password encryption in cookie auth doesn't work. +----------------------------------------------------------------------------------------------------------- + +If your cluster consist of different architectures, PHP code used for +encryption/decryption won't work correct. This is caused by use of +pack/unpack functions in code. Only solution is to use mcrypt +extension which works fine in this case. + +.. _faq1_38: + +1.38 Can I use phpMyAdmin on a server on which Suhosin is enabled? +------------------------------------------------------------------ + +Yes but the default configuration values of Suhosin are known to cause +problems with some operations, for example editing a table with many +columns and no primary key or with textual primary key. + +Suhosin configuration might lead to malfunction in some cases and it +can not be fully avoided as phpMyAdmin is kind of application which +needs to transfer big amounts of columns in single HTTP request, what +is something what Suhosin tries to prevent. Generally all +``suhosin.request.*``, ``suhosin.post.*`` and ``suhosin.get.*`` +directives can have negative effect on phpMyAdmin usability. You can +always find in your error logs which limit did cause dropping of +variable, so you can diagnose the problem and adjust matching +configuration variable. + +The default values for most Suhosin configuration options will work in +most scenarios, however you might want to adjust at least following +parameters: + +* `suhosin.request.max\_vars `_ should + be increased (eg. 2048) +* `suhosin.post.max\_vars `_ should be + increased (eg. 2048) +* `suhosin.request.max\_array\_index\_length `_ + should be increased (eg. 256) +* `suhosin.post.max\_array\_index\_length `_ + should be increased (eg. 256) +* `suhosin.request.max\_totalname\_length `_ + should be increased (eg. 8192) +* `suhosin.post.max\_totalname\_length `_ should be + increased (eg. 8192) +* `suhosin.get.max\_value\_length `_ + should be increased (eg. 1024) +* `suhosin.sql.bailout\_on\_error `_ + needs to be disabled (the default) +* `suhosin.log.\* `_ should not + include :term:`SQL`, otherwise you get big + slowdown + +You can also disable the warning using the :config:option:`$cfg['SuhosinDisableWarning']`. + +.. _faq1_39: + +1.39 When I try to connect via https, I can log in, but then my connection is redirected back to http. What can cause this behavior? +------------------------------------------------------------------------------------------------------------------------------------ + +Be sure that you have enabled ``SSLOptions`` and ``StdEnvVars`` in +your Apache configuration. + +.. seealso:: + +.. _faq1_40: + +1.40 When accessing phpMyAdmin via an Apache reverse proxy, cookie login does not work. +--------------------------------------------------------------------------------------- + +To be able to use cookie auth Apache must know that it has to rewrite +the set-cookie headers. Example from the Apache 2.2 documentation: + +.. code-block:: apache + + + ProxyPass /mirror/foo/ http://backend.example.com/ + ProxyPassReverse /mirror/foo/ http://backend.example.com/ + ProxyPassReverseCookieDomain backend.example.com public.example.com + ProxyPassReverseCookiePath / /mirror/foo/ + +Note: if the backend url looks like http://host/~user/phpmyadmin, the +tilde (~) must be url encoded as %7E in the ProxyPassReverse\* lines. +This is not specific to phpmyadmin, it's just the behavior of Apache. + +.. code-block:: apache + + + ProxyPass /mirror/foo/ http://backend.example.com/~user/phpmyadmin + ProxyPassReverse /mirror/foo/ http://backend.example.com/%7Euser/phpmyadmin + ProxyPassReverseCookiePath /%7Euser/phpmyadmin /mirror/foo + +.. seealso:: + +.. _faq1_41: + +1.41 When I view a database and ask to see its privileges, I get an error about an unknown column. +-------------------------------------------------------------------------------------------------- + +The MySQL server's privilege tables are not up to date, you need to +run the :command:`mysql_upgrade` command on the server. + +.. _faq1_42: + +1.42 How can I prevent robots from accessing phpMyAdmin? +-------------------------------------------------------- + +You can add various rules to :term:`.htaccess` to filter access based on user agent +field. This is quite easy to circumvent, but could prevent at least +some robots accessing your installation. + +.. code-block:: apache + + + RewriteEngine on + + # Allow only GET and POST verbs + RewriteCond %{REQUEST_METHOD} !^(GET|POST)$ [NC,OR] + + # Ban Typical Vulnerability Scanners and others + # Kick out Script Kiddies + RewriteCond %{HTTP_USER_AGENT} ^(java|curl|wget).* [NC,OR] + RewriteCond %{HTTP_USER_AGENT} ^.*(libwww-perl|curl|wget|python|nikto|wkito|pikto|scan|acunetix).* [NC,OR] + RewriteCond %{HTTP_USER_AGENT} ^.*(winhttp|HTTrack|clshttp|archiver|loader|email|harvest|extract|grab|miner).* [NC,OR] + + # Ban Search Engines, Crawlers to your administrative panel + # No reasons to access from bots + # Ultimately Better than the useless robots.txt + # Did google respect robots.txt? + # Try google: intitle:phpMyAdmin intext:"Welcome to phpMyAdmin *.*.*" intext:"Log in" -wiki -forum -forums -questions intext:"Cookies must be enabled" + RewriteCond %{HTTP_USER_AGENT} ^.*(AdsBot-Google|ia_archiver|Scooter|Ask.Jeeves|Baiduspider|Exabot|FAST.Enterprise.Crawler|FAST-WebCrawler|www\.neomo\.de|Gigabot|Mediapartners-Google|Google.Desktop|Feedfetcher-Google|Googlebot|heise-IT-Markt-Crawler|heritrix|ibm.com\cs/crawler|ICCrawler|ichiro|MJ12bot|MetagerBot|msnbot-NewsBlogs|msnbot|msnbot-media|NG-Search|lucene.apache.org|NutchCVS|OmniExplorer_Bot|online.link.validator|psbot0|Seekbot|Sensis.Web.Crawler|SEO.search.Crawler|Seoma.\[SEO.Crawler\]|SEOsearch|Snappy|www.urltrends.com|www.tkl.iis.u-tokyo.ac.jp/~crawler|SynooBot|crawleradmin.t-info@telekom.de|TurnitinBot|voyager|W3.SiteSearch.Crawler|W3C-checklink|W3C_Validator|www.WISEnutbot.com|yacybot|Yahoo-MMCrawler|Yahoo\!.DE.Slurp|Yahoo\!.Slurp|YahooSeeker).* [NC] + RewriteRule .* - [F] + +.. _faq1_43: + +1.43 Why can't I display the structure of my table containing hundreds of columns? +---------------------------------------------------------------------------------- + +Because your PHP's ``memory_limit`` is too low; adjust it in :file:`php.ini`. + +.. _faqconfig: + +Configuration ++++++++++++++ + +.. _faq2_1: + +2.1 The error message "Warning: Cannot add header information - headers already sent by ..." is displayed, what's the problem? +------------------------------------------------------------------------------------------------------------------------------ + +Edit your :file:`config.inc.php` file and ensure there is nothing (I.E. no +blank lines, no spaces, no characters...) neither before the ```` tag at the end. We also got a report +from a user under :term:`IIS`, that used a zipped distribution kit: the file +:file:`libraries/Config.class.php` contained an end-of-line character (hex 0A) +at the end; removing this character cleared his errors. + +.. _faq2_2: + +2.2 phpMyAdmin can't connect to MySQL. What's wrong? +---------------------------------------------------- + +Either there is an error with your PHP setup or your username/password +is wrong. Try to make a small script which uses mysql\_connect and see +if it works. If it doesn't, it may be you haven't even compiled MySQL +support into PHP. + +.. _faq2_3: + +2.3 The error message "Warning: MySQL Connection Failed: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (111) ..." is displayed. What can I do? +--------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +For RedHat users, Harald Legner suggests this on the mailing list: + +On my RedHat-Box the socket of MySQL is */var/lib/mysql/mysql.sock*. +In your :file:`php.ini` you will find a line + +.. code-block:: ini + + mysql.default_socket = /tmp/mysql.sock + +change it to + +.. code-block:: ini + + mysql.default_socket = /var/lib/mysql/mysql.sock + +Then restart apache and it will work. + +Here is a fix suggested by Brad Ummer: + +* First, you need to determine what socket is being used by MySQL. To do + this, telnet to your server and go to the MySQL bin directory. In this + directory there should be a file named *mysqladmin*. Type + ``./mysqladmin variables``, and this should give you a bunch of info + about your MySQL server, including the socket (*/tmp/mysql.sock*, for + example). +* Then, you need to tell PHP to use this socket. To do this in + phpMyAdmin, you need to complete the socket information in the + :file:`config.inc.php`. For example: + :config:option:`$cfg['Servers'][$i]['socket']` Please also make sure that + the permissions of this file allow to be readable by your webserver (i.e. + '0755'). + +Have also a look at the `corresponding section of the MySQL +documentation `_. + +.. _faq2_4: + +2.4 Nothing is displayed by my browser when I try to run phpMyAdmin, what can I do? +----------------------------------------------------------------------------------- + +Try to set the :config:option:`$cfg['OBGzip']` directive to ``false`` in the phpMyAdmin configuration +file. It helps sometime. Also have a look at your PHP version number: +if it contains "b" or "alpha" it means you're running a testing +version of PHP. That's not a so good idea, please upgrade to a plain +revision. + +.. _faq2_5: + +2.5 Each time I want to insert or change a row or drop a database or a table, an error 404 (page not found) is displayed or, with HTTP or cookie authentication, I'm asked to log in again. What's wrong? +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +Check the value you set for the :config:option:`$cfg['PmaAbsoluteUri']` directive in the phpMyAdmin +configuration file. + +.. _faq2_6: + +2.6 I get an "Access denied for user: 'root@localhost' (Using password: YES)"-error when trying to access a MySQL-Server on a host which is port-forwarded for my localhost. +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +When you are using a port on your localhost, which you redirect via +port-forwarding to another host, MySQL is not resolving the localhost +as expected. Erik Wasser explains: The solution is: if your host is +"localhost" MySQL (the command line tool :command:`mysql` as well) always +tries to use the socket connection for speeding up things. And that +doesn't work in this configuration with port forwarding. If you enter +"127.0.0.1" as hostname, everything is right and MySQL uses the +:term:`TCP` connection. + +.. _faqthemes: + +2.7 Using and creating themes +----------------------------- + +Themes are configured with :config:option:`$cfg['ThemePath']`, +:config:option:`$cfg['ThemeManager']` and :config:option:`$cfg['ThemeDefault']`. +Under :config:option:`$cfg['ThemePath']`, you should not delete the +directory ``pmahomme`` or its underlying structure, because this is the +system theme used by phpMyAdmin. ``pmahomme`` contains all images and +styles, for backwards compatibility and for all themes that would not +include images or css-files. If :config:option:`$cfg['ThemeManager']` +is enabled, you can select your favorite theme on the main page. Your selected +theme will be stored in a cookie. + +To create a theme: + +* make a new subdirectory (for example "your\_theme\_name") under :config:option:`$cfg['ThemePath']` (by + default ``themes``) +* copy the files and directories from ``pmahomme`` to "your\_theme\_name" +* edit the css-files in "your\_theme\_name/css" +* put your new images in "your\_theme\_name/img" +* edit :file:`layout.inc.php` in "your\_theme\_name" +* edit :file:`info.inc.php` in "your\_theme\_name" to contain your chosen + theme name, that will be visible in user interface +* make a new screenshot of your theme and save it under + "your\_theme\_name/screen.png" + +In theme directory there is file :file:`info.inc.php` which contains theme +verbose name, theme generation and theme version. These versions and +generations are enumerated from 1 and do not have any direct +dependence on phpMyAdmin version. Themes within same generation should +be backwards compatible - theme with version 2 should work in +phpMyAdmin requiring version 1. Themes with different generation are +incompatible. + +If you do not want to use your own symbols and buttons, remove the +directory "img" in "your\_theme\_name". phpMyAdmin will use the +default icons and buttons (from the system-theme ``pmahomme``). + +.. _faqmissingparameters: + +2.8 I get "Missing parameters" errors, what can I do? +----------------------------------------------------- + +Here are a few points to check: + +* In :file:`config.inc.php`, try to leave the :config:option:`$cfg['PmaAbsoluteUri']` directive empty. See also + :ref:`faq4_7`. +* Maybe you have a broken PHP installation or you need to upgrade your + Zend Optimizer. See . +* If you are using Hardened PHP with the ini directive + ``varfilter.max_request_variables`` set to the default (200) or + another low value, you could get this error if your table has a high + number of columns. Adjust this setting accordingly. (Thanks to Klaus + Dorninger for the hint). +* In the :file:`php.ini` directive ``arg_separator.input``, a value of ";" + will cause this error. Replace it with "&;". +* If you are using `Hardened-PHP `_, you + might want to increase `request limits `_. +* The directory specified in the :file:`php.ini` directive + ``session.save_path`` does not exist or is read-only. + +.. _faq2_9: + +2.9 Seeing an upload progress bar +--------------------------------- + +To be able to see a progress bar during your uploads, your server must +have the `APC `_ extension, the +`uploadprogress `_ one, or +you must be running PHP 5.4.0 or higher. Moreover, the JSON extension +has to be enabled in your PHP. + +If using APC, you must set ``apc.rfc1867`` to ``on`` in your :file:`php.ini`. + +If using PHP 5.4.0 or higher, you must set +``session.upload_progress.enabled`` to ``1`` in your :file:`php.ini`. However, +starting from phpMyAdmin version 4.0.4, session-based upload progress has +been temporarily deactivated due to its problematic behavior. + +.. seealso:: :rfc:`1867` + +.. _faqlimitations: + +Known limitations ++++++++++++++++++ + +.. _login_bug: + +3.1 When using HTTP authentication, a user who logged out can not log in again in with the same nick. +----------------------------------------------------------------------------------------------------- + +This is related to the authentication mechanism (protocol) used by +phpMyAdmin. To bypass this problem: just close all the opened browser +windows and then go back to phpMyAdmin. You should be able to log in +again. + +.. _faq3_2: + +3.2 When dumping a large table in compressed mode, I get a memory limit error or a time limit error. +---------------------------------------------------------------------------------------------------- + +Compressed dumps are built in memory and because of this are limited +to php's memory limit. For GZip/BZip2 exports this can be overcome +since 2.5.4 using :config:option:`$cfg['CompressOnFly']` (enabled by default). +Zip exports can not be handled this way, so if you need Zip files for larger +dump, you have to use another way. + +.. _faq3_3: + +3.3 With InnoDB tables, I lose foreign key relationships when I rename a table or a column. +------------------------------------------------------------------------------------------- + +This is an InnoDB bug, see . + +.. _faq3_4: + +3.4 I am unable to import dumps I created with the mysqldump tool bundled with the MySQL server distribution. +------------------------------------------------------------------------------------------------------------- + +The problem is that older versions of ``mysqldump`` created invalid +comments like this: + +.. code-block:: mysql + + + -- MySQL dump 8.22 + -- + -- Host: localhost Database: database + --------------------------------------------------------- + -- Server version 3.23.54 + +The invalid part of the code is the horizontal line made of dashes +that appears once in every dump created with mysqldump. If you want to +run your dump you have to turn it into valid MySQL. This means, you +have to add a whitespace after the first two dashes of the line or add +a # before it: ``-- -------------------------------------------------------`` or +``#---------------------------------------------------------`` + +.. _faq3_5: + +3.5 When using nested folders, multiple hierarchies are displayed in a wrong manner. +------------------------------------------------------------------------------------ + +Please note that you should not use the separating string multiple +times without any characters between them, or at the beginning/end of +your table name. If you have to, think about using another +TableSeparator or disabling that feature. + +.. seealso:: :config:option:`$cfg['NavigationTreeTableSeparator']` + +.. _faq3_6: + +3.6 What is currently not supported in phpMyAdmin about InnoDB? +--------------------------------------------------------------- + +In Relation view, having more than one index column in the foreign key. In Query-by- +example (Query), automatic generation of the query LEFT JOIN from the +foreign table. + +.. _faq3_7: + +3.7 I have table with many (100+) columns and when I try to browse table I get series of errors like "Warning: unable to parse url". How can this be fixed? +----------------------------------------------------------------------------------------------------------------------------------------------------------- + +Your table neither have a primary key nor an unique one, so we must +use a long expression to identify this row. This causes problems to +parse\_url function. The workaround is to create a primary or unique +key. + +.. _faq3_8: + +3.8 I cannot use (clickable) HTML-forms in columns where I put a MIME-Transformation onto! +------------------------------------------------------------------------------------------ + +Due to a surrounding form-container (for multi-row delete checkboxes), +no nested forms can be put inside the table where phpMyAdmin displays +the results. You can, however, use any form inside of a table if keep +the parent form-container with the target to tbl\_row\_delete.php and +just put your own input-elements inside. If you use a custom submit +input field, the form will submit itself to the displaying page again, +where you can validate the $HTTP\_POST\_VARS in a transformation. For +a tutorial on how to effectively use transformations, see our `Link +section `_ on the +official phpMyAdmin-homepage. + +.. _faq3_9: + +3.9 I get error messages when using "--sql\_mode=ANSI" for the MySQL server. +---------------------------------------------------------------------------- + +When MySQL is running in ANSI-compatibility mode, there are some major +differences in how :term:`SQL` is structured (see +). Most important of all, the +quote-character (") is interpreted as an identifier quote character and not as +a string quote character, which makes many internal phpMyAdmin operations into +invalid :term:`SQL` statements. There is no +workaround to this behaviour. News to this item will be posted in `Bug report +#1013 `_. + +.. _faq3_10: + +3.10 Homonyms and no primary key: When the results of a SELECT display more that one column with the same value (for example ``SELECT lastname from employees where firstname like 'A%'`` and two "Smith" values are displayed), if I click Edit I cannot be sure that I am editing the intended row. +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +Please make sure that your table has a primary key, so that phpMyAdmin +can use it for the Edit and Delete links. + +.. _faq3_11: + +3.11 The number of rows for InnoDB tables is not correct. +--------------------------------------------------------- + +phpMyAdmin uses a quick method to get the row count, and this method only +returns an approximate count in the case of InnoDB tables. See +:config:option:`$cfg['MaxExactCount']` for a way to modify those results, but +this could have a serious impact on performance. + +.. _faq3_12: + +3.12 (withdrawn). +----------------- + +.. _faq3_13: + +3.13 I get an error when entering ``USE`` followed by a db name containing an hyphen. +------------------------------------------------------------------------------------- + +The tests I have made with MySQL 5.1.49 shows that the API does not +accept this syntax for the USE command. + +.. _faq3_14: + +3.14 I am not able to browse a table when I don't have the right to SELECT one of the columns. +---------------------------------------------------------------------------------------------- + +This has been a known limitation of phpMyAdmin since the beginning and +it's not likely to be solved in the future. + +.. _faq3_15: + +3.15 (withdrawn). +----------------- + +.. _faq3_16: + +3.16 (withdrawn). +----------------- + +.. _faq3_17: + +3.17 (withdrawn). +----------------- + +.. _faq3_18: + +3.18 When I import a CSV file that contains multiple tables, they are lumped together into a single table. +---------------------------------------------------------------------------------------------------------- + +There is no reliable way to differentiate tables in :term:`CSV` format. For the +time being, you will have to break apart :term:`CSV` files containing multiple +tables. + +.. _faq3_19: + +3.19 When I import a file and have phpMyAdmin determine the appropriate data structure it only uses int, decimal, and varchar types. +------------------------------------------------------------------------------------------------------------------------------------ + +Currently, the import type-detection system can only assign these +MySQL types to columns. In future, more will likely be added but for +the time being you will have to edit the structure to your liking +post-import. Also, you should note the fact that phpMyAdmin will use +the size of the largest item in any given column as the column size +for the appropriate type. If you know you will be adding larger items +to that column then you should manually adjust the column sizes +accordingly. This is done for the sake of efficiency. + +.. _faq3_20: + +3.20 After upgrading, some bookmarks are gone or their content cannot be shown. +------------------------------------------------------------------------------- + +At some point, the character set used to store bookmark content has changed. +It's better to recreate your bookmark from the newer phpMyAdmin version. + +.. _faqmultiuser: + +ISPs, multi-user installations +++++++++++++++++++++++++++++++ + +.. _faq4_1: + +4.1 I'm an ISP. Can I setup one central copy of phpMyAdmin or do I need to install it for each customer? +-------------------------------------------------------------------------------------------------------- + +Since version 2.0.3, you can setup a central copy of phpMyAdmin for all your +users. The development of this feature was kindly sponsored by NetCologne GmbH. +This requires a properly setup MySQL user management and phpMyAdmin +:term:`HTTP` or cookie authentication. + +.. seealso:: :ref:`authentication_modes` + +.. _faq4_2: + +4.2 What's the preferred way of making phpMyAdmin secure against evil access? +----------------------------------------------------------------------------- + +This depends on your system. If you're running a server which cannot be +accessed by other people, it's sufficient to use the directory protection +bundled with your webserver (with Apache you can use :term:`.htaccess` files, +for example). If other people have telnet access to your server, you should use +phpMyAdmin's :term:`HTTP` or cookie authentication features. + +Suggestions: + +* Your :file:`config.inc.php` file should be ``chmod 660``. +* All your phpMyAdmin files should be chown -R phpmy.apache, where phpmy + is a user whose password is only known to you, and apache is the group + under which Apache runs. +* Follow security recommendations for PHP and your webserver. + +.. _faq4_3: + +4.3 I get errors about not being able to include a file in */lang* or in */libraries*. +-------------------------------------------------------------------------------------- + +Check :file:`php.ini`, or ask your sysadmin to check it. The +``include_path`` must contain "." somewhere in it, and +``open_basedir``, if used, must contain "." and "./lang" to allow +normal operation of phpMyAdmin. + +.. _faq4_4: + +4.4 phpMyAdmin always gives "Access denied" when using HTTP authentication. +--------------------------------------------------------------------------- + +This could happen for several reasons: + +* :config:option:`$cfg['Servers'][$i]['controluser']` and/or :config:option:`$cfg['Servers'][$i]['controlpass']` are wrong. +* The username/password you specify in the login dialog are invalid. +* You have already setup a security mechanism for the phpMyAdmin- + directory, eg. a :term:`.htaccess` file. This would interfere with phpMyAdmin's + authentication, so remove it. + +.. _faq4_5: + +4.5 Is it possible to let users create their own databases? +----------------------------------------------------------- + +Starting with 2.2.5, in the user management page, you can enter a +wildcard database name for a user (for example "joe%"), and put the +privileges you want. For example, adding ``SELECT, INSERT, UPDATE, +DELETE, CREATE, DROP, INDEX, ALTER`` would let a user create/manage +his/her database(s). + +.. _faq4_6: + +4.6 How can I use the Host-based authentication additions? +---------------------------------------------------------- + +If you have existing rules from an old :term:`.htaccess` file, you can take them and +add a username between the ``'deny'``/``'allow'`` and ``'from'`` +strings. Using the username wildcard of ``'%'`` would be a major +benefit here if your installation is suited to using it. Then you can +just add those updated lines into the +:config:option:`$cfg['Servers'][$i]['AllowDeny']['rules']` array. + +If you want a pre-made sample, you can try this fragment. It stops the +'root' user from logging in from any networks other than the private +network :term:`IP` blocks. + +.. code-block:: php + + + //block root from logging in except from the private networks + $cfg['Servers'][$i]['AllowDeny']['order'] = 'deny,allow'; + $cfg['Servers'][$i]['AllowDeny']['rules'] = array( + 'deny root from all', + 'allow root from localhost', + 'allow root from 10.0.0.0/8', + 'allow root from 192.168.0.0/16', + 'allow root from 172.16.0.0/12', + ); + +.. _faq4_7: + +4.7 Authentication window is displayed more than once, why? +----------------------------------------------------------- + +This happens if you are using a :term:`URL` to start phpMyAdmin which is +different than the one set in your :config:option:`$cfg['PmaAbsoluteUri']`. For +example, a missing "www", or entering with an :term:`IP` address while a domain +name is defined in the config file. + +.. _faq4_8: + +4.8 Which parameters can I use in the URL that starts phpMyAdmin? +----------------------------------------------------------------- + +When starting phpMyAdmin, you can use the ``db``, ``pma_username``, +``pma_password`` and ``server`` parameters. This last one can contain +either the numeric host index (from ``$i`` of the configuration file) +or one of the host names present in the configuration file. Using +``pma_username`` and ``pma_password`` has been tested along with the +usage of 'cookie' ``auth_type``. + +.. _faqbrowsers: + +Browsers or client OS ++++++++++++++++++++++ + +.. _faq5_1: + +5.1 I get an out of memory error, and my controls are non-functional, when trying to create a table with more than 14 columns. +------------------------------------------------------------------------------------------------------------------------------ + +We could reproduce this problem only under Win98/98SE. Testing under +WinNT4 or Win2K, we could easily create more than 60 columns. A +workaround is to create a smaller number of columns, then come back to +your table properties and add the other columns. + +.. _faq5_2: + +5.2 With Xitami 2.5b4, phpMyAdmin won't process form fields. +------------------------------------------------------------ + +This is not a phpMyAdmin problem but a Xitami known bug: you'll face +it with each script/website that use forms. Upgrade or downgrade your +Xitami server. + +.. _faq5_3: + +5.3 I have problems dumping tables with Konqueror (phpMyAdmin 2.2.2). +--------------------------------------------------------------------- + +With Konqueror 2.1.1: plain dumps, zip and GZip dumps work ok, except +that the proposed file name for the dump is always 'tbl\_dump.php'. +Bzip2 dumps don't seem to work. With Konqueror 2.2.1: plain dumps +work; zip dumps are placed into the user's temporary directory, so +they must be moved before closing Konqueror, or else they disappear. +GZip dumps give an error message. Testing needs to be done for +Konqueror 2.2.2. + +.. _faq5_4: + +5.4 I can't use the cookie authentication mode because Internet Explorer never stores the cookies. +-------------------------------------------------------------------------------------------------- + +MS Internet Explorer seems to be really buggy about cookies, at least +till version 6. + +.. _faq5_5: + +5.5 In Internet Explorer 5.0, I get JavaScript errors when browsing my rows. +---------------------------------------------------------------------------- + +Upgrade to at least Internet Explorer 5.5 SP2. + +.. _faq5_6: + +5.6 In Internet Explorer 5.0, 5.5 or 6.0, I get an error (like "Page not found") when trying to modify a row in a table with many columns, or with a text column. +----------------------------------------------------------------------------------------------------------------------------------------------------------------- + +Your table neither have a primary key nor an unique one, so we must use a long +:term:`URL` to identify this row. There is a limit on the length of the +:term:`URL` in those browsers, and this not happen in Netscape, for example. +The workaround is to create a primary or unique key, or use another browser. + +.. _faq5_7: + +5.7 I refresh (reload) my browser, and come back to the welcome page. +--------------------------------------------------------------------- + +Some browsers support right-clicking into the frame you want to +refresh, just do this in the right frame. + +.. _faq5_8: + +5.8 With Mozilla 0.9.7 I have problems sending a query modified in the query box. +--------------------------------------------------------------------------------- + +Looks like a Mozilla bug: 0.9.6 was OK. We will keep an eye on future +Mozilla versions. + +.. _faq5_9: + +5.9 With Mozilla 0.9.? to 1.0 and Netscape 7.0-PR1 I can't type a whitespace in the SQL-Query edit area: the page scrolls down. +------------------------------------------------------------------------------------------------------------------------------- + +This is a Mozilla bug (see bug #26882 at `BugZilla +`_). + +.. _faq5_10: + +5.10 With Netscape 4.75 I get empty rows between each row of data in a CSV exported file. +----------------------------------------------------------------------------------------- + +This is a known Netscape 4.75 bug: it adds some line feeds when +exporting data in octet-stream mode. Since we can't detect the +specific Netscape version, we cannot workaround this bug. + +.. _faq5_11: + +5.11 Extended-ASCII characters like German umlauts are displayed wrong. +----------------------------------------------------------------------- + +Please ensure that you have set your browser's character set to the +one of the language file you have selected on phpMyAdmin's start page. +Alternatively, you can try the auto detection mode that is supported +by the recent versions of the most browsers. + +.. _faq5_12: + +5.12 Mac OS X Safari browser changes special characters to "?". +--------------------------------------------------------------- + +This issue has been reported by a :term:`Mac OS X` user, who adds that Chimera, +Netscape and Mozilla do not have this problem. + +.. _faq5_13: + +5.13 With Internet Explorer 5.5 or 6, and HTTP authentication type, I cannot manage two servers: I log in to the first one, then the other one, but if I switch back to the first, I have to log in on each operation. +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +This is a bug in Internet Explorer, other browsers do not behave this +way. + +.. _faq5_14: + +5.14 Using Opera6, I can manage to get to the authentication, but nothing happens after that, only a blank screen. +------------------------------------------------------------------------------------------------------------------ + +Please upgrade to Opera7 at least. + +.. _faq5_15: + +5.15 I have display problems with Safari. +----------------------------------------- + +Please upgrade to at least version 1.2.3. + +.. _faq5_16: + +5.16 With Internet Explorer, I get "Access is denied" Javascript errors. Or I cannot make phpMyAdmin work under Windows. +------------------------------------------------------------------------------------------------------------------------ + +Please check the following points: + +* Maybe you have defined your :config:option:`$cfg['PmaAbsoluteUri']` setting in + :file:`config.inc.php` to an :term:`IP` address and you are starting phpMyAdmin + with a :term:`URL` containing a domain name, or the reverse situation. +* Security settings in IE and/or Microsoft Security Center are too high, + thus blocking scripts execution. +* The Windows Firewall is blocking Apache and MySQL. You must allow + :term:`HTTP` ports (80 or 443) and MySQL + port (usually 3306) in the "in" and "out" directions. + +.. _faq5_17: + +5.17 With Firefox, I cannot delete rows of data or drop a database. +------------------------------------------------------------------- + +Many users have confirmed that the Tabbrowser Extensions plugin they +installed in their Firefox is causing the problem. + +.. _faq5_18: + +5.18 With Konqueror 4.2.x an invalid ``LIMIT`` clause is generated when I browse a table. +----------------------------------------------------------------------------------------- + +This happens only when both of these conditions are met: using the +``http`` authentication mode and ``register_globals`` being set to +``On`` on the server. It seems to be a browser-specific problem; +meanwhile use the ``cookie`` authentication mode. + +.. _faq5_19: + +5.19 I get JavaScript errors in my browser. +------------------------------------------- + +Issues have been reported with some combinations of browser +extensions. To troubleshoot, disable all extensions then clear your +browser cache to see if the problem goes away. + +.. _faqusing: + +Using phpMyAdmin +++++++++++++++++ + +.. _faq6_1: + +6.1 I can't insert new rows into a table / I can't create a table - MySQL brings up a SQL error. +------------------------------------------------------------------------------------------------ + +Examine the :term:`SQL` error with care. +Often the problem is caused by specifying a wrong column-type. Common +errors include: + +* Using ``VARCHAR`` without a size argument +* Using ``TEXT`` or ``BLOB`` with a size argument + +Also, look at the syntax chapter in the MySQL manual to confirm that +your syntax is correct. + +.. _faq6_2: + +6.2 When I create a table, I set an index for two columns and phpMyAdmin generates only one index with those two columns. +------------------------------------------------------------------------------------------------------------------------- + +This is the way to create a multi-columns index. If you want two +indexes, create the first one when creating the table, save, then +display the table properties and click the Index link to create the +other index. + +.. _faq6_3: + +6.3 How can I insert a null value into my table? +------------------------------------------------ + +Since version 2.2.3, you have a checkbox for each column that can be +null. Before 2.2.3, you had to enter "null", without the quotes, as +the column's value. Since version 2.5.5, you have to use the checkbox +to get a real NULL value, so if you enter "NULL" this means you want a +literal NULL in the column, and not a NULL value (this works in PHP4). + +.. _faq6_4: + +6.4 How can I backup my database or table? +------------------------------------------ + +Click on a database or table name in the navigation panel, the properties will +be displayed. Then on the menu, click "Export", you can dump the structure, the +data, or both. This will generate standard :term:`SQL` statements that can be +used to recreate your database/table. You will need to choose "Save as file", +so that phpMyAdmin can transmit the resulting dump to your station. Depending +on your PHP configuration, you will see options to compress the dump. See also +the :config:option:`$cfg['ExecTimeLimit']` configuration variable. For +additional help on this subject, look for the word "dump" in this document. + +.. _faq6_5: + +6.5 How can I restore (upload) my database or table using a dump? How can I run a ".sql" file? +---------------------------------------------------------------------------------------------- + +Click on a database name in the navigation panel, the properties will +be displayed. Select "Import" from the list of tabs in the right–hand +frame (or ":term:`SQL`" if your phpMyAdmin +version is previous to 2.7.0). In the "Location of the text file" +section, type in the path to your dump filename, or use the Browse +button. Then click Go. With version 2.7.0, the import engine has been +re–written, if possible it is suggested that you upgrade to take +advantage of the new features. For additional help on this subject, +look for the word "upload" in this document. + +.. _faq6_6: + +6.6 How can I use the relation table in Query-by-example? +--------------------------------------------------------- + +Here is an example with the tables persons, towns and countries, all +located in the database "mydb". If you don't have a ``pma__relation`` +table, create it as explained in the configuration section. Then +create the example tables: + +.. code-block:: mysql + + + CREATE TABLE REL_countries ( + country_code char(1) NOT NULL default '', + description varchar(10) NOT NULL default '', + PRIMARY KEY (country_code) + ) TYPE=MyISAM; + + INSERT INTO REL_countries VALUES ('C', 'Canada'); + + CREATE TABLE REL_persons ( + id tinyint(4) NOT NULL auto_increment, + person_name varchar(32) NOT NULL default '', + town_code varchar(5) default '0', + country_code char(1) NOT NULL default '', + PRIMARY KEY (id) + ) TYPE=MyISAM; + + INSERT INTO REL_persons VALUES (11, 'Marc', 'S', ''); + INSERT INTO REL_persons VALUES (15, 'Paul', 'S', 'C'); + + CREATE TABLE REL_towns ( + town_code varchar(5) NOT NULL default '0', + description varchar(30) NOT NULL default '', + PRIMARY KEY (town_code) + ) TYPE=MyISAM; + + INSERT INTO REL_towns VALUES ('S', 'Sherbrooke'); + INSERT INTO REL_towns VALUES ('M', 'Montréal'); + +To setup appropriate links and display information: + +* on table "REL\_persons" click Structure, then Relation view +* for "town\_code", choose from dropdowns, "mydb", "REL\_towns", "code" + for foreign database, table and column respectively +* for "country\_code", choose from dropdowns, "mydb", "REL\_countries", + "country\_code" for foreign database, table and column respectively +* on table "REL\_towns" click Structure, then Relation view +* in "Choose column to display", choose "description" +* repeat the two previous steps for table "REL\_countries" + +Then test like this: + +* Click on your db name in the navigation panel +* Choose "Query" +* Use tables: persons, towns, countries +* Click "Update query" +* In the columns row, choose persons.person\_name and click the "Show" + tickbox +* Do the same for towns.description and countries.descriptions in the + other 2 columns +* Click "Update query" and you will see in the query box that the + correct joins have been generated +* Click "Submit query" + +.. _faqdisplay: + +6.7 How can I use the "display column" feature? +----------------------------------------------- + +Starting from the previous example, create the ``pma__table_info`` as +explained in the configuration section, then browse your persons +table, and move the mouse over a town code or country code. See also +:ref:`faq6_21` for an additional feature that "display column" +enables: drop-down list of possible values. + +.. _faqpdf: + +6.8 How can I produce a PDF schema of my database? +-------------------------------------------------- + +First the configuration variables "relation", "table\_coords" and +"pdf\_pages" have to be filled in. Then you need to think about your +schema layout. Which tables will go on which pages? + +* Select your database in the navigation panel. +* Choose "Operations" in the navigation bar at the top. +* Choose "Edit :term:`PDF` Pages" near the + bottom of the page. +* Enter a name for the first :term:`PDF` page + and click Go. If you like, you can use the "automatic layout," which + will put all your linked tables onto the new page. +* Select the name of the new page (making sure the Edit radio button is + selected) and click Go. +* Select a table from the list, enter its coordinates and click Save. + Coordinates are relative; your diagram will be automatically scaled to + fit the page. When initially placing tables on the page, just pick any + coordinates -- say, 50x50. After clicking Save, you can then use the + :ref:`wysiwyg` to position the element correctly. +* When you'd like to look at your :term:`PDF`, first be sure to click the Save + button beneath the list of tables and coordinates, to save any changes you + made there. Then scroll all the way down, select the :term:`PDF` options you + want, and click Go. +* Internet Explorer for Windows may suggest an incorrect filename when + you try to save a generated :term:`PDF`. + When saving a generated :term:`PDF`, be + sure that the filename ends in ".pdf", for example "schema.pdf". + Browsers on other operating systems, and other browsers on Windows, do + not have this problem. + +.. _faq6_9: + +6.9 phpMyAdmin is changing the type of one of my columns! +--------------------------------------------------------- + +No, it's MySQL that is doing `silent column type changing +`_. + +.. _underscore: + +6.10 When creating a privilege, what happens with underscores in the database name? +----------------------------------------------------------------------------------- + +If you do not put a backslash before the underscore, this is a +wildcard grant, and the underscore means "any character". So, if the +database name is "john\_db", the user would get rights to john1db, +john2db ... If you put a backslash before the underscore, it means +that the database name will have a real underscore. + +.. _faq6_11: + +6.11 What is the curious symbol ø in the statistics pages? +---------------------------------------------------------- + +It means "average". + +.. _faqexport: + +6.12 I want to understand some Export options. +---------------------------------------------- + +**Structure:** + +* "Add DROP TABLE" will add a line telling MySQL to `drop the table + `_, if it already + exists during the import. It does NOT drop the table after your + export, it only affects the import file. +* "If Not Exists" will only create the table if it doesn't exist. + Otherwise, you may get an error if the table name exists but has a + different structure. +* "Add AUTO\_INCREMENT value" ensures that AUTO\_INCREMENT value (if + any) will be included in backup. +* "Enclose table and column names with backquotes" ensures that column + and table names formed with special characters are protected. +* "Add into comments" includes column comments, relations, and MIME + types set in the pmadb in the dump as :term:`SQL` comments + (*/\* xxx \*/*). + +**Data:** + +* "Complete inserts" adds the column names on every INSERT command, for + better documentation (but resulting file is bigger). +* "Extended inserts" provides a shorter dump file by using only once the + INSERT verb and the table name. +* "Delayed inserts" are best explained in the `MySQL manual - INSERT DELAYED Syntax + `_. +* "Ignore inserts" treats errors as a warning instead. Again, more info + is provided in the `MySQL manual - INSERT Syntax + `_, but basically with + this selected, invalid values are adjusted and inserted rather than + causing the entire statement to fail. + +.. _faq6_13: + +6.13 I would like to create a database with a dot in its name. +-------------------------------------------------------------- + +This is a bad idea, because in MySQL the syntax "database.table" is +the normal way to reference a database and table name. Worse, MySQL +will usually let you create a database with a dot, but then you cannot +work with it, nor delete it. + +.. _faqsqlvalidator: + +6.14 How do I set up the SQL Validator? +--------------------------------------- + +To use SQL Validator, you need PHP with :term:`XML`, :term:`PCRE` and +:term:`PEAR` support. In addition you need a :term:`SOAP` support, either as a +PHP extension or as a PEAR SOAP module. + +To install :term:`PEAR` :term:`SOAP` module, run :command:`pear install +Net_Socket Net_URL HTTP_Request Mail_Mime Net_DIME SOAP` to get the necessary +:term:`PEAR` modules for usage. + +If you use the Validator, you should be aware that any :term:`SQL` statement +you submit will be stored anonymously (database/table/column names, strings, +numbers replaced with generic values). The Mimer :term:`SQL` Validator itself, +is © 2001 Upright Database Technology. We utilize it as free SOAP service. + +.. _faq6_15: + +6.15 I want to add a BLOB column and put an index on it, but MySQL says "BLOB column '...' used in key specification without a key length". +------------------------------------------------------------------------------------------------------------------------------------------- + +The right way to do this, is to create the column without any indexes, +then display the table structure and use the "Create an index" dialog. +On this page, you will be able to choose your BLOB column, and set a +size to the index, which is the condition to create an index on a BLOB +column. + +.. _faq6_16: + +6.16 How can I simply move in page with plenty editing fields? +-------------------------------------------------------------- + +You can use :kbd:`Ctrl+arrows` (:kbd:`Option+Arrows` in Safari) for moving on +most pages with many editing fields (table structure changes, row editing, +etc.). + +.. _faq6_17: + +6.17 Transformations: I can't enter my own mimetype! WTF is this feature then useful for? +----------------------------------------------------------------------------------------- + +Slow down :). Defining mimetypes is of no use, if you can't put +transformations on them. Otherwise you could just put a comment on the +column. Because entering your own mimetype will cause serious syntax +checking issues and validation, this introduces a high-risk false- +user-input situation. Instead you have to initialize mimetypes using +functions or empty mimetype definitions. + +Plus, you have a whole overview of available mimetypes. Who knows all those +mimetypes by heart so he/she can enter it at will? + +.. _faqbookmark: + +6.18 Bookmarks: Where can I store bookmarks? Why can't I see any bookmarks below the query box? What is this variable for? +-------------------------------------------------------------------------------------------------------------------------- + +Any query you have executed can be stored as a bookmark on the page +where the results are displayed. You will find a button labeled +'Bookmark this query' just at the end of the page. As soon as you have +stored a bookmark, it is related to the database you run the query on. +You can now access a bookmark dropdown on each page, the query box +appears on for that database. + +You can also have, inside the query, a placeholder for a variable. +This is done by inserting into the query a SQL comment between ``/*`` and +``*/``. Inside the comment, the special string ``[VARIABLE]`` is used. +Be aware that the whole query minus the SQL comment must be +valid by itself, otherwise you won't be able to store it as a bookmark. + +When you execute the bookmark, everything typed into the *value* +input box on the query box page will replace the string ``/*[VARIABLE]*/`` in +your stored query. + +Also remember, that everything else inside the ``/*[VARIABLE]*/`` string for +your query will remain the way it is, but will be stripped of the ``/**/`` +chars. So you can use: + +.. code-block:: mysql + + /*, [VARIABLE] AS myname */ + +which will be expanded to + +.. code-block:: mysql + + , VARIABLE as myname + +in your query, where VARIABLE is the string you entered in the input box. If an +empty string is provided, no replacements are made. + +A more complex example. Say you have stored +this query: + +.. code-block:: mysql + + SELECT Name, Address FROM addresses WHERE 1 /* AND Name LIKE '%[VARIABLE]%' */ + +Say, you now enter "phpMyAdmin" as the variable for the stored query, the full +query will be: + +.. code-block:: mysql + + SELECT Name, Address FROM addresses WHERE 1 AND Name LIKE '%phpMyAdmin%' + +You can use multiple occurrences of ``/*[VARIABLE]*/`` in a single query +(that is, multiple occurrences of the *same* variable). + +**NOTE THE ABSENCE OF SPACES** inside the ``/**/`` construct. Any spaces +inserted there will be later also inserted as spaces in your query and may lead +to unexpected results especially when using the variable expansion inside of a +"LIKE ''" expression. + +Your initial query which is going to be stored as a bookmark has to yield at +least one result row so you can store the bookmark. You may have that to work +around using well positioned ``/**/`` comments. + +.. _faq6_19: + +6.19 How can I create simple LATEX document to include exported table? +---------------------------------------------------------------------- + +You can simply include table in your LATEX documents, +minimal sample document should look like following one (assuming you +have table exported in file :file:`table.tex`): + +.. code-block:: latex + + + \documentclass{article} % or any class you want + \usepackage{longtable} % for displaying table + \begin{document} % start of document + \include{table} % including exported table + \end{document} % end of document + +.. _faq6_20: + +6.20 I see a lot of databases which are not mine, and cannot access them. +------------------------------------------------------------------------- + +You have one of these global privileges: CREATE TEMPORARY TABLES, SHOW +DATABASES, LOCK TABLES. Those privileges also enable users to see all the +database names. So if your users do not need those privileges, you can remove +them and their databases list will shorten. + +.. seealso:: + +.. _faq6_21: + +6.21 In edit/insert mode, how can I see a list of possible values for a column, based on some foreign table? +------------------------------------------------------------------------------------------------------------ + +You have to setup appropriate links between the tables, and also setup +the "display column" in the foreign table. See :ref:`faq6_6` for an +example. Then, if there are 100 values or less in the foreign table, a +drop-down list of values will be available. You will see two lists of +values, the first list containing the key and the display column, the +second list containing the display column and the key. The reason for +this is to be able to type the first letter of either the key or the +display column. For 100 values or more, a distinct window will appear, +to browse foreign key values and choose one. To change the default +limit of 100, see :config:option:`$cfg['ForeignKeyMaxLimit']`. + + +.. _faq6_22: + +6.22 Bookmarks: Can I execute a default bookmark automatically when entering Browse mode for a table? +----------------------------------------------------------------------------------------------------- + +Yes. If a bookmark has the same label as a table name and it's not a +public bookmark, it will be executed. + +.. _faq6_23: + +6.23 Export: I heard phpMyAdmin can export Microsoft Excel files? +----------------------------------------------------------------- + +You can use :term:`CSV` for Microsoft Excel, +which works out of the box. + +.. versionchanged:: 3.4.5 + Since phpMyAdmin 3.4.5 support for direct export to Microsoft Excel version + 97 and newer was dropped. + +.. _faq6_24: + +6.24 Now that phpMyAdmin supports native MySQL 4.1.x column comments, what happens to my column comments stored in pmadb? +------------------------------------------------------------------------------------------------------------------------- + +Automatic migration of a table's pmadb-style column comments to the +native ones is done whenever you enter Structure page for this table. + +.. _faq6_25: + +6.25 (withdrawn). +----------------- + +.. _faq6_26: + +6.26 How can I select a range of rows? +-------------------------------------- + +Click the first row of the range, hold the shift key and click the +last row of the range. This works everywhere you see rows, for example +in Browse mode or on the Structure page. + +.. _faq6_27: + +6.27 What format strings can I use? +----------------------------------- + +In all places where phpMyAdmin accepts format strings, you can use +``@VARIABLE@`` expansion and `strftime `_ +format strings. The expanded variables depend on a context (for +example, if you haven't chosen a table, you can not get the table +name), but the following variables can be used: + +``@HTTP_HOST@`` + HTTP host that runs phpMyAdmin +``@SERVER@`` + MySQL server name +``@VERBOSE@`` + Verbose MySQL server name as defined in :config:option:`$cfg['Servers'][$i]['verbose']` +``@VSERVER@`` + Verbose MySQL server name if set, otherwise normal +``@DATABASE@`` + Currently opened database +``@TABLE@`` + Currently opened table +``@COLUMNS@`` + Columns of the currently opened table +``@PHPMYADMIN@`` + phpMyAdmin with version + +.. _wysiwyg: + +6.28 How can I easily edit relational schema for export? +-------------------------------------------------------- + +By clicking on the button 'toggle scratchboard' on the page where you +edit x/y coordinates of those elements you can activate a scratchboard +where all your elements are placed. By clicking on an element, you can +move them around in the pre-defined area and the x/y coordinates will +get updated dynamically. Likewise, when entering a new position +directly into the input field, the new position in the scratchboard +changes after your cursor leaves the input field. + +You have to click on the 'OK'-button below the tables to save the new +positions. If you want to place a new element, first add it to the +table of elements and then you can drag the new element around. + +By changing the paper size and the orientation you can change the size +of the scratchboard as well. You can do so by just changing the +dropdown field below, and the scratchboard will resize automatically, +without interfering with the current placement of the elements. + +If ever an element gets out of range you can either enlarge the paper +size or click on the 'reset' button to place all elements below each +other. + +.. _faq6_29: + +6.29 Why can't I get a chart from my query result table? +-------------------------------------------------------- + +Not every table can be put to the chart. Only tables with one, two or +three columns can be visualised as a chart. Moreover the table must be +in a special format for chart script to understand it. Currently +supported formats can be found in the `wiki `_. + +.. _faq6_30: + +6.30 Import: How can I import ESRI Shapefiles? +---------------------------------------------- + +An ESRI Shapefile is actually a set of several files, where .shp file +contains geometry data and .dbf file contains data related to those +geometry data. To read data from .dbf file you need to have PHP +compiled with the dBase extension (--enable-dbase). Otherwise only +geometry data will be imported. + +To upload these set of files you can use either of the following +methods: + +Configure upload directory with :config:option:`$cfg['UploadDir']`, upload both .shp and .dbf files with +the same filename and chose the .shp file from the import page. + +Create a Zip archive with .shp and .dbf files and import it. For this +to work, you need to set :config:option:`$cfg['TempDir']` to a place where the web server user can +write (for example ``'./tmp'``). + +To create the temporary directory on a UNIX-based system, you can do: + +.. code-block:: sh + + cd phpMyAdmin + mkdir tmp + chmod o+rwx tmp + +.. _faq6_31: + +6.31 How do I create a relation in designer? +-------------------------------------------- + +To select relation, click: The display column is shown in pink. To +set/unset a column as the display column, click the "Choose column to +display" icon, then click on the appropriate column name. + +.. _faq6_32: + +6.32 How can I use the zoom search feature? +------------------------------------------- + +The Zoom search feature is an alternative to table search feature. It allows +you to explore a table by representing its data in a scatter plot. You can +locate this feature by selecting a table and clicking the :guilabel:`Search` +tab. One of the sub-tabs in the :guilabel:`Table Search` page is +:guilabel:`Zoom Search`. + +Consider the table REL\_persons in :ref:`faq6_6` for +an example. To use zoom search, two columns need to be selected, for +example, id and town\_code. The id values will be represented on one +axis and town\_code values on the other axis. Each row will be +represented as a point in a scatter plot based on its id and +town\_code. You can include two additional search criteria apart from +the two fields to display. + +You can choose which field should be +displayed as label for each point. If a display column has been set +for the table (see :ref:`faqdisplay`), it is taken as the label unless +you specify otherwise. You can also select the maximum number of rows +you want to be displayed in the plot by specifing it in the 'Max rows +to plot' field. Once you have decided over your criteria, click 'Go' +to display the plot. + +After the plot is generated, you can use the +mousewheel to zoom in and out of the plot. In addition, panning +feature is enabled to navigate through the plot. You can zoom-in to a +certail level of detail and use panning to locate your area of +interest. Clicking on a point opens a dialogue box, displaying field +values of the data row represented by the point. You can edit the +values if required and click on submit to issue an update query. Basic +instructions on how to use can be viewed by clicking the 'How to use?' +link located just above the plot. + +.. _faq6_33: + +6.33 When browsing a table, how can I copy a column name? +--------------------------------------------------------- + +Selecting the name of the column within the browse table header cell +for copying is difficult, as the columns support reordering by +dragging the header cells as well as sorting by clicking on the linked +column name. To copy a column name, double-click on the empty area +next to the column name, when the tooltip tells you to do so. This +will show you an input box with the column name. You may right-click +the column name within this input box to copy it to your clipboard. + +.. _faqproject: + +phpMyAdmin project +++++++++++++++++++ + +.. _faq7_1: + +7.1 I have found a bug. How do I inform developers? +--------------------------------------------------- + +Our Bug Tracker is located at under the +Bugs section. But please first discuss your bug with other users: +. + +.. _faq7_2: + +7.2 I want to translate the messages to a new language or upgrade an existing language, where do I start? +--------------------------------------------------------------------------------------------------------- + +Translations are very welcome and all you need to have are the +language skills. The easiest way is to use our `online translation +service `_. You can check +out all the possibilities to translate in the `translate section on +our website `_. + +.. _faq7_3: + +7.3 I would like to help out with the development of phpMyAdmin. How should I proceed? +-------------------------------------------------------------------------------------- + +We welcome every contribution to the development of phpMyAdmin. You +can check out all the possibilities to contribute in the `contribute +section on our website +`_. + +.. seealso:: :ref:`developers` + +.. _faqsecurity: + +Security +++++++++ + +.. _faq8_1: + +8.1 Where can I get information about the security alerts issued for phpMyAdmin? +-------------------------------------------------------------------------------- + +Please refer to . + +.. _faq8_2: + +8.2 How can I protect phpMyAdmin against brute force attacks? +------------------------------------------------------------- + +If you use Apache web server, phpMyAdmin exports information about +authentication to the Apache environment and it can be used in Apache +logs. Currently there are two variables available: + + +``userID`` + User name of currently active user (he does not have to be logged in). +``userStatus`` + Status of currently active user, one of ``ok`` (user is logged in), + ``mysql-denied`` (MySQL denied user login), ``allow-denied`` (user denied + by allow/deny rules), ``root-denied`` (root is denied in configuration), + ``empty-denied`` (empty password is denied). + +``LogFormat`` directive for Apache can look like following: + +.. code-block:: apache + + LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %{userID}n %{userStatus}n" pma_combined + +You can then use any log analyzing tools to detect possible break-in +attempts. + +.. _faqsynchronization: + +Synchronization ++++++++++++++++ + +.. _faq9_1: + +9.1 (withdrawn). +---------------- + +.. _faq9_2: + +9.2 (withdrawn). +---------------- + diff --git a/phpMyAdmin/doc/html/_sources/glossary.txt b/phpMyAdmin/doc/html/_sources/glossary.txt new file mode 100644 index 0000000..d558b44 --- /dev/null +++ b/phpMyAdmin/doc/html/_sources/glossary.txt @@ -0,0 +1,406 @@ +.. _glossary: + +Glossary +======== + +From Wikipedia, the free encyclopedia + +.. glossary:: + + .htaccess + the default name of Apache's directory-level configuration file. + + .. seealso:: + + ACL + Access Contol List + + Blowfish + a keyed, symmetric block cipher, designed in 1993 by Bruce Schneier. + + .. seealso:: + + Browser + a software application that enables a user to display and interact with text, images, and other information typically located on a web page at a website on the World Wide Web. + + .. seealso:: + + bzip2 + a free software/open source data compression algorithm and program developed by Julian Seward. + + .. seealso:: + + CGI + Common Gateway Interface is an important World Wide Web technology that + enables a client web browser to request data from a program executed on + the Web server. + + .. seealso:: + + Changelog + a log or record of changes made to a project. + + .. seealso:: + + Client + a computer system that accesses a (remote) service on another computer by some kind of network. + + .. seealso:: + + column + a set of data values of a particular simple type, one for each row of the table. + + .. seealso:: + + Cookie + a packet of information sent by a server to a World Wide Web browser and then sent back by the browser each time it accesses that server. + + .. seealso:: + + CSV + Comma- separated values + + .. seealso:: + + DB + look at :term:`database` + + database + an organized collection of data. + + .. seealso:: + + Engine + look at :term:`storage engines` + + extension + a PHP module that extends PHP with additional functionality. + + .. seealso:: + + FAQ + Frequently Asked Questions is a list of commonly asked question and there + answers. + + .. seealso:: + + Field + one part of divided data/columns. + + .. seealso:: + + foreign key + a column or group of columns in a database row that point to a key column + or group of columns forming a key of another database row in some + (usually different) table. + + .. seealso:: + + FPDF + the free :term:`PDF` library + + .. seealso:: + + GD + Graphics Library by Thomas Boutell and others for dynamically manipulating images. + + .. seealso:: + + GD2 + look at :term:`gd` + + gzip + gzip is short for GNU zip, a GNU free software file compression program. + + .. seealso:: + + host + any machine connected to a computer network, a node that has a hostname. + + .. seealso:: + + hostname + the unique name by which a network attached device is known on a network. + + .. seealso:: + + HTTP + HyperText Transfer Protocol is the primary method used to transfer or + convey information on the World Wide Web. + + .. seealso:: + + https + a :term:`HTTP`-connection with additional security measures. + + .. seealso:: + + IEC + International Electrotechnical Commission + + IIS + Internet Information Services is a set of Internet-based services for + servers using Microsoft Windows. + + .. seealso:: + + Index + a feature that allows quick access to the rows in a table. + + .. seealso:: + + IP + Internet Protocol is a data-oriented protocol used by source and + destination hosts for communicating data across a packet-switched + internetwork. + + .. seealso:: + + IP Address + a unique number that devices use in order to identify and communicate with each other on a network utilizing the Internet Protocol standard. + + .. seealso:: + + IPv6 + IPv6 (Internet Protocol version 6) is the latest revision of the + Internet Protocol (:term:`IP`), designed to deal with the + long-anticipated problem of its precedessor IPv4 running out of addresses. + + .. seealso:: + + ISAPI + Internet Server Application Programming Interface is the API of Internet Information Services (IIS). + + .. seealso:: + + ISP + Internet service provider is a business or organization that offers users + access to the Internet and related services. + + .. seealso:: + + ISO + International Standards Organisation + + JPEG + a most commonly used standard method of lossy compression for photographic images. + + .. seealso:: + + JPG + look at :term:`jpeg` + + Key + look at :term:`index` + + LATEX + a document preparation system for the TEX typesetting program. + + .. seealso:: + + Mac + Apple Macintosh is line of personal computers is designed, developed, manufactured, and marketed by Apple Computer. + + .. seealso:: + + Mac OS X + the operating system which is included with all currently shipping Apple Macintosh computers in the consumer and professional markets. + + .. seealso:: + + MCrypt + a cryptographic library. + + .. seealso:: + + mcrypt + the MCrypt PHP extension. + + .. seealso:: + + MIME + Multipurpose Internet Mail Extensions is + an Internet Standard for the format of e-mail. + + .. seealso:: + + module + some sort of extension for the Apache Webserver. + + .. seealso:: + + MySQL + a multithreaded, multi-user, SQL (Structured Query Language) Database Management System (DBMS). + + .. seealso:: + + mysqli + the improved MySQL client PHP extension. + + .. seealso:: + + mysql + the MySQL client PHP extension. + + .. seealso:: + + OpenDocument + open standard for office documents. + + .. seealso:: + + OS X + look at :term:`Mac OS X`. + + .. seealso:: + + PDF + Portable Document Format is a file format developed by Adobe Systems for + representing two dimensional documents in a device independent and + resolution independent format. + + .. seealso:: + + PEAR + the PHP Extension and Application Repository. + + .. seealso:: + + PCRE + Perl Compatible Regular Expressions is the perl-compatible regular + expression functions for PHP + + .. seealso:: + + PHP + short for "PHP: Hypertext Preprocessor", is an open-source, reflective + programming language used mainly for developing server-side applications + and dynamic web content, and more recently, a broader range of software + applications. + + .. seealso:: + + port + a connection through which data is sent and received. + + .. seealso:: + + RFC + Request for Comments (RFC) documents are a series of memoranda + encompassing new research, innovations, and methodologies applicable to + Internet technologies. + + .. seealso:: + + RFC 1952 + GZIP file format specification version 4.3 + + .. seealso:: :rfc:`1952` + + Row (record, tuple) + represents a single, implicitly structured data item in a table. + + .. seealso:: + + Server + a computer system that provides services to other computing systems over a network. + + .. seealso:: + + Storage Engines + handlers for different table types + + .. seealso:: + + SOAP + Simple Object Access Protocol is a protocol specification for exchanging + structured information in the implementation of Web Services in computer + networks. + + .. seealso:: + + socket + a form of inter-process communication. + + .. seealso:: + + SSL + Secure Sockets Layer is a cryptographic protocol which provides secure + communication on the Internet. + + .. seealso:: + + Stored procedure + a subroutine available to applications accessing a relational database system + + .. seealso:: + + SQL + Structured Query Language + + .. seealso:: + + table + a set of data elements (cells) that is organized, defined and stored as + horizontal rows and vertical columns where each item can be uniquely + identified by a label or key or by it?s position in relation to other + items. + + .. seealso:: + + tar + a type of archive file format: the Tape ARchive format. + + .. seealso:: + + TCP + Transmission Control Protocol is one of the core protocols of the + Internet protocol suite. + + .. seealso:: + + TCPDF + Rewrite of :term:`UFPDF` with various improvements. + + .. seealso:: + + trigger + a procedural code that is automatically executed in response to certain events on a particular table or view in a database + + .. seealso:: + + UFPDF + Unicode/UTF-8 extension for :term:`FPDF` + + .. seealso:: + + URL + Uniform Resource Locator is a sequence of characters, conforming to a + standardized format, that is used for referring to resources, such as + documents and images on the Internet, by their location. + + .. seealso:: + + Webserver + A computer (program) that is responsible for accepting HTTP requests from clients and serving them Web pages. + + .. seealso:: + + XML + Extensible Markup Language is a W3C-recommended general- purpose markup + language for creating special-purpose markup languages, capable of + describing many different kinds of data. + + .. seealso:: + + ZIP + a popular data compression and archival format. + + .. seealso:: + + zlib + an open-source, cross- platform data compression library by Jean-loup Gailly and Mark Adler. + + .. seealso:: + + diff --git a/phpMyAdmin/doc/html/_sources/index.txt b/phpMyAdmin/doc/html/_sources/index.txt new file mode 100644 index 0000000..917ddf8 --- /dev/null +++ b/phpMyAdmin/doc/html/_sources/index.txt @@ -0,0 +1,32 @@ +.. phpMyAdmin documentation master file, created by + sphinx-quickstart on Wed Sep 26 14:04:48 2012. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to phpMyAdmin's documentation! +====================================== + +Contents: + +.. toctree:: + :maxdepth: 2 + + intro + require + setup + config + user + faq + developers + vendors + copyright + credits + glossary + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`search` +* :ref:`glossary` diff --git a/phpMyAdmin/doc/html/_sources/intro.txt b/phpMyAdmin/doc/html/_sources/intro.txt new file mode 100644 index 0000000..9576814 --- /dev/null +++ b/phpMyAdmin/doc/html/_sources/intro.txt @@ -0,0 +1,68 @@ +.. _intro: + +Introduction +============ + +phpMyAdmin can manage a whole MySQL server (needs a super-user) as +well as a single database. To accomplish the latter you'll need a +properly set up MySQL user who can read/write only the desired +database. It's up to you to look up the appropriate part in the MySQL +manual. + + +Supported features +------------------ + +Currently phpMyAdmin can: + +* browse and drop databases, tables, views, columns and indexes +* display multiple results sets through stored procedures or queries +* create, copy, drop, rename and alter databases, tables, columns and + indexes +* maintenance server, databases and tables, with proposals on server + configuration +* execute, edit and bookmark any :term:`SQL`-statement, even batch-queries +* load text files into tables +* create [#f1]_ and read dumps of tables +* export [#f1]_ data to various formats: :term:`CSV`, :term:`XML`, :term:`PDF`, + :term:`ISO`/:term:`IEC` 26300 - :term:`OpenDocument` Text and Spreadsheet, Microsoft + Word 2000, and LATEX formats +* import data and :term:`MySQL` structures from :term:`OpenDocument` spreadsheets, as + well as :term:`XML`, :term:`CSV`, and :term:`SQL` files +* administer multiple servers +* manage MySQL users and privileges +* check referential integrity in MyISAM tables +* using Query-by-example (QBE), create complex queries automatically + connecting required tables +* create :term:`PDF` graphics of your + database layout +* search globally in a database or a subset of it +* transform stored data into any format using a set of predefined + functions, like displaying BLOB-data as image or download-link +* track changes on databases, tables and views +* support InnoDB tables and foreign keys see :ref:`faq3_6` +* support mysqli, the improved MySQL extension see :ref:`faq1_17` +* create, edit, call, export and drop stored procedures and functions +* create, edit, export and drop events and triggers +* communicate in `62 different languages + `_ + + +A word about users +------------------ + +Many people have difficulty understanding the concept of user +management with regards to phpMyAdmin. When a user logs in to +phpMyAdmin, that username and password are passed directly to MySQL. +phpMyAdmin does no account management on its own (other than allowing +one to manipulate the MySQL user account information); all users must +be valid MySQL users. + +.. rubric:: Footnotes + +.. [#f1] + + phpMyAdmin can compress (:term:`Zip`, :term:`GZip` or :term:`RFC 1952` + formats) dumps and :term:`CSV` exports if you use PHP with + :term:`Zlib` support (``--with-zlib``). + Proper support may also need changes in :file:`php.ini`. diff --git a/phpMyAdmin/doc/html/_sources/other.txt b/phpMyAdmin/doc/html/_sources/other.txt new file mode 100644 index 0000000..aa95451 --- /dev/null +++ b/phpMyAdmin/doc/html/_sources/other.txt @@ -0,0 +1,18 @@ +Other sources of information +============================ + +Printed Book +------------ + +The definitive guide to using phpMyAdmin is the book Mastering phpMyAdmin for +Effective MySQL Management by Marc Delisle. You can get information on that +book and other officially endorsed `books at the phpMyAdmin site`_. + +.. _books at the phpMyAdmin site: http://www.phpmyadmin.net/home_page/docs.php?books + +Tutorials +--------- + +Third party tutorials and articles are listed on our `wiki page`_. + +.. _wiki page: http://wiki.phpmyadmin.net/pma/Articles diff --git a/phpMyAdmin/doc/html/_sources/privileges.txt b/phpMyAdmin/doc/html/_sources/privileges.txt new file mode 100644 index 0000000..0c12932 --- /dev/null +++ b/phpMyAdmin/doc/html/_sources/privileges.txt @@ -0,0 +1,50 @@ +User management +=============== + +User management is the process of controlling which users are allowed to +connect to the MySQL server and what permissions they have on each database. +phpMyAdmin does not handle user management, rather it passes the username and +password on to MySQL, which then determines whether a user is permitted to +perform a particular action. Within phpMyAdmin, administrators have full +control over creating users, viewing and editing privileges for existing users, +and removing users. + +Within phpMyAdmin, user management is controlled via the :guilabel:`Users` link +from the main page. Users can be created, edited, and removed. + +Creating a new user +------------------- + +To create a new user, click the :guilabel:`Add a new user` link near the bottom +of the :guilabel:`Users` page (you must be a "superuser", e.g., user "root"). +Use the textboxes and drop-downs to configure the user to your particular +needs. You can then select whether to create a database for that user and grant +specific global privileges. Once you've created the user (by clicking Go), you +can define that user's permissions on a specific database (don't grant global +privileges in that case). In general, users do not need any global privileges +(other than USAGE), only permissions for their specific database. + +Editing an existing user +------------------------ + +To edit an existing user, simply click the pencil icon to the right of that +user in the :guilabel:`Users` page. You can then edit their global- and +database-specific privileges, change their password, or even copy those +privileges to a new user. + +Deleting a user +--------------- + +From the :guilabel:`Users` page, check the checkbox for the user you wish to +remove, select whether or not to also remove any databases of the same name (if +they exist), and click Go. + +Assigning privileges to user for a specific database +---------------------------------------------------- + +Users are assigned to databases by editing the user record (from the +:guilabel:`Users` link on the home page) not from within the :guilabel:`Users` +link under the table. If you are creating a user specifically for a given table +you will have to create the user first (with no global privileges) and then go +back and edit that user to add the table and privileges for the individual +table. diff --git a/phpMyAdmin/doc/html/_sources/require.txt b/phpMyAdmin/doc/html/_sources/require.txt new file mode 100644 index 0000000..4582d72 --- /dev/null +++ b/phpMyAdmin/doc/html/_sources/require.txt @@ -0,0 +1,53 @@ +.. _require: + +Requirements +============ + +Web server +---------- + +Since, phpMyAdmin's interface is based entirely in your browser, you'll need a +web server (such as Apache, :term:`IIS`) to install phpMyAdmin's files into. + +PHP +--- + +* You need PHP 5.3.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. + +* You need GD2 support in PHP to display inline thumbnails of JPEGs + ("image/jpeg: inline") with their original aspect ratio. + +* When using the cookie authentication (the default), the `mcrypt + `_ extension is strongly suggested for most + users and is **required** for 64–bit machines. Not using mcrypt will + cause phpMyAdmin to load pages significantly slower. + +* To support upload progress bars, see :ref:`faq2_9`. + +* To support XML and Open Document Spreadsheet importing, you need the + `libxml `_ extension. + +* Performance suggestion: install the ``ctype`` extension. + +.. seealso:: :ref:`faq1_31`, :ref:`authentication_modes` + +Database +-------- + +phpMyAdmin supports MySQL-compatible databases. + +* MySQL 5.5 or newer +* MariaDB 5.5 or newer +* Drizzle + +.. seealso:: :ref:`faq1_17` + +Web browser +----------- + +To access phpMyAdmin you need a web browser with cookies and javascript +enabled. + diff --git a/phpMyAdmin/doc/html/_sources/setup.txt b/phpMyAdmin/doc/html/_sources/setup.txt new file mode 100644 index 0000000..783cffd --- /dev/null +++ b/phpMyAdmin/doc/html/_sources/setup.txt @@ -0,0 +1,493 @@ +.. _setup: + +Installation +============ + +phpMyAdmin does not apply any special security methods to the MySQL +database server. It is still the system administrator's job to grant +permissions on the MySQL databases properly. phpMyAdmin's :guilabel:`Users` +page can be used for this. + +.. warning:: + + :term:`Mac` users should note that if you are on a version before + :term:`Mac OS X`, StuffIt unstuffs with :term:`Mac` formats. So you'll have + to resave as in BBEdit to Unix style ALL phpMyAdmin scripts before + uploading them to your server, as PHP seems not to like :term:`Mac`-style + end of lines character ("``\r``"). + +Linux distributions ++++++++++++++++++++ + +phpMyAdmin is included in most Linux distributions. It is recommended to use +distribution packages when possible - they usually provide integration to your +distribution and you will automatically get security updates from your distribution. + + +Debian +------ + +Debian's package repositories include a phpMyAdmin package, but be aware that +the configuration file is maintained in ``/etc/phpmyadmin`` and may differ in +some ways from the official phpMyAdmin documentation. + +OpenSUSE +-------- + +OpenSUSE already comes with phpMyAdmin package, just install packages from +the `openSUSE Build Service `_. + +Ubuntu +------ + +Ubuntu ships phpMyAdmin package, however if you want to use recent version, you +can use packages from +`PPA for Michal ÄŒihaÅ™ `_. + +Gentoo +------ + +Gentoo ships the phpMyAdmin package, both in a near stock configuration as well +as in a ``webapp-config`` configuration. Use ``emerge dev-db/phpmyadmin`` to +install. + +Mandriva +-------- + +Mandriva ships the phpMyAdmin package in their ``contrib`` branch and can be +installed via the usual Control Center. + +Fedora +------ + +Fedora ships the phpMyAdmin package, but be aware that the configuration file +is maintained in ``/etc/phpMyAdmin/`` and may differ in some ways from the +official phpMyAdmin documentation. + +Red Hat Enterprise Linux +------------------------ + +Red Hat Enterprise Linux itself and thus derivatives like CentOS don't +ship phpMyAdmin, but the Fedora-driven repository +`Extra Packages for Enterprise Linux (EPEL) `_ +is doing so, if it's +`enabled `_. +But be aware that the configuration file is maintained in +``/etc/phpMyAdmin/`` and may differ in some ways from the +official phpMyAdmin documentation. + + +Installing on Windows ++++++++++++++++++++++ + +The easiest way to get phpMyAdmin on Windows is using third party products +which include phpMyAdmin together with a database and web server such as +`XAMPP `_. + +You can find more of such options at `Wikipedia `_. + + +.. _quick_install: + +Quick Install ++++++++++++++ + +#. Choose an appropriate distribution kit from the phpmyadmin.net + Downloads page. Some kits contain only the English messages, others + contain all languages. We'll assume you chose a kit whose name + looks like ``phpMyAdmin-x.x.x -all-languages.tar.gz``. +#. Untar or unzip the distribution (be sure to unzip the subdirectories): + ``tar -xzvf phpMyAdmin_x.x.x-all-languages.tar.gz`` in your + webserver's document root. If you don't have direct access to your + document root, put the files in a directory on your local machine, + and, after step 4, transfer the directory on your web server using, + for example, ftp. +#. Ensure that all the scripts have the appropriate owner (if PHP is + running in safe mode, having some scripts with an owner different from + the owner of other scripts will be a problem). See :ref:`faq4_2` and + :ref:`faq1_26` for suggestions. +#. Now you must configure your installation. There are two methods that + can be used. Traditionally, users have hand-edited a copy of + :file:`config.inc.php`, but now a wizard-style setup script is provided + for those who prefer a graphical installation. Creating a + :file:`config.inc.php` is still a quick way to get started and needed for + some advanced features. + + +Manually creating the file +-------------------------- + +To manually create the file, simply use your text editor to create the +file :file:`config.inc.php` (you can copy :file:`config.sample.inc.php` to get +minimal configuration file) in the main (top-level) phpMyAdmin +directory (the one that contains :file:`index.php`). phpMyAdmin first +loads :file:`libraries/config.default.php` and then overrides those values +with anything found in :file:`config.inc.php`. If the default value is +okay for a particular setting, there is no need to include it in +:file:`config.inc.php`. You'll need a few directives to get going, a +simple configuration may look like this: + +.. code-block:: xml+php + + + + +Or, if you prefer to not be prompted every time you log in: + +.. code-block:: xml+php + + + + +For a full explanation of possible configuration values, see the +:ref:`config` of this document. + +.. index:: Setup script + +.. _setup_script: + +Using Setup script +------------------ + +Instead of manually editing :file:`config.inc.php`, you can use the `Setup +Script `_. First you must manually create a folder ``config`` +in the phpMyAdmin directory. This is a security measure. On a +Linux/Unix system you can use the following commands: + +.. code-block:: sh + + + cd phpMyAdmin + mkdir config # create directory for saving + chmod o+rw config # give it world writable permissions + +And to edit an existing configuration, copy it over first: + +.. code-block:: sh + + + cp config.inc.php config/ # copy current configuration for editing + chmod o+w config/config.inc.php # give it world writable permissions + +On other platforms, simply create the folder and ensure that your web +server has read and write access to it. :ref:`faq1_26` can help with +this. + +Next, open ``setup/`` in your browser. If you have an existing configuration, +use the ``Load`` button to bring its content inside the setup panel. +Note that **changes are not saved to disk until explicitly choose ``Save``** +from the *Configuration* area of the screen. Normally the script saves the new +:file:`config.inc.php` to the ``config/`` directory, but if the webserver does +not have the proper permissions you may see the error "Cannot load or +save configuration." Ensure that the ``config/`` directory exists and +has the proper permissions - or use the ``Download`` link to save the +config file locally and upload it (via FTP or some similar means) to the +proper location. + +Once the file has been saved, it must be moved out of the ``config/`` +directory and the permissions must be reset, again as a security +measure: + +.. code-block:: sh + + + mv config/config.inc.php . # move file to current directory + chmod o-rw config.inc.php # remove world read and write permissions + rm -rf config # remove not needed directory + +Now the file is ready to be used. You can choose to review or edit the +file with your favorite editor, if you prefer to set some advanced +options which the setup script does not provide. + +#. If you are using the ``auth_type`` "config", it is suggested that you + protect the phpMyAdmin installation directory because using config + does not require a user to enter a password to access the phpMyAdmin + installation. Use of an alternate authentication method is + recommended, for example with HTTP–AUTH in a :term:`.htaccess` file or switch to using + ``auth_type`` cookie or http. See the :ref:`faqmultiuser` + for additional information, especially :ref:`faq4_4`. +#. Open the `main phpMyAdmin directory `_ in your browser. + phpMyAdmin should now display a welcome screen and your databases, or + a login dialog if using :term:`HTTP` or + cookie authentication mode. +#. You should deny access to the ``./libraries`` and ``./setup/lib`` + subfolders in your webserver configuration. For Apache you can use + supplied :term:`.htaccess` file in that folder, for other webservers, you should + configure this yourself. Such configuration prevents from possible + path exposure and cross side scripting vulnerabilities that might + happen to be found in that code. +#. It is generally good idea to protect public phpMyAdmin installation + against access by robots as they usually can not do anything good + there. You can do this using ``robots.txt`` file in root of your + webserver or limit access by web server configuration, see + :ref:`faq1_42`. + +.. index:: + single: Configuration storage + single: phpMyAdmin configuration storage + single: pmadb + +.. _linked-tables: + +phpMyAdmin configuration storage +++++++++++++++++++++++++++++++++ + +For a whole set of new features (bookmarks, comments, :term:`SQL`-history, +tracking mechanism, :term:`PDF`-generation, column contents transformation, +etc.) you need to create a set of special tables. Those tables can be located +in your own database, or in a central database for a multi-user installation +(this database would then be accessed by the controluser, so no other user +should have rights to it). + +Please look at your ``./examples/`` directory, where you should find a +file called *create\_tables.sql*. (If you are using a Windows server, +pay special attention to :ref:`faq1_23`). + +If you already had this infrastructure and upgraded to MySQL 4.1.2 or +newer, please use :file:`examples/upgrade_tables_mysql_4_1_2+.sql` +and then create new tables by importing +:file:`examples/create_tables.sql`. + +You can use your phpMyAdmin to create the tables for you. Please be +aware that you may need special (administrator) privileges to create +the database and tables, and that the script may need some tuning, +depending on the database name. + +After having imported the :file:`examples/create_tables.sql` file, you +should specify the table names in your :file:`config.inc.php` file. The +directives used for that can be found in the :ref:`config`. You will also need to +have a controluser with the proper rights to those tables (see section +:ref:`authentication_modes` below). + +.. _upgrading: + +Upgrading from an older version ++++++++++++++++++++++++++++++++ + +Simply copy :file:`config.inc.php` from your previous installation into +the newly unpacked one. Configuration files from old versions may +require some tweaking as some options have been changed or removed. +For compatibility with PHP 6, remove a +``set_magic_quotes_runtime(0);`` statement that you might find near +the end of your configuration file. + +You should **not** copy :file:`libraries/config.default.php` over +:file:`config.inc.php` because the default configuration file is version- +specific. + +If you have upgraded your MySQL server from a version previous to 4.1.2 to +version 5.x or newer and if you use the phpMyAdmin configuration storage, you +should run the :term:`SQL` script found in +:file:`examples/upgrade_tables_mysql_4_1_2+.sql`. + +.. index:: Authentication mode + +.. _authentication_modes: + +Using authentication modes +++++++++++++++++++++++++++ + +:term:`HTTP` and cookie authentication modes are recommended in a **multi-user +environment** where you want to give users access to their own database and +don't want them to play around with others. Nevertheless be aware that MS +Internet Explorer seems to be really buggy about cookies, at least till version +6. Even in a **single-user environment**, you might prefer to use :term:`HTTP` +or cookie mode so that your user/password pair are not in clear in the +configuration file. + +:term:`HTTP` and cookie authentication +modes are more secure: the MySQL login information does not need to be +set in the phpMyAdmin configuration file (except possibly for the +:config:option:`$cfg['Servers'][$i]['controluser']`). +However, keep in mind that the password travels in plain text, unless +you are using the HTTPS protocol. In cookie mode, the password is +stored, encrypted with the blowfish algorithm, in a temporary cookie. + +.. note: + + This section is only applicable if your MySQL server is running + with ``--skip-show-database``. + +For ':term:`HTTP`' and 'cookie' modes, phpMyAdmin needs a controluser that has +**only** the ``SELECT`` privilege on the *`mysql`.`user` (all columns except +`Password`)*, *`mysql`.`db` (all columns)*, *`mysql`.`host` (all columns)* and +*`mysql`.`tables\_priv` (all columns except `Grantor` and `Timestamp`)* tables. +You must specify the details for the controluser in the :file:`config.inc.php` +file under the :config:option:`$cfg['Servers'][$i]['controluser']` and +:config:option:`$cfg['Servers'][$i]['controlpass']` settings. The following +example assumes you want to use ``pma`` as the controluser and ``pmapass`` as +the controlpass, but **this is only an example: use something else in your +file!** Input these statements from the phpMyAdmin :term:`SQL` Query window or +mysql command–line client. Of course you have to replace ``localhost`` with the +webserver's host if it's not the same as the MySQL server's one. + +.. code-block:: mysql + + GRANT USAGE ON mysql.* TO 'pma'@'localhost' IDENTIFIED BY 'pmapass'; + GRANT SELECT ( + Host, User, Select_priv, Insert_priv, Update_priv, Delete_priv, + Create_priv, Drop_priv, Reload_priv, Shutdown_priv, Process_priv, + File_priv, Grant_priv, References_priv, Index_priv, Alter_priv, + Show_db_priv, Super_priv, Create_tmp_table_priv, Lock_tables_priv, + Execute_priv, Repl_slave_priv, Repl_client_priv + ) ON mysql.user TO 'pma'@'localhost'; + GRANT SELECT ON mysql.db TO 'pma'@'localhost'; + GRANT SELECT ON mysql.host TO 'pma'@'localhost'; + GRANT SELECT (Host, Db, User, Table_name, Table_priv, Column_priv) + ON mysql.tables_priv TO 'pma'@'localhost'; + +If you want to use the many new relation and bookmark features: + +.. code-block:: mysql + + GRANT SELECT, INSERT, UPDATE, DELETE ON .* TO 'pma'@'localhost'; + +(this of course requires that your :ref:`linked-tables` be set up). + +Then each of the *true* users should be granted a set of privileges +on a set of particular databases. Normally you shouldn't give global +privileges to an ordinary user, unless you understand the impact of those +privileges (for example, you are creating a superuser). +For example, to grant the user *real_user* with all privileges on +the database *user_base*: + +.. code-block:: mysql + + GRANT ALL PRIVILEGES ON user_base.* TO 'real_user'@localhost IDENTIFIED BY 'real_password'; + + +What the user may now do is controlled entirely by the MySQL user management +system. With HTTP or cookie authentication mode, you don't need to fill the +user/password fields inside the :config:option:`$cfg['Servers']`. + +.. index:: pair: HTTP; Authentication mode + +HTTP authentication mode +------------------------ + +* Uses :term:`HTTP` Basic authentication + method and allows you to log in as any valid MySQL user. +* Is supported with most PHP configurations. For :term:`IIS` (:term:`ISAPI`) + support using :term:`CGI` PHP see :ref:`faq1_32`, for using with Apache + :term:`CGI` see :ref:`faq1_35`. +* See also :ref:`faq4_4` about not using the :term:`.htaccess` mechanism along with + ':term:`HTTP`' authentication mode. + +.. index:: pair: Cookie; Authentication mode + +.. _cookie: + +Cookie authentication mode +-------------------------- + +* You can use this method as a replacement for the :term:`HTTP` authentication + (for example, if you're running :term:`IIS`). +* Obviously, the user must enable cookies in the browser, but this is + now a requirement for all authentication modes. +* With this mode, the user can truly log out of phpMyAdmin and log in + back with the same username. +* If you want to log in to arbitrary server see :config:option:`$cfg['AllowArbitraryServer']` directive. +* As mentioned in the :ref:`require` section, having the ``mcrypt`` extension will + speed up access considerably, but is not required. + +.. index:: pair: Signon; Authentication mode + +Signon authentication mode +-------------------------- + +* This mode is a convenient way of using credentials from another + application to authenticate to phpMyAdmin. +* The other application has to store login information into session + data. + +.. seealso:: + :config:option:`$cfg['Servers'][$i]['auth_type']`, + :config:option:`$cfg['Servers'][$i]['SignonSession']`, + :config:option:`$cfg['Servers'][$i]['SignonScript']`, + :config:option:`$cfg['Servers'][$i]['SignonURL']` + + +.. index:: pair: Config; Authentication mode + +Config authentication mode +-------------------------- + +* This mode is the less secure one because it requires you to fill the + :config:option:`$cfg['Servers'][$i]['user']` and + :config:option:`$cfg['Servers'][$i]['password']` + fields (and as a result, anyone who can read your :file:`config.inc.php` + can discover your username and password). But you don't need to setup + a "controluser" here: using the :config:option:`$cfg['Servers'][$i]['only_db']` might be enough. +* In the :ref:`faqmultiuser` section, there is an entry explaining how + to protect your configuration file. +* For additional security in this mode, you may wish to consider the + Host authentication :config:option:`$cfg['Servers'][$i]['AllowDeny']['order']` + and :config:option:`$cfg['Servers'][$i]['AllowDeny']['rules']` configuration directives. +* Unlike cookie and http, does not require a user to log in when first + loading the phpMyAdmin site. This is by design but could allow any + user to access your installation. Use of some restriction method is + suggested, perhaps a :term:`.htaccess` file with the HTTP-AUTH directive or disallowing + incoming HTTP requests at one’s router or firewall will suffice (both + of which are beyond the scope of this manual but easily searchable + with Google). + +.. index:: pair: Swekey; Authentication mode + +.. _swekey: + +Swekey authentication mode +-------------------------- + +The Swekey is a low cost authentication USB key that can be used in +web applications. When Swekey authentication is activated, phpMyAdmin +requires the users's Swekey to be plugged before entering the login +page (currently supported for cookie authentication mode only). Swekey +Authentication is disabled by default. To enable it, add the following +line to :file:`config.inc.php`: + +.. code-block:: php + + $cfg['Servers'][$i]['auth_swekey_config'] = '/etc/swekey.conf'; + +You then have to create the ``swekey.conf`` file that will associate +each user with their Swekey Id. It is important to place this file +outside of your web server's document root (in the example, it is +located in ``/etc``). A self documented sample file is provided in the +``examples`` directory. Feel free to use it with your own users' +information. If you want to purchase a Swekey please visit +`http://phpmyadmin.net/auth\_key `_ +since this link provides funding for phpMyAdmin. + +.. seealso:: :config:option:`$cfg['Servers'][$i]['auth_swekey_config']` + + +Securing your phpMyAdmin installation ++++++++++++++++++++++++++++++++++++++ + +The phpMyAdmin team tries hardly to make the application secure, however there +are always ways to make your installation more secure: + +* remove ``setup`` directory from phpMyAdmin, you will probably not + use it after initial setup +* properly choose authentication method - :ref:`cookie` + is probably the best choice for shared hosting +* in case you don't want all MySQL users to be able to access + phpMyAdmin, you can use :config:option:`$cfg['Servers'][$i]['AllowDeny']['rules']` to limit them +* consider hiding phpMyAdmin behind authentication proxy, so that + MySQL credentials are not all users need to login +* if you are afraid of automated attacks, enabling Captcha by + :config:option:`$cfg['CaptchaLoginPublicKey']` and + :config:option:`$cfg['CaptchaLoginPrivateKey']` might be an option. diff --git a/phpMyAdmin/doc/html/_sources/transformations.txt b/phpMyAdmin/doc/html/_sources/transformations.txt new file mode 100644 index 0000000..4c3ce46 --- /dev/null +++ b/phpMyAdmin/doc/html/_sources/transformations.txt @@ -0,0 +1,138 @@ +.. _transformations: + +Transformations +=============== + +.. _transformationsintro: + +Introduction +++++++++++++ + +To enable transformations, you have to setup the ``column_info`` +table and the proper directives. Please see the :ref:`config` on how to do so. + +You can apply different transformations to the contents of each +column. The transformation will take the content of each column and +transform it with certain rules defined in the selected +transformation. + +Say you have a column 'filename' which contains a filename. Normally +you would see in phpMyAdmin only this filename. Using transformations +you can transform that filename into a HTML link, so you can click +inside of the phpMyAdmin structure on the column's link and will see +the file displayed in a new browser window. Using transformation +options you can also specify strings to append/prepend to a string or +the format you want the output stored in. + +For a general overview of all available transformations and their +options, you can consult your *//transformation\_overview.php* installation. + +For a tutorial on how to effectively use transformations, see our +`Link section `_ on the +official phpMyAdmin homepage. + +.. _transformationshowto: + +Usage ++++++ + +Go to your *tbl\_structure.php* page (i.e. reached through clicking on +the 'Structure' link for a table). There click on "Change" (or change +icon) and there you will see three new fields at the end of the line. +They are called 'MIME-type', 'Browser transformation' and +'Transformation options'. + +* The field 'MIME-type' is a drop-down field. Select the MIME-type that + corresponds to the column's contents. Please note that transformations + are inactive as long as no MIME-type is selected. +* The field 'Browser transformation' is a drop-down field. You can + choose from a hopefully growing amount of pre-defined transformations. + See below for information on how to build your own transformation. + There are global transformations and mimetype-bound transformations. + Global transformations can be used for any mimetype. They will take + the mimetype, if necessary, into regard. Mimetype-bound + transformations usually only operate on a certain mimetype. There are + transformations which operate on the main mimetype (like 'image'), + which will most likely take the subtype into regard, and those who + only operate on a specific subtype (like 'image/jpeg'). You can use + transformations on mimetypes for which the function was not defined + for. There is no security check for you selected the right + transformation, so take care of what the output will be like. +* The field 'Transformation options' is a free-type textfield. You have + to enter transform-function specific options here. Usually the + transforms can operate with default options, but it is generally a + good idea to look up the overview to see which options are necessary. + Much like the ENUM/SET-Fields, you have to split up several options + using the format 'a','b','c',...(NOTE THE MISSING BLANKS). This is + because internally the options will be parsed as an array, leaving the + first value the first element in the array, and so forth. If you want + to specify a MIME character set you can define it in the + transformation\_options. You have to put that outside of the pre- + defined options of the specific mime-transform, as the last value of + the set. Use the format "'; charset=XXX'". If you use a transform, for + which you can specify 2 options and you want to append a character + set, enter "'first parameter','second parameter','charset=us-ascii'". + You can, however use the defaults for the parameters: "'','','charset + =us-ascii'". + +.. _transformationsfiles: + +File structure +++++++++++++++ + +All specific transformations for mimetypes are defined through class +files in the directory 'libraries/plugins/transformations/'. Each of +them extends a certain transformation abstract class declared in +libraries/plugins/transformations/abstract. + +They are stored in files to ease up customization and easy adding of +new transformations. + +Because the user cannot enter own mimetypes, it is kept sure that +transformations always work. It makes no sense to apply a +transformation to a mimetype the transform-function doesn't know to +handle. + +There is a file called '*transformations.lib.php*' that provides some +basic functions which can be included by any other transform function. + +The file name convention is ``[Mimetype]_[Subtype]_[Transformation +Name].class.php``, while the abtract class that it extends has the +name ``[Transformation Name]TransformationsPlugin``. All of the +methods that have to be implemented by a transformations plug-in are: + +#. getMIMEType() and getMIMESubtype() in the main class; +#. getName(), getInfo() and applyTransformation() in the abstract class + it extends. + +The getMIMEType(), getMIMESubtype() and getName() methods return the +name of the MIME type, MIME Subtype and transformation accordingly. +getInfo() returns the transformation's description and possible +options it may receive and applyTransformation() is the method that +does the actual work of the transformation plug-in. + +Please see the libraries/plugins/transformations/TEMPLATE and +libraries/plugins/transformations/TEMPLATE\_ABSTRACT files for adding +your own transformation plug-in. You can also generate a new +transformation plug-in (with or without the abstract transformation +class), by using +:file:`libraries/plugins/transformations/generator_plugin.sh` or +:file:`libraries/plugins/transformations/generator_main_class.sh`. + +The applyTransformation() method always gets passed three variables: + +#. **$buffer** - Contains the text inside of the column. This is the + text, you want to transform. +#. **$options** - Contains any user-passed options to a transform + function as an array. +#. **$meta** - Contains an object with information about your column. The + data is drawn from the output of the `mysql\_fetch\_field() + `_ function. This means, all + object properties described on the `manual page + `_ are available in this + variable and can be used to transform a column accordingly to + unsigned/zerofill/not\_null/... properties. The $meta->mimetype + variable contains the original MIME-type of the column (i.e. + 'text/plain', 'image/jpeg' etc.) + diff --git a/phpMyAdmin/doc/html/_sources/user.txt b/phpMyAdmin/doc/html/_sources/user.txt new file mode 100644 index 0000000..ceaf723 --- /dev/null +++ b/phpMyAdmin/doc/html/_sources/user.txt @@ -0,0 +1,9 @@ +User Guide +========== + +.. toctree:: + :maxdepth: 2 + + transformations + privileges + other diff --git a/phpMyAdmin/doc/html/_sources/vendors.txt b/phpMyAdmin/doc/html/_sources/vendors.txt new file mode 100644 index 0000000..13d7e55 --- /dev/null +++ b/phpMyAdmin/doc/html/_sources/vendors.txt @@ -0,0 +1,34 @@ +Distributing and packaging phpMyAdmin +===================================== + +This document is intended to give advices to people who want to +redistribute phpMyAdmin inside other software package such as Linux +distribution or some all in one package including web server and MySQL +server. + +Generally you can customize some basic aspects (paths to some files and +behavior) in :file:`libraries/vendor_config.php`. + +For example if you want setup script to generate config file in var, change +``SETUP_CONFIG_FILE`` to :file:`/var/lib/phpmyadmin/config.inc.php` and you +will also probably want to skip directory writable check, so set +``SETUP_DIR_WRITABLE`` to false. + +External libraries +------------------ + +phpMyAdmin includes several external libraries, you might want to +replace them with system ones if they are available, but please note +that you should test whether version you provide is compatible with the +one we ship. + +Currently known list of external libraries: + +js/jquery + jQuery js framework and various jQuery based libraries. + +libraries/php-gettext + php-gettext library +libraries/tcpdf + tcpdf library, stripped down of not needed files + diff --git a/phpMyAdmin/doc/html/_static/ajax-loader.gif b/phpMyAdmin/doc/html/_static/ajax-loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..61faf8cab23993bd3e1560bff0668bd628642330 GIT binary patch literal 673 zcmZ?wbhEHb6krfw_{6~Q|Nno%(3)e{?)x>&1u}A`t?OF7Z|1gRivOgXi&7IyQd1Pl zGfOfQ60;I3a`F>X^fL3(@);C=vM_KlFfb_o=k{|A33hf2a5d61U}gjg=>Rd%XaNQW zW@Cw{|b%Y*pl8F?4B9 zlo4Fz*0kZGJabY|>}Okf0}CCg{u4`zEPY^pV?j2@h+|igy0+Kz6p;@SpM4s6)XEMg z#3Y4GX>Hjlml5ftdH$4x0JGdn8~MX(U~_^d!Hi)=HU{V%g+mi8#UGbE-*ao8f#h+S z2a0-5+vc7MU$e-NhmBjLIC1v|)9+Im8x1yacJ7{^tLX(ZhYi^rpmXm0`@ku9b53aN zEXH@Y3JaztblgpxbJt{AtE1ad1Ca>{v$rwwvK(>{m~Gf_=-Ro7Fk{#;i~+{{>QtvI yb2P8Zac~?~=sRA>$6{!(^3;ZP0TPFR(G_-UDU(8Jl0?(IXu$~#4A!880|o%~Al1tN literal 0 HcmV?d00001 diff --git a/phpMyAdmin/doc/html/_static/basic.css b/phpMyAdmin/doc/html/_static/basic.css new file mode 100644 index 0000000..43e8baf --- /dev/null +++ b/phpMyAdmin/doc/html/_static/basic.css @@ -0,0 +1,540 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox input[type="text"] { + width: 170px; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + width: 30px; +} + +img { + border: 0; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable dl, table.indextable dd { + margin-top: 0; + margin-bottom: 0; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- general body styles --------------------------------------------------- */ + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.field-list ul { + padding-left: 1em; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.field-list td, table.field-list th { + border: 0 !important; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +dl { + margin-bottom: 15px; +} + +dd p { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, .highlighted { + background-color: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.refcount { + color: #060; +} + +.optional { + font-size: 1.3em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +tt.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +tt.descclassname { + background-color: transparent; +} + +tt.xref, a tt { + background-color: transparent; + font-weight: bold; +} + +h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/phpMyAdmin/doc/html/_static/comment-bright.png b/phpMyAdmin/doc/html/_static/comment-bright.png new file mode 100644 index 0000000000000000000000000000000000000000..551517b8c83b76f734ff791f847829a760ad1903 GIT binary patch literal 3500 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 A2LJ#7 literal 0 HcmV?d00001 diff --git a/phpMyAdmin/doc/html/_static/comment.png b/phpMyAdmin/doc/html/_static/comment.png new file mode 100644 index 0000000000000000000000000000000000000000..92feb52b8824c6b0f59b658b1196c61de9162a95 GIT binary patch literal 3445 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 Xn!ZpXD%P(H00000NkvXXu0mjf= 0 && !jQuery(node.parentNode).hasClass(className)) { + var span = document.createElement("span"); + span.className = className; + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this); + }); + } + } + return this.each(function() { + highlight(this); + }); +}; + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated == 'undefined') + return string; + return (typeof translated == 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated == 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('

') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) == 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this == '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); diff --git a/phpMyAdmin/doc/html/_static/down-pressed.png b/phpMyAdmin/doc/html/_static/down-pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..6f7ad782782e4f8e39b0c6e15c7344700cdd2527 GIT binary patch literal 368 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6U4S$Y z{B+)352QE?JR*yM+OLB!qm#z$3ZNi+iKnkC`z>}Z23@f-Ava~9&<9T!#}JFtXD=!G zGdl{fK6ro2OGiOl+hKvH6i=D3%%Y^j`yIkRn!8O>@bG)IQR0{Kf+mxNd=_WScA8u_ z3;8(7x2){m9`nt+U(Nab&1G)!{`SPVpDX$w8McLTzAJ39wprG3p4XLq$06M`%}2Yk zRPPsbES*dnYm1wkGL;iioAUB*Or2kz6(-M_r_#Me-`{mj$Z%( literal 0 HcmV?d00001 diff --git a/phpMyAdmin/doc/html/_static/down.png b/phpMyAdmin/doc/html/_static/down.png new file mode 100644 index 0000000000000000000000000000000000000000..3003a88770de3977d47a2ba69893436a2860f9e7 GIT binary patch literal 363 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6U4S$Y z{B+)352QE?JR*yM+OLB!qm#z$3ZNi+iKnkC`z>}xaV3tUZ$qnrLa#kt978NlpS`ru z&)HFc^}^>{UOEce+71h5nn>6&w6A!ieNbu1wh)UGh{8~et^#oZ1# z>T7oM=FZ~xXWnTo{qnXm$ZLOlqGswI_m2{XwVK)IJmBjW{J3-B3x@C=M{ShWt#fYS9M?R;8K$~YwlIqwf>VA7q=YKcwf2DS4Zj5inDKXXB1zl=(YO3ST6~rDq)&z z*o>z)=hxrfG-cDBW0G$!?6{M<$@{_4{m1o%Ub!naEtn|@^frU1tDnm{r-UW|!^@B8 literal 0 HcmV?d00001 diff --git a/phpMyAdmin/doc/html/_static/file.png b/phpMyAdmin/doc/html/_static/file.png new file mode 100644 index 0000000000000000000000000000000000000000..d18082e397e7e54f20721af768c4c2983258f1b4 GIT binary patch literal 392 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP$HyOL$D9)yc9|lc|nKf<9@eUiWd>3GuTC!a5vdfWYEazjncPj5ZQX%+1 zt8B*4=d)!cdDz4wr^#OMYfqGz$1LDFF>|#>*O?AGil(WEs?wLLy{Gj2J_@opDm%`dlax3yA*@*N$G&*ukFv>P8+2CBWO(qz zD0k1@kN>hhb1_6`&wrCswzINE(evt-5C1B^STi2@PmdKI;Vst0PQB6!2kdN literal 0 HcmV?d00001 diff --git a/phpMyAdmin/doc/html/_static/jquery.js b/phpMyAdmin/doc/html/_static/jquery.js new file mode 100644 index 0000000..96d660c --- /dev/null +++ b/phpMyAdmin/doc/html/_static/jquery.js @@ -0,0 +1,9404 @@ +/*! + * jQuery JavaScript Library v1.7.2 + * http://jquery.com/ + * + * Copyright 2011, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Thu Nov 15 18:28:24 BRST 2012 + */ +(function( window, undefined ) { + +// Use the correct document accordingly with window argument (sandbox) +var document = window.document, + navigator = window.navigator, + location = window.location; +var jQuery = (function() { + +// Define a local copy of jQuery +var jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context, rootjQuery ); + }, + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$, + + // A central reference to the root jQuery(document) + rootjQuery, + + // A simple way to check for HTML strings or ID strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, + + // Check if a string has a non-whitespace character in it + rnotwhite = /\S/, + + // Used for trimming whitespace + trimLeft = /^\s+/, + trimRight = /\s+$/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, + rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + + // Useragent RegExp + rwebkit = /(webkit)[ \/]([\w.]+)/, + ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, + rmsie = /(msie) ([\w.]+)/, + rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, + + // Matches dashed string for camelizing + rdashAlpha = /-([a-z]|[0-9])/ig, + rmsPrefix = /^-ms-/, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return ( letter + "" ).toUpperCase(); + }, + + // Keep a UserAgent string for use with jQuery.browser + userAgent = navigator.userAgent, + + // For matching the engine and version of the browser + browserMatch, + + // The deferred used on DOM ready + readyList, + + // The ready event handler + DOMContentLoaded, + + // Save a reference to some core methods + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty, + push = Array.prototype.push, + slice = Array.prototype.slice, + trim = String.prototype.trim, + indexOf = Array.prototype.indexOf, + + // [[Class]] -> type pairs + class2type = {}; + +jQuery.fn = jQuery.prototype = { + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem, ret, doc; + + // Handle $(""), $(null), or $(undefined) + if ( !selector ) { + return this; + } + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + } + + // The body element only exists once, optimize finding it + if ( selector === "body" && !context && document.body ) { + this.context = document; + this[0] = document.body; + this.selector = selector; + this.length = 1; + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + // Are we dealing with HTML string or an ID? + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = quickExpr.exec( selector ); + } + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + doc = ( context ? context.ownerDocument || context : document ); + + // If a single string is passed in and it's a single tag + // just do a createElement and skip the rest + ret = rsingleTag.exec( selector ); + + if ( ret ) { + if ( jQuery.isPlainObject( context ) ) { + selector = [ document.createElement( ret[1] ) ]; + jQuery.fn.attr.call( selector, context, true ); + + } else { + selector = [ doc.createElement( ret[1] ) ]; + } + + } else { + ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); + selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes; + } + + return jQuery.merge( this, selector ); + + // HANDLE: $("#id") + } else { + elem = document.getElementById( match[2] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || rootjQuery ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.7.2", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return slice.call( this, 0 ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == null ? + + // Return a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + // Build a new jQuery matched element set + var ret = this.constructor(); + + if ( jQuery.isArray( elems ) ) { + push.apply( ret, elems ); + + } else { + jQuery.merge( ret, elems ); + } + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) { + ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; + } else if ( name ) { + ret.selector = this.selector + "." + name + "(" + selector + ")"; + } + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + // Attach the listeners + jQuery.bindReady(); + + // Add the callback + readyList.add( fn ); + + return this; + }, + + eq: function( i ) { + i = +i; + return i === -1 ? + this.slice( i ) : + this.slice( i, i + 1 ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ), + "slice", slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + noConflict: function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + // Either a released hold or an DOMready/load event and not yet ready + if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready, 1 ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.fireWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.trigger ) { + jQuery( document ).trigger( "ready" ).off( "ready" ); + } + } + }, + + bindReady: function() { + if ( readyList ) { + return; + } + + readyList = jQuery.Callbacks( "once memory" ); + + // Catch cases where $(document).ready() is called after the + // browser event has already occurred. + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + return setTimeout( jQuery.ready, 1 ); + } + + // Mozilla, Opera and webkit nightlies currently support this event + if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", jQuery.ready, false ); + + // If IE event model is used + } else if ( document.attachEvent ) { + // ensure firing before onload, + // maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", DOMContentLoaded ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", jQuery.ready ); + + // If IE and not a frame + // continually check to see if the document is ready + var toplevel = false; + + try { + toplevel = window.frameElement == null; + } catch(e) {} + + if ( document.documentElement.doScroll && toplevel ) { + doScrollCheck(); + } + } + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type(obj) === "array"; + }, + + isWindow: function( obj ) { + return obj != null && obj == obj.window; + }, + + isNumeric: function( obj ) { + return !isNaN( parseFloat(obj) ) && isFinite( obj ); + }, + + type: function( obj ) { + return obj == null ? + String( obj ) : + class2type[ toString.call(obj) ] || "object"; + }, + + isPlainObject: function( obj ) { + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + try { + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call(obj, "constructor") && + !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + } catch ( e ) { + // IE8,9 Will throw exceptions on certain host objects #9897 + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + for ( var name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw new Error( msg ); + }, + + parseJSON: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( data ); + } + + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { + + return ( new Function( "return " + data ) )(); + + } + jQuery.error( "Invalid JSON: " + data ); + }, + + // Cross-browser xml parsing + parseXML: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + var xml, tmp; + try { + if ( window.DOMParser ) { // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString( data , "text/xml" ); + } else { // IE + xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + } catch( e ) { + xml = undefined; + } + if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; + }, + + noop: function() {}, + + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && rnotwhite.test( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); + }, + + // args is for internal usage only + each: function( object, callback, args ) { + var name, i = 0, + length = object.length, + isObj = length === undefined || jQuery.isFunction( object ); + + if ( args ) { + if ( isObj ) { + for ( name in object ) { + if ( callback.apply( object[ name ], args ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.apply( object[ i++ ], args ) === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isObj ) { + for ( name in object ) { + if ( callback.call( object[ name ], name, object[ name ] ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { + break; + } + } + } + } + + return object; + }, + + // Use native String.trim function wherever possible + trim: trim ? + function( text ) { + return text == null ? + "" : + trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); + }, + + // results is for internal usage only + makeArray: function( array, results ) { + var ret = results || []; + + if ( array != null ) { + // The window, strings (and functions) also have 'length' + // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 + var type = jQuery.type( array ); + + if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { + push.call( ret, array ); + } else { + jQuery.merge( ret, array ); + } + } + + return ret; + }, + + inArray: function( elem, array, i ) { + var len; + + if ( array ) { + if ( indexOf ) { + return indexOf.call( array, elem, i ); + } + + len = array.length; + i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; + + for ( ; i < len; i++ ) { + // Skip accessing in sparse arrays + if ( i in array && array[ i ] === elem ) { + return i; + } + } + } + + return -1; + }, + + merge: function( first, second ) { + var i = first.length, + j = 0; + + if ( typeof second.length === "number" ) { + for ( var l = second.length; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var ret = [], retVal; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( var i = 0, length = elems.length; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, key, ret = [], + i = 0, + length = elems.length, + // jquery objects are treated as arrays + isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; + + // Go through the array, translating each of the items to their + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Go through every key on the object, + } else { + for ( key in elems ) { + value = callback( elems[ key ], key, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + } + + // Flatten any nested arrays + return ret.concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + if ( typeof context === "string" ) { + var tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + var args = slice.call( arguments, 2 ), + proxy = function() { + return fn.apply( context, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; + + return proxy; + }, + + // Mutifunctional method to get and set values to a collection + // The value/s can optionally be executed if it's a function + access: function( elems, fn, key, value, chainable, emptyGet, pass ) { + var exec, + bulk = key == null, + i = 0, + length = elems.length; + + // Sets many values + if ( key && typeof key === "object" ) { + for ( i in key ) { + jQuery.access( elems, fn, i, key[i], 1, emptyGet, value ); + } + chainable = 1; + + // Sets one value + } else if ( value !== undefined ) { + // Optionally, function values get executed if exec is true + exec = pass === undefined && jQuery.isFunction( value ); + + if ( bulk ) { + // Bulk operations only iterate when executing function values + if ( exec ) { + exec = fn; + fn = function( elem, key, value ) { + return exec.call( jQuery( elem ), value ); + }; + + // Otherwise they run against the entire set + } else { + fn.call( elems, value ); + fn = null; + } + } + + if ( fn ) { + for (; i < length; i++ ) { + fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + } + } + + chainable = 1; + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + length ? fn( elems[0], key ) : emptyGet; + }, + + now: function() { + return ( new Date() ).getTime(); + }, + + // Use of jQuery.browser is frowned upon. + // More details: http://docs.jquery.com/Utilities/jQuery.browser + uaMatch: function( ua ) { + ua = ua.toLowerCase(); + + var match = rwebkit.exec( ua ) || + ropera.exec( ua ) || + rmsie.exec( ua ) || + ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || + []; + + return { browser: match[1] || "", version: match[2] || "0" }; + }, + + sub: function() { + function jQuerySub( selector, context ) { + return new jQuerySub.fn.init( selector, context ); + } + jQuery.extend( true, jQuerySub, this ); + jQuerySub.superclass = this; + jQuerySub.fn = jQuerySub.prototype = this(); + jQuerySub.fn.constructor = jQuerySub; + jQuerySub.sub = this.sub; + jQuerySub.fn.init = function init( selector, context ) { + if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { + context = jQuerySub( context ); + } + + return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); + }; + jQuerySub.fn.init.prototype = jQuerySub.fn; + var rootjQuerySub = jQuerySub(document); + return jQuerySub; + }, + + browser: {} +}); + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +browserMatch = jQuery.uaMatch( userAgent ); +if ( browserMatch.browser ) { + jQuery.browser[ browserMatch.browser ] = true; + jQuery.browser.version = browserMatch.version; +} + +// Deprecated, use jQuery.browser.webkit instead +if ( jQuery.browser.webkit ) { + jQuery.browser.safari = true; +} + +// IE doesn't match non-breaking spaces with \s +if ( rnotwhite.test( "\xA0" ) ) { + trimLeft = /^[\s\xA0]+/; + trimRight = /[\s\xA0]+$/; +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); + +// Cleanup functions for the document ready method +if ( document.addEventListener ) { + DOMContentLoaded = function() { + document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + jQuery.ready(); + }; + +} else if ( document.attachEvent ) { + DOMContentLoaded = function() { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( document.readyState === "complete" ) { + document.detachEvent( "onreadystatechange", DOMContentLoaded ); + jQuery.ready(); + } + }; +} + +// The DOM ready check for Internet Explorer +function doScrollCheck() { + if ( jQuery.isReady ) { + return; + } + + try { + // If IE is used, use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + document.documentElement.doScroll("left"); + } catch(e) { + setTimeout( doScrollCheck, 1 ); + return; + } + + // and execute any waiting functions + jQuery.ready(); +} + +return jQuery; + +})(); + + +// String to Object flags format cache +var flagsCache = {}; + +// Convert String-formatted flags into Object-formatted ones and store in cache +function createFlags( flags ) { + var object = flagsCache[ flags ] = {}, + i, length; + flags = flags.split( /\s+/ ); + for ( i = 0, length = flags.length; i < length; i++ ) { + object[ flags[i] ] = true; + } + return object; +} + +/* + * Create a callback list using the following parameters: + * + * flags: an optional list of space-separated flags that will change how + * the callback list behaves + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible flags: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( flags ) { + + // Convert flags from String-formatted to Object-formatted + // (we check in cache first) + flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {}; + + var // Actual callback list + list = [], + // Stack of fire calls for repeatable lists + stack = [], + // Last fire value (for non-forgettable lists) + memory, + // Flag to know if list was already fired + fired, + // Flag to know if list is currently firing + firing, + // First callback to fire (used internally by add and fireWith) + firingStart, + // End of the loop when firing + firingLength, + // Index of currently firing callback (modified by remove if needed) + firingIndex, + // Add one or several callbacks to the list + add = function( args ) { + var i, + length, + elem, + type, + actual; + for ( i = 0, length = args.length; i < length; i++ ) { + elem = args[ i ]; + type = jQuery.type( elem ); + if ( type === "array" ) { + // Inspect recursively + add( elem ); + } else if ( type === "function" ) { + // Add if not in unique mode and callback is not in + if ( !flags.unique || !self.has( elem ) ) { + list.push( elem ); + } + } + } + }, + // Fire callbacks + fire = function( context, args ) { + args = args || []; + memory = !flags.memory || [ context, args ]; + fired = true; + firing = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) { + memory = true; // Mark as halted + break; + } + } + firing = false; + if ( list ) { + if ( !flags.once ) { + if ( stack && stack.length ) { + memory = stack.shift(); + self.fireWith( memory[ 0 ], memory[ 1 ] ); + } + } else if ( memory === true ) { + self.disable(); + } else { + list = []; + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + var length = list.length; + add( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + // With memory, if we're not firing then + // we should call right away, unless previous + // firing was halted (stopOnFalse) + } else if ( memory && memory !== true ) { + firingStart = length; + fire( memory[ 0 ], memory[ 1 ] ); + } + } + return this; + }, + // Remove a callback from the list + remove: function() { + if ( list ) { + var args = arguments, + argIndex = 0, + argLength = args.length; + for ( ; argIndex < argLength ; argIndex++ ) { + for ( var i = 0; i < list.length; i++ ) { + if ( args[ argIndex ] === list[ i ] ) { + // Handle firingIndex and firingLength + if ( firing ) { + if ( i <= firingLength ) { + firingLength--; + if ( i <= firingIndex ) { + firingIndex--; + } + } + } + // Remove the element + list.splice( i--, 1 ); + // If we have some unicity property then + // we only need to do this once + if ( flags.unique ) { + break; + } + } + } + } + } + return this; + }, + // Control if a given callback is in the list + has: function( fn ) { + if ( list ) { + var i = 0, + length = list.length; + for ( ; i < length; i++ ) { + if ( fn === list[ i ] ) { + return true; + } + } + } + return false; + }, + // Remove all callbacks from the list + empty: function() { + list = []; + return this; + }, + // Have the list do nothing anymore + disable: function() { + list = stack = memory = undefined; + return this; + }, + // Is it disabled? + disabled: function() { + return !list; + }, + // Lock the list in its current state + lock: function() { + stack = undefined; + if ( !memory || memory === true ) { + self.disable(); + } + return this; + }, + // Is it locked? + locked: function() { + return !stack; + }, + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( stack ) { + if ( firing ) { + if ( !flags.once ) { + stack.push( [ context, args ] ); + } + } else if ( !( flags.once && memory ) ) { + fire( context, args ); + } + } + return this; + }, + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + + + +var // Static reference to slice + sliceDeferred = [].slice; + +jQuery.extend({ + + Deferred: function( func ) { + var doneList = jQuery.Callbacks( "once memory" ), + failList = jQuery.Callbacks( "once memory" ), + progressList = jQuery.Callbacks( "memory" ), + state = "pending", + lists = { + resolve: doneList, + reject: failList, + notify: progressList + }, + promise = { + done: doneList.add, + fail: failList.add, + progress: progressList.add, + + state: function() { + return state; + }, + + // Deprecated + isResolved: doneList.fired, + isRejected: failList.fired, + + then: function( doneCallbacks, failCallbacks, progressCallbacks ) { + deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks ); + return this; + }, + always: function() { + deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments ); + return this; + }, + pipe: function( fnDone, fnFail, fnProgress ) { + return jQuery.Deferred(function( newDefer ) { + jQuery.each( { + done: [ fnDone, "resolve" ], + fail: [ fnFail, "reject" ], + progress: [ fnProgress, "notify" ] + }, function( handler, data ) { + var fn = data[ 0 ], + action = data[ 1 ], + returned; + if ( jQuery.isFunction( fn ) ) { + deferred[ handler ](function() { + returned = fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify ); + } else { + newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); + } + }); + } else { + deferred[ handler ]( newDefer[ action ] ); + } + }); + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + if ( obj == null ) { + obj = promise; + } else { + for ( var key in promise ) { + obj[ key ] = promise[ key ]; + } + } + return obj; + } + }, + deferred = promise.promise({}), + key; + + for ( key in lists ) { + deferred[ key ] = lists[ key ].fire; + deferred[ key + "With" ] = lists[ key ].fireWith; + } + + // Handle state + deferred.done( function() { + state = "resolved"; + }, failList.disable, progressList.lock ).fail( function() { + state = "rejected"; + }, doneList.disable, progressList.lock ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( firstParam ) { + var args = sliceDeferred.call( arguments, 0 ), + i = 0, + length = args.length, + pValues = new Array( length ), + count = length, + pCount = length, + deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? + firstParam : + jQuery.Deferred(), + promise = deferred.promise(); + function resolveFunc( i ) { + return function( value ) { + args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + if ( !( --count ) ) { + deferred.resolveWith( deferred, args ); + } + }; + } + function progressFunc( i ) { + return function( value ) { + pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + deferred.notifyWith( promise, pValues ); + }; + } + if ( length > 1 ) { + for ( ; i < length; i++ ) { + if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) { + args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) ); + } else { + --count; + } + } + if ( !count ) { + deferred.resolveWith( deferred, args ); + } + } else if ( deferred !== firstParam ) { + deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); + } + return promise; + } +}); + + + + +jQuery.support = (function() { + + var support, + all, + a, + select, + opt, + input, + fragment, + tds, + events, + eventName, + i, + isSupported, + div = document.createElement( "div" ), + documentElement = document.documentElement; + + // Preliminary tests + div.setAttribute("className", "t"); + div.innerHTML = "
a"; + + all = div.getElementsByTagName( "*" ); + a = div.getElementsByTagName( "a" )[ 0 ]; + + // Can't get basic test support + if ( !all || !all.length || !a ) { + return {}; + } + + // First batch of supports tests + select = document.createElement( "select" ); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName( "input" )[ 0 ]; + + support = { + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: ( div.firstChild.nodeType === 3 ), + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName("tbody").length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName("link").length, + + // Get the style information from getAttribute + // (IE uses .cssText instead) + style: /top/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: ( a.getAttribute("href") === "/a" ), + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.55/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Make sure that if no value is specified for a checkbox + // that it defaults to "on". + // (WebKit defaults to "" instead) + checkOn: ( input.value === "on" ), + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + optSelected: opt.selected, + + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) + getSetAttribute: div.className !== "t", + + // Tests for enctype support on a form(#6743) + enctype: !!document.createElement("form").enctype, + + // Makes sure cloning an html5 element does not cause problems + // Where outerHTML is undefined, this still works + html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", + + // Will be defined later + submitBubbles: true, + changeBubbles: true, + focusinBubbles: false, + deleteExpando: true, + noCloneEvent: true, + inlineBlockNeedsLayout: false, + shrinkWrapBlocks: false, + reliableMarginRight: true, + pixelMargin: true + }; + + // jQuery.boxModel DEPRECATED in 1.3, use jQuery.support.boxModel instead + jQuery.boxModel = support.boxModel = (document.compatMode === "CSS1Compat"); + + // Make sure checked status is properly cloned + input.checked = true; + support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as disabled) + select.disabled = true; + support.optDisabled = !opt.disabled; + + // Test to see if it's possible to delete an expando from an element + // Fails in Internet Explorer + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + + if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { + div.attachEvent( "onclick", function() { + // Cloning a node shouldn't copy over any + // bound event handlers (IE does this) + support.noCloneEvent = false; + }); + div.cloneNode( true ).fireEvent( "onclick" ); + } + + // Check if a radio maintains its value + // after being appended to the DOM + input = document.createElement("input"); + input.value = "t"; + input.setAttribute("type", "radio"); + support.radioValue = input.value === "t"; + + input.setAttribute("checked", "checked"); + + // #11217 - WebKit loses check when the name is after the checked attribute + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + fragment = document.createDocumentFragment(); + fragment.appendChild( div.lastChild ); + + // WebKit doesn't clone checked state correctly in fragments + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + support.appendChecked = input.checked; + + fragment.removeChild( input ); + fragment.appendChild( div ); + + // Technique from Juriy Zaytsev + // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ + // We only care about the case where non-standard event systems + // are used, namely in IE. Short-circuiting here helps us to + // avoid an eval call (in setAttribute) which can cause CSP + // to go haywire. See: https://developer.mozilla.org/en/Security/CSP + if ( div.attachEvent ) { + for ( i in { + submit: 1, + change: 1, + focusin: 1 + }) { + eventName = "on" + i; + isSupported = ( eventName in div ); + if ( !isSupported ) { + div.setAttribute( eventName, "return;" ); + isSupported = ( typeof div[ eventName ] === "function" ); + } + support[ i + "Bubbles" ] = isSupported; + } + } + + fragment.removeChild( div ); + + // Null elements to avoid leaks in IE + fragment = select = opt = div = input = null; + + // Run tests that need a body at doc ready + jQuery(function() { + var container, outer, inner, table, td, offsetSupport, + marginDiv, conMarginTop, style, html, positionTopLeftWidthHeight, + paddingMarginBorderVisibility, paddingMarginBorder, + body = document.getElementsByTagName("body")[0]; + + if ( !body ) { + // Return for frameset docs that don't have a body + return; + } + + conMarginTop = 1; + paddingMarginBorder = "padding:0;margin:0;border:"; + positionTopLeftWidthHeight = "position:absolute;top:0;left:0;width:1px;height:1px;"; + paddingMarginBorderVisibility = paddingMarginBorder + "0;visibility:hidden;"; + style = "style='" + positionTopLeftWidthHeight + paddingMarginBorder + "5px solid #000;"; + html = "
" + + "" + + "
"; + + container = document.createElement("div"); + container.style.cssText = paddingMarginBorderVisibility + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px"; + body.insertBefore( container, body.firstChild ); + + // Construct the test element + div = document.createElement("div"); + container.appendChild( div ); + + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + // (only IE 8 fails this test) + div.innerHTML = "
t
"; + tds = div.getElementsByTagName( "td" ); + isSupported = ( tds[ 0 ].offsetHeight === 0 ); + + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; + + // Check if empty table cells still have offsetWidth/Height + // (IE <= 8 fail this test) + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); + + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. For more + // info see bug #3333 + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + if ( window.getComputedStyle ) { + div.innerHTML = ""; + marginDiv = document.createElement( "div" ); + marginDiv.style.width = "0"; + marginDiv.style.marginRight = "0"; + div.style.width = "2px"; + div.appendChild( marginDiv ); + support.reliableMarginRight = + ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; + } + + if ( typeof div.style.zoom !== "undefined" ) { + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + // (IE < 8 does this) + div.innerHTML = ""; + div.style.width = div.style.padding = "1px"; + div.style.border = 0; + div.style.overflow = "hidden"; + div.style.display = "inline"; + div.style.zoom = 1; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); + + // Check if elements with layout shrink-wrap their children + // (IE 6 does this) + div.style.display = "block"; + div.style.overflow = "visible"; + div.innerHTML = "
"; + support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); + } + + div.style.cssText = positionTopLeftWidthHeight + paddingMarginBorderVisibility; + div.innerHTML = html; + + outer = div.firstChild; + inner = outer.firstChild; + td = outer.nextSibling.firstChild.firstChild; + + offsetSupport = { + doesNotAddBorder: ( inner.offsetTop !== 5 ), + doesAddBorderForTableAndCells: ( td.offsetTop === 5 ) + }; + + inner.style.position = "fixed"; + inner.style.top = "20px"; + + // safari subtracts parent border width here which is 5px + offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 ); + inner.style.position = inner.style.top = ""; + + outer.style.overflow = "hidden"; + outer.style.position = "relative"; + + offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 ); + offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop ); + + if ( window.getComputedStyle ) { + div.style.marginTop = "1%"; + support.pixelMargin = ( window.getComputedStyle( div, null ) || { marginTop: 0 } ).marginTop !== "1%"; + } + + if ( typeof container.style.zoom !== "undefined" ) { + container.style.zoom = 1; + } + + body.removeChild( container ); + marginDiv = div = container = null; + + jQuery.extend( support, offsetSupport ); + }); + + return support; +})(); + + + + +var rbrace = /^(?:\{.*\}|\[.*\])$/, + rmultiDash = /([A-Z])/g; + +jQuery.extend({ + cache: {}, + + // Please use with caution + uuid: 0, + + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var privateCache, thisCache, ret, + internalKey = jQuery.expando, + getByName = typeof name === "string", + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey, + isEvents = name === "events"; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) { + return; + } + + if ( !id ) { + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + elem[ internalKey ] = id = ++jQuery.uuid; + } else { + id = internalKey; + } + } + + if ( !cache[ id ] ) { + cache[ id ] = {}; + + // Avoids exposing jQuery metadata on plain JS objects when the object + // is serialized using JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ] = jQuery.extend( cache[ id ], name ); + } else { + cache[ id ].data = jQuery.extend( cache[ id ].data, name ); + } + } + + privateCache = thisCache = cache[ id ]; + + // jQuery data() is stored in a separate object inside the object's internal data + // cache in order to avoid key collisions between internal data and user-defined + // data. + if ( !pvt ) { + if ( !thisCache.data ) { + thisCache.data = {}; + } + + thisCache = thisCache.data; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // Users should not attempt to inspect the internal events object using jQuery.data, + // it is undocumented and subject to change. But does anyone listen? No. + if ( isEvents && !thisCache[ name ] ) { + return privateCache.events; + } + + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( getByName ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; + } + + return ret; + }, + + removeData: function( elem, name, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, i, l, + + // Reference to internal data cache key + internalKey = jQuery.expando, + + isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + + // See jQuery.data for more information + id = isNode ? elem[ internalKey ] : internalKey; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + + thisCache = pvt ? cache[ id ] : cache[ id ].data; + + if ( thisCache ) { + + // Support array or space separated string names for data keys + if ( !jQuery.isArray( name ) ) { + + // try the string as a key before any manipulation + if ( name in thisCache ) { + name = [ name ]; + } else { + + // split the camel cased version by spaces unless a key with the spaces exists + name = jQuery.camelCase( name ); + if ( name in thisCache ) { + name = [ name ]; + } else { + name = name.split( " " ); + } + } + } + + for ( i = 0, l = name.length; i < l; i++ ) { + delete thisCache[ name[i] ]; + } + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( !pvt ) { + delete cache[ id ].data; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject(cache[ id ]) ) { + return; + } + } + + // Browsers that fail expando deletion also refuse to delete expandos on + // the window, but it will allow it on all other JS objects; other browsers + // don't care + // Ensure that `cache` is not a window object #10080 + if ( jQuery.support.deleteExpando || !cache.setInterval ) { + delete cache[ id ]; + } else { + cache[ id ] = null; + } + + // We destroyed the cache and need to eliminate the expando on the node to avoid + // false lookups in the cache for entries that no longer exist + if ( isNode ) { + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( jQuery.support.deleteExpando ) { + delete elem[ internalKey ]; + } else if ( elem.removeAttribute ) { + elem.removeAttribute( internalKey ); + } else { + elem[ internalKey ] = null; + } + } + }, + + // For internal use only. + _data: function( elem, name, data ) { + return jQuery.data( elem, name, data, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + if ( elem.nodeName ) { + var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; + + if ( match ) { + return !(match === true || elem.getAttribute("classid") !== match); + } + } + + return true; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var parts, part, attr, name, l, + elem = this[0], + i = 0, + data = null; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = jQuery.data( elem ); + + if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { + attr = elem.attributes; + for ( l = attr.length; i < l; i++ ) { + name = attr[i].name; + + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.substring(5) ); + + dataAttr( elem, name, data[ name ] ); + } + } + jQuery._data( elem, "parsedAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + parts = key.split( ".", 2 ); + parts[1] = parts[1] ? "." + parts[1] : ""; + part = parts[1] + "!"; + + return jQuery.access( this, function( value ) { + + if ( value === undefined ) { + data = this.triggerHandler( "getData" + part, [ parts[0] ] ); + + // Try to fetch any internally stored data first + if ( data === undefined && elem ) { + data = jQuery.data( elem, key ); + data = dataAttr( elem, key, data ); + } + + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; + } + + parts[1] = value; + this.each(function() { + var self = jQuery( this ); + + self.triggerHandler( "setData" + part, parts ); + jQuery.data( this, key, value ); + self.triggerHandler( "changeData" + part, parts ); + }); + }, null, value, arguments.length > 1, null, false ); + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +function dataAttr( elem, key, data ) { + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + jQuery.isNumeric( data ) ? +data : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// checks a cache object for emptiness +function isEmptyDataObject( obj ) { + for ( var name in obj ) { + + // if the public data object is empty, the private is still empty + if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { + continue; + } + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} + + + + +function handleQueueMarkDefer( elem, type, src ) { + var deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + defer = jQuery._data( elem, deferDataKey ); + if ( defer && + ( src === "queue" || !jQuery._data(elem, queueDataKey) ) && + ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) { + // Give room for hard-coded callbacks to fire first + // and eventually mark/queue something else on the element + setTimeout( function() { + if ( !jQuery._data( elem, queueDataKey ) && + !jQuery._data( elem, markDataKey ) ) { + jQuery.removeData( elem, deferDataKey, true ); + defer.fire(); + } + }, 0 ); + } +} + +jQuery.extend({ + + _mark: function( elem, type ) { + if ( elem ) { + type = ( type || "fx" ) + "mark"; + jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 ); + } + }, + + _unmark: function( force, elem, type ) { + if ( force !== true ) { + type = elem; + elem = force; + force = false; + } + if ( elem ) { + type = type || "fx"; + var key = type + "mark", + count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 ); + if ( count ) { + jQuery._data( elem, key, count ); + } else { + jQuery.removeData( elem, key, true ); + handleQueueMarkDefer( elem, type, "mark" ); + } + } + }, + + queue: function( elem, type, data ) { + var q; + if ( elem ) { + type = ( type || "fx" ) + "queue"; + q = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !q || jQuery.isArray(data) ) { + q = jQuery._data( elem, type, jQuery.makeArray(data) ); + } else { + q.push( data ); + } + } + return q || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + fn = queue.shift(), + hooks = {}; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + } + + if ( fn ) { + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + jQuery._data( elem, type + ".run", hooks ); + fn.call( elem, function() { + jQuery.dequeue( elem, type ); + }, hooks ); + } + + if ( !queue.length ) { + jQuery.removeData( elem, type + "queue " + type + ".run", true ); + handleQueueMarkDefer( elem, type, "queue" ); + } + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[0], type ); + } + + return data === undefined ? + this : + this.each(function() { + var queue = jQuery.queue( this, type, data ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = setTimeout( next, time ); + hooks.stop = function() { + clearTimeout( timeout ); + }; + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, object ) { + if ( typeof type !== "string" ) { + object = type; + type = undefined; + } + type = type || "fx"; + var defer = jQuery.Deferred(), + elements = this, + i = elements.length, + count = 1, + deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + tmp; + function resolve() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + } + while( i-- ) { + if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || + ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || + jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && + jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) { + count++; + tmp.add( resolve ); + } + } + resolve(); + return defer.promise( object ); + } +}); + + + + +var rclass = /[\n\t\r]/g, + rspace = /\s+/, + rreturn = /\r/g, + rtype = /^(?:button|input)$/i, + rfocusable = /^(?:button|input|object|select|textarea)$/i, + rclickable = /^a(?:rea)?$/i, + rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, + getSetAttribute = jQuery.support.getSetAttribute, + nodeHook, boolHook, fixSpecified; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each(function() { + jQuery.removeAttr( this, name ); + }); + }, + + prop: function( name, value ) { + return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; + return this.each(function() { + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch( e ) {} + }); + }, + + addClass: function( value ) { + var classNames, i, l, elem, + setClass, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).addClass( value.call(this, j, this.className) ); + }); + } + + if ( value && typeof value === "string" ) { + classNames = value.split( rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 ) { + if ( !elem.className && classNames.length === 1 ) { + elem.className = value; + + } else { + setClass = " " + elem.className + " "; + + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { + setClass += classNames[ c ] + " "; + } + } + elem.className = jQuery.trim( setClass ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classNames, i, l, elem, className, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).removeClass( value.call(this, j, this.className) ); + }); + } + + if ( (value && typeof value === "string") || value === undefined ) { + classNames = ( value || "" ).split( rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 && elem.className ) { + if ( value ) { + className = (" " + elem.className + " ").replace( rclass, " " ); + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + className = className.replace(" " + classNames[ c ] + " ", " "); + } + elem.className = jQuery.trim( className ); + + } else { + elem.className = ""; + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( i ) { + jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + state = stateVal, + classNames = value.split( rspace ); + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space seperated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + } else if ( type === "undefined" || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // toggle whole className + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " ", + i = 0, + l = this.length; + for ( ; i < l; i++ ) { + if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + var hooks, ret, isFunction, + elem = this[0]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { + return ret; + } + + ret = elem.value; + + return typeof ret === "string" ? + // handle most common string cases + ret.replace(rreturn, "") : + // handle cases where value is null/undef or number + ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each(function( i ) { + var self = jQuery(this), val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, self.val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + } else if ( typeof val === "number" ) { + val += ""; + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { + return value == null ? "" : value + ""; + }); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + valHooks: { + option: { + get: function( elem ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + }, + select: { + get: function( elem ) { + var value, i, max, option, + index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type === "select-one"; + + // Nothing was selected + if ( index < 0 ) { + return null; + } + + // Loop through all the selected options + i = one ? index : 0; + max = one ? index + 1 : options.length; + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Don't return options that are disabled or in a disabled optgroup + if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && + (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + // Fixes Bug #2551 -- select.val() broken in IE after form.reset() + if ( one && !values.length && options.length ) { + return jQuery( options[ index ] ).val(); + } + + return values; + }, + + set: function( elem, value ) { + var values = jQuery.makeArray( value ); + + jQuery(elem).find("option").each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + elem.selectedIndex = -1; + } + return values; + } + } + }, + + attrFn: { + val: true, + css: true, + html: true, + text: true, + data: true, + width: true, + height: true, + offset: true + }, + + attr: function( elem, name, value, pass ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( pass && name in jQuery.attrFn ) { + return jQuery( elem )[ name ]( value ); + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + // All attributes are lowercase + // Grab necessary hook if one is defined + if ( notxml ) { + name = name.toLowerCase(); + hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); + } + + if ( value !== undefined ) { + + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + + } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + elem.setAttribute( name, "" + value ); + return value; + } + + } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + + ret = elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return ret === null ? + undefined : + ret; + } + }, + + removeAttr: function( elem, value ) { + var propName, attrNames, name, l, isBool, + i = 0; + + if ( value && elem.nodeType === 1 ) { + attrNames = value.toLowerCase().split( rspace ); + l = attrNames.length; + + for ( ; i < l; i++ ) { + name = attrNames[ i ]; + + if ( name ) { + propName = jQuery.propFix[ name ] || name; + isBool = rboolean.test( name ); + + // See #9699 for explanation of this approach (setting first, then removal) + // Do not do this for boolean attributes (see #10870) + if ( !isBool ) { + jQuery.attr( elem, name, "" ); + } + elem.removeAttribute( getSetAttribute ? name : propName ); + + // Set corresponding property to false for boolean attributes + if ( isBool && propName in elem ) { + elem[ propName ] = false; + } + } + } + } + }, + + attrHooks: { + type: { + set: function( elem, value ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { + // Setting the type on a radio button after the value resets the value in IE6-9 + // Reset value to it's default in case type is set after value + // This is for element creation + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + }, + // Use the value property for back compat + // Use the nodeHook for button elements in IE6/7 (#1954) + value: { + get: function( elem, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.get( elem, name ); + } + return name in elem ? + elem.value : + null; + }, + set: function( elem, value, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.set( elem, value, name ); + } + // Does not return so that setAttribute is also used + elem.value = value; + } + } + }, + + propFix: { + tabindex: "tabIndex", + readonly: "readOnly", + "for": "htmlFor", + "class": "className", + maxlength: "maxLength", + cellspacing: "cellSpacing", + cellpadding: "cellPadding", + rowspan: "rowSpan", + colspan: "colSpan", + usemap: "useMap", + frameborder: "frameBorder", + contenteditable: "contentEditable" + }, + + prop: function( elem, name, value ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + if ( notxml ) { + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + return ( elem[ name ] = value ); + } + + } else { + if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + return elem[ name ]; + } + } + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + var attributeNode = elem.getAttributeNode("tabindex"); + + return attributeNode && attributeNode.specified ? + parseInt( attributeNode.value, 10 ) : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + } + } +}); + +// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional) +jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex; + +// Hook for boolean attributes +boolHook = { + get: function( elem, name ) { + // Align boolean attributes with corresponding properties + // Fall back to attribute presence where some booleans are not supported + var attrNode, + property = jQuery.prop( elem, name ); + return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? + name.toLowerCase() : + undefined; + }, + set: function( elem, value, name ) { + var propName; + if ( value === false ) { + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + // value is true since we know at this point it's type boolean and not false + // Set boolean attributes to the same name and set the DOM property + propName = jQuery.propFix[ name ] || name; + if ( propName in elem ) { + // Only set the IDL specifically if it already exists on the element + elem[ propName ] = true; + } + + elem.setAttribute( name, name.toLowerCase() ); + } + return name; + } +}; + +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !getSetAttribute ) { + + fixSpecified = { + name: true, + id: true, + coords: true + }; + + // Use this for any attribute in IE6/7 + // This fixes almost every IE6/7 issue + nodeHook = jQuery.valHooks.button = { + get: function( elem, name ) { + var ret; + ret = elem.getAttributeNode( name ); + return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ? + ret.nodeValue : + undefined; + }, + set: function( elem, value, name ) { + // Set the existing or create a new attribute node + var ret = elem.getAttributeNode( name ); + if ( !ret ) { + ret = document.createAttribute( name ); + elem.setAttributeNode( ret ); + } + return ( ret.nodeValue = value + "" ); + } + }; + + // Apply the nodeHook to tabindex + jQuery.attrHooks.tabindex.set = nodeHook.set; + + // Set width and height to auto instead of 0 on empty string( Bug #8150 ) + // This is for removals + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + set: function( elem, value ) { + if ( value === "" ) { + elem.setAttribute( name, "auto" ); + return value; + } + } + }); + }); + + // Set contenteditable to false on removals(#10429) + // Setting to empty string throws an error as an invalid value + jQuery.attrHooks.contenteditable = { + get: nodeHook.get, + set: function( elem, value, name ) { + if ( value === "" ) { + value = "false"; + } + nodeHook.set( elem, value, name ); + } + }; +} + + +// Some attributes require a special call on IE +if ( !jQuery.support.hrefNormalized ) { + jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + var ret = elem.getAttribute( name, 2 ); + return ret === null ? undefined : ret; + } + }); + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + // Return undefined in the case of empty string + // Normalize to lowercase since IE uppercases css property names + return elem.style.cssText.toLowerCase() || undefined; + }, + set: function( elem, value ) { + return ( elem.style.cssText = "" + value ); + } + }; +} + +// Safari mis-reports the default selected property of an option +// Accessing the parent's selectedIndex property fixes it +if ( !jQuery.support.optSelected ) { + jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { + get: function( elem ) { + var parent = elem.parentNode; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + return null; + } + }); +} + +// IE6/7 call enctype encoding +if ( !jQuery.support.enctype ) { + jQuery.propFix.enctype = "encoding"; +} + +// Radios and checkboxes getter/setter +if ( !jQuery.support.checkOn ) { + jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + get: function( elem ) { + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + return elem.getAttribute("value") === null ? "on" : elem.value; + } + }; + }); +} +jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); + } + } + }); +}); + + + + +var rformElems = /^(?:textarea|input|select)$/i, + rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/, + rhoverHack = /(?:^|\s)hover(\.\S+)?\b/, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|contextmenu)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/, + quickParse = function( selector ) { + var quick = rquickIs.exec( selector ); + if ( quick ) { + // 0 1 2 3 + // [ _, tag, id, class ] + quick[1] = ( quick[1] || "" ).toLowerCase(); + quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" ); + } + return quick; + }, + quickIs = function( elem, m ) { + var attrs = elem.attributes || {}; + return ( + (!m[1] || elem.nodeName.toLowerCase() === m[1]) && + (!m[2] || (attrs.id || {}).value === m[2]) && + (!m[3] || m[3].test( (attrs[ "class" ] || {}).value )) + ); + }, + hoverHack = function( events ) { + return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); + }; + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + add: function( elem, types, handler, data, selector ) { + + var elemData, eventHandle, events, + t, tns, type, namespaces, handleObj, + handleObjIn, quick, handlers, special; + + // Don't attach events to noData or text/comment nodes (allow plain objects tho) + if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + events = elemData.events; + if ( !events ) { + elemData.events = events = {}; + } + eventHandle = elemData.handle; + if ( !eventHandle ) { + elemData.handle = eventHandle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : + undefined; + }; + // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events + eventHandle.elem = elem; + } + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = jQuery.trim( hoverHack(types) ).split( " " ); + for ( t = 0; t < types.length; t++ ) { + + tns = rtypenamespace.exec( types[t] ) || []; + type = tns[1]; + namespaces = ( tns[2] || "" ).split( "." ).sort(); + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend({ + type: type, + origType: tns[1], + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + quick: selector && quickParse( selector ), + namespace: namespaces.join(".") + }, handleObjIn ); + + // Init the event handler queue if we're the first + handlers = events[ type ]; + if ( !handlers ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener/attachEvent if the special events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + global: {}, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var elemData = jQuery.hasData( elem ) && jQuery._data( elem ), + t, tns, type, origType, namespaces, origCount, + j, events, special, handle, eventType, handleObj; + + if ( !elemData || !(events = elemData.events) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = jQuery.trim( hoverHack( types || "" ) ).split(" "); + for ( t = 0; t < types.length; t++ ) { + tns = rtypenamespace.exec( types[t] ) || []; + type = origType = tns[1]; + namespaces = tns[2]; + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector? special.delegateType : special.bindType ) || type; + eventType = events[ type ] || []; + origCount = eventType.length; + namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null; + + // Remove matching events + for ( j = 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !namespaces || namespaces.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { + eventType.splice( j--, 1 ); + + if ( handleObj.selector ) { + eventType.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( eventType.length === 0 && origCount !== eventType.length ) { + if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + handle = elemData.handle; + if ( handle ) { + handle.elem = null; + } + + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery.removeData( elem, [ "events", "handle" ], true ); + } + }, + + // Events that are safe to short-circuit if no handlers are attached. + // Native DOM events should not be added, they may have inline handlers. + customEvent: { + "getData": true, + "setData": true, + "changeData": true + }, + + trigger: function( event, data, elem, onlyHandlers ) { + // Don't do events on text and comment nodes + if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { + return; + } + + // Event object or event type + var type = event.type || event, + namespaces = [], + cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType; + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "!" ) >= 0 ) { + // Exclusive events trigger only for the exact event (no namespaces) + type = type.slice(0, -1); + exclusive = true; + } + + if ( type.indexOf( "." ) >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + + if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { + // No jQuery handlers for this event type, and it can't have inline handlers + return; + } + + // Caller can pass in an Event, Object, or just an event type string + event = typeof event === "object" ? + // jQuery.Event object + event[ jQuery.expando ] ? event : + // Object literal + new jQuery.Event( type, event ) : + // Just the event type (string) + new jQuery.Event( type ); + + event.type = type; + event.isTrigger = true; + event.exclusive = exclusive; + event.namespace = namespaces.join( "." ); + event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null; + ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; + + // Handle a global trigger + if ( !elem ) { + + // TODO: Stop taunting the data cache; remove global events and always attach to document + cache = jQuery.cache; + for ( i in cache ) { + if ( cache[ i ].events && cache[ i ].events[ type ] ) { + jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); + } + } + return; + } + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data != null ? jQuery.makeArray( data ) : []; + data.unshift( event ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + eventPath = [[ elem, special.bindType || type ]]; + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; + old = null; + for ( ; cur; cur = cur.parentNode ) { + eventPath.push([ cur, bubbleType ]); + old = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( old && old === elem.ownerDocument ) { + eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); + } + } + + // Fire handlers on the event path + for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { + + cur = eventPath[i][0]; + event.type = eventPath[i][1]; + + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + // Note that this is a bare JS function and not a jQuery handler + handle = ontype && cur[ ontype ]; + if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) { + event.preventDefault(); + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && + !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction() check here because IE6/7 fails that test. + // Don't do default actions on window, that's where global variables be (#6170) + // IE<9 dies on focus/blur to hidden element (#1486) + if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + old = elem[ ontype ]; + + if ( old ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( old ) { + elem[ ontype ] = old; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event || window.event ); + + var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), + delegateCount = handlers.delegateCount, + args = [].slice.call( arguments, 0 ), + run_all = !event.exclusive && !event.namespace, + special = jQuery.event.special[ event.type ] || {}, + handlerQueue = [], + i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[0] = event; + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers that should run if there are delegated events + // Avoid non-left-click bubbling in Firefox (#3861) + if ( delegateCount && !(event.button && event.type === "click") ) { + + // Pregenerate a single jQuery object for reuse with .is() + jqcur = jQuery(this); + jqcur.context = this.ownerDocument || this; + + for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { + + // Don't process events on disabled elements (#6911, #8165) + if ( cur.disabled !== true ) { + selMatch = {}; + matches = []; + jqcur[0] = cur; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + sel = handleObj.selector; + + if ( selMatch[ sel ] === undefined ) { + selMatch[ sel ] = ( + handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel ) + ); + } + if ( selMatch[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, matches: matches }); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( handlers.length > delegateCount ) { + handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); + } + + // Run delegates first; they may want to stop propagation beneath us + for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { + matched = handlerQueue[ i ]; + event.currentTarget = matched.elem; + + for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { + handleObj = matched.matches[ j ]; + + // Triggered event must either 1) be non-exclusive and have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). + if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { + + event.data = handleObj.data; + event.handleObj = handleObj; + + ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) + .apply( matched.elem, args ); + + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** + props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split(" "), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), + filter: function( event, original ) { + var eventDoc, doc, body, + button = original.button, + fromElement = original.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && fromElement ) { + event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, + originalEvent = event, + fixHook = jQuery.event.fixHooks[ event.type ] || {}, + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = jQuery.Event( originalEvent ); + + for ( i = copy.length; i; ) { + prop = copy[ --i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) + if ( !event.target ) { + event.target = originalEvent.srcElement || document; + } + + // Target should not be a text node (#504, Safari) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8) + if ( event.metaKey === undefined ) { + event.metaKey = event.ctrlKey; + } + + return fixHook.filter? fixHook.filter( event, originalEvent ) : event; + }, + + special: { + ready: { + // Make sure the ready event is setup + setup: jQuery.bindReady + }, + + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + + focus: { + delegateType: "focusin" + }, + blur: { + delegateType: "focusout" + }, + + beforeunload: { + setup: function( data, namespaces, eventHandle ) { + // We only want to do this special case on windows + if ( jQuery.isWindow( this ) ) { + this.onbeforeunload = eventHandle; + } + }, + + teardown: function( namespaces, eventHandle ) { + if ( this.onbeforeunload === eventHandle ) { + this.onbeforeunload = null; + } + } + } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +// Some plugins are using, but it's undocumented/deprecated and will be removed. +// The 1.7 special event interface should provide all the hooks needed now. +jQuery.event.handle = jQuery.event.dispatch; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + if ( elem.detachEvent ) { + elem.detachEvent( "on" + type, handle ); + } + }; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !(this instanceof jQuery.Event) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || + src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +function returnFalse() { + return false; +} +function returnTrue() { + return true; +} + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + preventDefault: function() { + this.isDefaultPrevented = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + + // if preventDefault exists run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // otherwise set the returnValue property of the original event to false (IE) + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + this.isPropagationStopped = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + // if stopPropagation exists run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + // otherwise set the cancelBubble property of the original event to true (IE) + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + }, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var target = this, + related = event.relatedTarget, + handleObj = event.handleObj, + selector = handleObj.selector, + ret; + + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !jQuery.contains( target, related )) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +}); + +// IE submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Lazy-add a submit handler when a descendant form may potentially be submitted + jQuery.event.add( this, "click._submit keypress._submit", function( e ) { + // Node name check avoids a VML-related crash in IE (#9807) + var elem = e.target, + form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; + if ( form && !form._submit_attached ) { + jQuery.event.add( form, "submit._submit", function( event ) { + event._submit_bubble = true; + }); + form._submit_attached = true; + } + }); + // return undefined since we don't need an event listener + }, + + postDispatch: function( event ) { + // If form was submitted by the user, bubble the event up the tree + if ( event._submit_bubble ) { + delete event._submit_bubble; + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event, true ); + } + } + }, + + teardown: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Remove delegated handlers; cleanData eventually reaps submit handlers attached above + jQuery.event.remove( this, "._submit" ); + } + }; +} + +// IE change delegation and checkbox/radio fix +if ( !jQuery.support.changeBubbles ) { + + jQuery.event.special.change = { + + setup: function() { + + if ( rformElems.test( this.nodeName ) ) { + // IE doesn't fire change on a check/radio until blur; trigger it on click + // after a propertychange. Eat the blur-change in special.change.handle. + // This still fires onchange a second time for check/radio after blur. + if ( this.type === "checkbox" || this.type === "radio" ) { + jQuery.event.add( this, "propertychange._change", function( event ) { + if ( event.originalEvent.propertyName === "checked" ) { + this._just_changed = true; + } + }); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._just_changed && !event.isTrigger ) { + this._just_changed = false; + jQuery.event.simulate( "change", this, event, true ); + } + }); + } + return false; + } + // Delegated event; lazy-add a change handler on descendant inputs + jQuery.event.add( this, "beforeactivate._change", function( e ) { + var elem = e.target; + + if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { + jQuery.event.simulate( "change", this.parentNode, event, true ); + } + }); + elem._change_attached = true; + } + }); + }, + + handle: function( event ) { + var elem = event.target; + + // Swallow native change events from checkbox/radio, we already triggered them above + if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { + return event.handleObj.handler.apply( this, arguments ); + } + }, + + teardown: function() { + jQuery.event.remove( this, "._change" ); + + return rformElems.test( this.nodeName ); + } + }; +} + +// Create "bubbling" focus and blur events +if ( !jQuery.support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler while someone wants focusin/focusout + var attaches = 0, + handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + if ( attaches++ === 0 ) { + document.addEventListener( orig, handler, true ); + } + }, + teardown: function() { + if ( --attaches === 0 ) { + document.removeEventListener( orig, handler, true ); + } + } + }; + }); +} + +jQuery.fn.extend({ + + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { // && selector != null + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); + } + return this; + } + + if ( data == null && fn == null ) { + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return this; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on( types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + var handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + // ( types-object [, selector] ) + for ( var type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each(function() { + jQuery.event.remove( this, types, fn, selector ); + }); + }, + + bind: function( types, data, fn ) { + return this.on( types, null, data, fn ); + }, + unbind: function( types, fn ) { + return this.off( types, null, fn ); + }, + + live: function( types, data, fn ) { + jQuery( this.context ).on( types, this.selector, data, fn ); + return this; + }, + die: function( types, fn ) { + jQuery( this.context ).off( types, this.selector || "**", fn ); + return this; + }, + + delegate: function( selector, types, data, fn ) { + return this.on( types, selector, data, fn ); + }, + undelegate: function( selector, types, fn ) { + // ( namespace ) or ( selector, types [, fn] ) + return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn ); + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + triggerHandler: function( type, data ) { + if ( this[0] ) { + return jQuery.event.trigger( type, data, this[0], true ); + } + }, + + toggle: function( fn ) { + // Save reference to arguments for access in closure + var args = arguments, + guid = fn.guid || jQuery.guid++, + i = 0, + toggler = function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + }; + + // link all the functions, so any of them can unbind this click handler + toggler.guid = guid; + while ( i < args.length ) { + args[ i++ ].guid = guid; + } + + return this.click( toggler ); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +}); + +jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + if ( fn == null ) { + fn = data; + data = null; + } + + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; + + if ( jQuery.attrFn ) { + jQuery.attrFn[ name ] = true; + } + + if ( rkeyEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; + } + + if ( rmouseEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; + } +}); + + + +/*! + * Sizzle CSS Selector Engine + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + expando = "sizcache" + (Math.random() + '').replace('.', ''), + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true, + rBackslash = /\\/g, + rReturn = /\r\n/g, + rNonWord = /\W/; + +// Here we check if the JavaScript engine is using some sort of +// optimization where it does not always call our comparision +// function. If that is the case, discard the hasDuplicate value. +// Thus far that includes Google Chrome. +[0, 0].sort(function() { + baseHasDuplicate = false; + return 0; +}); + +var Sizzle = function( selector, context, results, seed ) { + results = results || []; + context = context || document; + + var origContext = context; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var m, set, checkSet, extra, ret, cur, pop, i, + prune = true, + contextXML = Sizzle.isXML( context ), + parts = [], + soFar = selector; + + // Reset the position of the chunker regexp (start from head) + do { + chunker.exec( "" ); + m = chunker.exec( soFar ); + + if ( m ) { + soFar = m[3]; + + parts.push( m[1] ); + + if ( m[2] ) { + extra = m[3]; + break; + } + } + } while ( m ); + + if ( parts.length > 1 && origPOS.exec( selector ) ) { + + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context, seed ); + + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) { + selector += parts.shift(); + } + + set = posProcess( selector, set, seed ); + } + } + + } else { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + + ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? + Sizzle.filter( ret.expr, ret.set )[0] : + ret.set[0]; + } + + if ( context ) { + ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + + set = ret.expr ? + Sizzle.filter( ret.expr, ret.set ) : + ret.set; + + if ( parts.length > 0 ) { + checkSet = makeArray( set ); + + } else { + prune = false; + } + + while ( parts.length ) { + cur = parts.pop(); + pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + + } else { + checkSet = parts = []; + } + } + + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + Sizzle.error( cur || selector ); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + + } else if ( context && context.nodeType === 1 ) { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + + } else { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + + } else { + makeArray( checkSet, results ); + } + + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } + + return results; +}; + +Sizzle.uniqueSort = function( results ) { + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort( sortOrder ); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[ i - 1 ] ) { + results.splice( i--, 1 ); + } + } + } + } + + return results; +}; + +Sizzle.matches = function( expr, set ) { + return Sizzle( expr, null, null, set ); +}; + +Sizzle.matchesSelector = function( node, expr ) { + return Sizzle( expr, null, null, [node] ).length > 0; +}; + +Sizzle.find = function( expr, context, isXML ) { + var set, i, len, match, type, left; + + if ( !expr ) { + return []; + } + + for ( i = 0, len = Expr.order.length; i < len; i++ ) { + type = Expr.order[i]; + + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + left = match[1]; + match.splice( 1, 1 ); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace( rBackslash, "" ); + set = Expr.find[ type ]( match, context, isXML ); + + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } + + if ( !set ) { + set = typeof context.getElementsByTagName !== "undefined" ? + context.getElementsByTagName( "*" ) : + []; + } + + return { set: set, expr: expr }; +}; + +Sizzle.filter = function( expr, set, inplace, not ) { + var match, anyFound, + type, found, item, filter, left, + i, pass, + old = expr, + result = [], + curLoop = set, + isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); + + while ( expr && set.length ) { + for ( type in Expr.filter ) { + if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { + filter = Expr.filter[ type ]; + left = match[1]; + + anyFound = false; + + match.splice(1,1); + + if ( left.substr( left.length - 1 ) === "\\" ) { + continue; + } + + if ( curLoop === result ) { + result = []; + } + + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + + if ( !match ) { + anyFound = found = true; + + } else if ( match === true ) { + continue; + } + } + + if ( match ) { + for ( i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + pass = not ^ found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + + } else { + curLoop[i] = false; + } + + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + + expr = expr.replace( Expr.match[ type ], "" ); + + if ( !anyFound ) { + return []; + } + + break; + } + } + } + + // Improper expression + if ( expr === old ) { + if ( anyFound == null ) { + Sizzle.error( expr ); + + } else { + break; + } + } + + old = expr; + } + + return curLoop; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Utility function for retreiving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +var getText = Sizzle.getText = function( elem ) { + var i, node, + nodeType = elem.nodeType, + ret = ""; + + if ( nodeType ) { + if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent || innerText for elements + if ( typeof elem.textContent === 'string' ) { + return elem.textContent; + } else if ( typeof elem.innerText === 'string' ) { + // Replace IE's carriage returns + return elem.innerText.replace( rReturn, '' ); + } else { + // Traverse it's children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + } else { + + // If no nodeType, this is expected to be an array + for ( i = 0; (node = elem[i]); i++ ) { + // Do not traverse comment nodes + if ( node.nodeType !== 8 ) { + ret += getText( node ); + } + } + } + return ret; +}; + +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + + match: { + ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ + }, + + leftMatch: {}, + + attrMap: { + "class": "className", + "for": "htmlFor" + }, + + attrHandle: { + href: function( elem ) { + return elem.getAttribute( "href" ); + }, + type: function( elem ) { + return elem.getAttribute( "type" ); + } + }, + + relative: { + "+": function(checkSet, part){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !rNonWord.test( part ), + isPartStrNotTag = isPartStr && !isTag; + + if ( isTag ) { + part = part.toLowerCase(); + } + + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? + elem || false : + elem === part; + } + } + + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + + ">": function( checkSet, part ) { + var elem, + isPartStr = typeof part === "string", + i = 0, + l = checkSet.length; + + if ( isPartStr && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + + for ( ; i < l; i++ ) { + elem = checkSet[i]; + + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; + } + } + + } else { + for ( ; i < l; i++ ) { + elem = checkSet[i]; + + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + + "": function(checkSet, part, isXML){ + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); + }, + + "~": function( checkSet, part, isXML ) { + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); + } + }, + + find: { + ID: function( match, context, isXML ) { + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [m] : []; + } + }, + + NAME: function( match, context ) { + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], + results = context.getElementsByName( match[1] ); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + + return ret.length === 0 ? null : ret; + } + }, + + TAG: function( match, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( match[1] ); + } + } + }, + preFilter: { + CLASS: function( match, curLoop, inplace, result, not, isXML ) { + match = " " + match[1].replace( rBackslash, "" ) + " "; + + if ( isXML ) { + return match; + } + + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { + if ( !inplace ) { + result.push( elem ); + } + + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + + return false; + }, + + ID: function( match ) { + return match[1].replace( rBackslash, "" ); + }, + + TAG: function( match, curLoop ) { + return match[1].replace( rBackslash, "" ).toLowerCase(); + }, + + CHILD: function( match ) { + if ( match[1] === "nth" ) { + if ( !match[2] ) { + Sizzle.error( match[0] ); + } + + match[2] = match[2].replace(/^\+|\s*/g, ''); + + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( + match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + else if ( match[2] ) { + Sizzle.error( match[0] ); + } + + // TODO: Move to normal caching system + match[0] = done++; + + return match; + }, + + ATTR: function( match, curLoop, inplace, result, not, isXML ) { + var name = match[1] = match[1].replace( rBackslash, "" ); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + // Handle if an un-quoted value was used + match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + + PSEUDO: function( match, curLoop, inplace, result, not ) { + if ( match[1] === "not" ) { + // If we're dealing with a complex expression, or a simple one + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + + if ( !inplace ) { + result.push.apply( result, ret ); + } + + return false; + } + + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + + POS: function( match ) { + match.unshift( true ); + + return match; + } + }, + + filters: { + enabled: function( elem ) { + return elem.disabled === false && elem.type !== "hidden"; + }, + + disabled: function( elem ) { + return elem.disabled === true; + }, + + checked: function( elem ) { + return elem.checked === true; + }, + + selected: function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + parent: function( elem ) { + return !!elem.firstChild; + }, + + empty: function( elem ) { + return !elem.firstChild; + }, + + has: function( elem, i, match ) { + return !!Sizzle( match[3], elem ).length; + }, + + header: function( elem ) { + return (/h\d/i).test( elem.nodeName ); + }, + + text: function( elem ) { + var attr = elem.getAttribute( "type" ), type = elem.type; + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); + }, + + radio: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; + }, + + checkbox: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; + }, + + file: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; + }, + + password: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; + }, + + submit: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "submit" === elem.type; + }, + + image: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; + }, + + reset: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "reset" === elem.type; + }, + + button: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && "button" === elem.type || name === "button"; + }, + + input: function( elem ) { + return (/input|select|textarea|button/i).test( elem.nodeName ); + }, + + focus: function( elem ) { + return elem === elem.ownerDocument.activeElement; + } + }, + setFilters: { + first: function( elem, i ) { + return i === 0; + }, + + last: function( elem, i, match, array ) { + return i === array.length - 1; + }, + + even: function( elem, i ) { + return i % 2 === 0; + }, + + odd: function( elem, i ) { + return i % 2 === 1; + }, + + lt: function( elem, i, match ) { + return i < match[3] - 0; + }, + + gt: function( elem, i, match ) { + return i > match[3] - 0; + }, + + nth: function( elem, i, match ) { + return match[3] - 0 === i; + }, + + eq: function( elem, i, match ) { + return match[3] - 0 === i; + } + }, + filter: { + PSEUDO: function( elem, match, i, array ) { + var name = match[1], + filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; + + } else if ( name === "not" ) { + var not = match[3]; + + for ( var j = 0, l = not.length; j < l; j++ ) { + if ( not[j] === elem ) { + return false; + } + } + + return true; + + } else { + Sizzle.error( name ); + } + }, + + CHILD: function( elem, match ) { + var first, last, + doneName, parent, cache, + count, diff, + type = match[1], + node = elem; + + switch ( type ) { + case "only": + case "first": + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + if ( type === "first" ) { + return true; + } + + node = elem; + + /* falls through */ + case "last": + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + return true; + + case "nth": + first = match[2]; + last = match[3]; + + if ( first === 1 && last === 0 ) { + return true; + } + + doneName = match[0]; + parent = elem.parentNode; + + if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) { + count = 0; + + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + + parent[ expando ] = doneName; + } + + diff = elem.nodeIndex - last; + + if ( first === 0 ) { + return diff === 0; + + } else { + return ( diff % first === 0 && diff / first >= 0 ); + } + } + }, + + ID: function( elem, match ) { + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + + TAG: function( elem, match ) { + return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match; + }, + + CLASS: function( elem, match ) { + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + + ATTR: function( elem, match ) { + var name = match[1], + result = Sizzle.attr ? + Sizzle.attr( elem, name ) : + Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + !type && Sizzle.attr ? + result != null : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value !== check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + + POS: function( elem, match, i, array ) { + var name = match[2], + filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; + +var origPOS = Expr.match.POS, + fescape = function(all, num){ + return "\\" + (num - 0 + 1); + }; + +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); +} +// Expose origPOS +// "global" as in regardless of relation to brackets/parens +Expr.match.globalPOS = origPOS; + +var makeArray = function( array, results ) { + array = Array.prototype.slice.call( array, 0 ); + + if ( results ) { + results.push.apply( results, array ); + return results; + } + + return array; +}; + +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +// Also verifies that the returned array holds DOM nodes +// (which is not the case in the Blackberry browser) +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; + +// Provide a fallback method if it does not work +} catch( e ) { + makeArray = function( array, results ) { + var i = 0, + ret = results || []; + + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + + } else { + if ( typeof array.length === "number" ) { + for ( var l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + + } else { + for ( ; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + + return ret; + }; +} + +var sortOrder, siblingCheck; + +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + return a.compareDocumentPosition ? -1 : 1; + } + + return a.compareDocumentPosition(b) & 4 ? -1 : 1; + }; + +} else { + sortOrder = function( a, b ) { + // The nodes are identical, we can exit early + if ( a === b ) { + hasDuplicate = true; + return 0; + + // Fallback to using sourceIndex (in IE) if it's available on both nodes + } else if ( a.sourceIndex && b.sourceIndex ) { + return a.sourceIndex - b.sourceIndex; + } + + var al, bl, + ap = [], + bp = [], + aup = a.parentNode, + bup = b.parentNode, + cur = aup; + + // If the nodes are siblings (or identical) we can do a quick check + if ( aup === bup ) { + return siblingCheck( a, b ); + + // If no parents were found then the nodes are disconnected + } else if ( !aup ) { + return -1; + + } else if ( !bup ) { + return 1; + } + + // Otherwise they're somewhere else in the tree so we need + // to build up a full list of the parentNodes for comparison + while ( cur ) { + ap.unshift( cur ); + cur = cur.parentNode; + } + + cur = bup; + + while ( cur ) { + bp.unshift( cur ); + cur = cur.parentNode; + } + + al = ap.length; + bl = bp.length; + + // Start walking down the tree looking for a discrepancy + for ( var i = 0; i < al && i < bl; i++ ) { + if ( ap[i] !== bp[i] ) { + return siblingCheck( ap[i], bp[i] ); + } + } + + // We ended someplace up the tree so do a sibling check + return i === al ? + siblingCheck( a, bp[i], -1 ) : + siblingCheck( ap[i], b, 1 ); + }; + + siblingCheck = function( a, b, ret ) { + if ( a === b ) { + return ret; + } + + var cur = a.nextSibling; + + while ( cur ) { + if ( cur === b ) { + return -1; + } + + cur = cur.nextSibling; + } + + return 1; + }; +} + +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + var form = document.createElement("div"), + id = "script" + (new Date()).getTime(), + root = document.documentElement; + + form.innerHTML = ""; + + // Inject it into the root element, check its status, and remove it quickly + root.insertBefore( form, root.firstChild ); + + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + if ( document.getElementById( id ) ) { + Expr.find.ID = function( match, context, isXML ) { + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + + return m ? + m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? + [m] : + undefined : + []; + } + }; + + Expr.filter.ID = function( elem, match ) { + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } + + root.removeChild( form ); + + // release memory in IE + root = form = null; +})(); + +(function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") + + // Create a fake element + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + // Make sure no comments are found + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function( match, context ) { + var results = context.getElementsByTagName( match[1] ); + + // Filter out possible comments + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; + } + + return results; + }; + } + + // Check to see if an attribute returns normalized href attributes + div.innerHTML = ""; + + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + + Expr.attrHandle.href = function( elem ) { + return elem.getAttribute( "href", 2 ); + }; + } + + // release memory in IE + div = null; +})(); + +if ( document.querySelectorAll ) { + (function(){ + var oldSizzle = Sizzle, + div = document.createElement("div"), + id = "__sizzle__"; + + div.innerHTML = "

"; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function( query, context, extra, seed ) { + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && !Sizzle.isXML(context) ) { + // See if we find a selector to speed up + var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); + + if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { + // Speed-up: Sizzle("TAG") + if ( match[1] ) { + return makeArray( context.getElementsByTagName( query ), extra ); + + // Speed-up: Sizzle(".CLASS") + } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { + return makeArray( context.getElementsByClassName( match[2] ), extra ); + } + } + + if ( context.nodeType === 9 ) { + // Speed-up: Sizzle("body") + // The body element only exists once, optimize finding it + if ( query === "body" && context.body ) { + return makeArray( [ context.body ], extra ); + + // Speed-up: Sizzle("#ID") + } else if ( match && match[3] ) { + var elem = context.getElementById( match[3] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id === match[3] ) { + return makeArray( [ elem ], extra ); + } + + } else { + return makeArray( [], extra ); + } + } + + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(qsaError) {} + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + var oldContext = context, + old = context.getAttribute( "id" ), + nid = old || id, + hasParent = context.parentNode, + relativeHierarchySelector = /^\s*[+~]/.test( query ); + + if ( !old ) { + context.setAttribute( "id", nid ); + } else { + nid = nid.replace( /'/g, "\\$&" ); + } + if ( relativeHierarchySelector && hasParent ) { + context = context.parentNode; + } + + try { + if ( !relativeHierarchySelector || hasParent ) { + return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); + } + + } catch(pseudoError) { + } finally { + if ( !old ) { + oldContext.removeAttribute( "id" ); + } + } + } + } + + return oldSizzle(query, context, extra, seed); + }; + + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } + + // release memory in IE + div = null; + })(); +} + +(function(){ + var html = document.documentElement, + matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; + + if ( matches ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9 fails this) + var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), + pseudoWorks = false; + + try { + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( document.documentElement, "[test!='']:sizzle" ); + + } catch( pseudoError ) { + pseudoWorks = true; + } + + Sizzle.matchesSelector = function( node, expr ) { + // Make sure that attribute selectors are quoted + expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); + + if ( !Sizzle.isXML( node ) ) { + try { + if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { + var ret = matches.call( node, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || !disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9, so check for that + node.document && node.document.nodeType !== 11 ) { + return ret; + } + } + } catch(e) {} + } + + return Sizzle(expr, null, null, [node]).length > 0; + }; + } +})(); + +(function(){ + var div = document.createElement("div"); + + div.innerHTML = "
"; + + // Opera can't find a second classname (in 9.6) + // Also, make sure that getElementsByClassName actually exists + if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { + return; + } + + // Safari caches class attributes, doesn't catch changes (in 3.2) + div.lastChild.className = "e"; + + if ( div.getElementsByClassName("e").length === 1 ) { + return; + } + + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function( match, context, isXML ) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; + + // release memory in IE + div = null; +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + + if ( elem ) { + var match = false; + + elem = elem[dir]; + + while ( elem ) { + if ( elem[ expando ] === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 && !isXML ){ + elem[ expando ] = doneName; + elem.sizset = i; + } + + if ( elem.nodeName.toLowerCase() === cur ) { + match = elem; + break; + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + + if ( elem ) { + var match = false; + + elem = elem[dir]; + + while ( elem ) { + if ( elem[ expando ] === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem[ expando ] = doneName; + elem.sizset = i; + } + + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +if ( document.documentElement.contains ) { + Sizzle.contains = function( a, b ) { + return a !== b && (a.contains ? a.contains(b) : true); + }; + +} else if ( document.documentElement.compareDocumentPosition ) { + Sizzle.contains = function( a, b ) { + return !!(a.compareDocumentPosition(b) & 16); + }; + +} else { + Sizzle.contains = function() { + return false; + }; +} + +Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; + + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +var posProcess = function( selector, context, seed ) { + var match, + tmpSet = [], + later = "", + root = context.nodeType ? [context] : context; + + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } + + selector = Expr.relative[selector] ? selector + "*" : selector; + + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet, seed ); + } + + return Sizzle.filter( later, tmpSet ); +}; + +// EXPOSE +// Override sizzle attribute retrieval +Sizzle.attr = jQuery.attr; +Sizzle.selectors.attrMap = {}; +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.filters; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})(); + + +var runtil = /Until$/, + rparentsprev = /^(?:parents|prevUntil|prevAll)/, + // Note: This RegExp should be improved, or likely pulled from Sizzle + rmultiselector = /,/, + isSimple = /^.[^:#\[\.,]*$/, + slice = Array.prototype.slice, + POS = jQuery.expr.match.globalPOS, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend({ + find: function( selector ) { + var self = this, + i, l; + + if ( typeof selector !== "string" ) { + return jQuery( selector ).filter(function() { + for ( i = 0, l = self.length; i < l; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }); + } + + var ret = this.pushStack( "", "find", selector ), + length, n, r; + + for ( i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + if ( i > 0 ) { + // Make sure that the results are unique + for ( n = length; n < ret.length; n++ ) { + for ( r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + ret.splice(n--, 1); + break; + } + } + } + } + } + + return ret; + }, + + has: function( target ) { + var targets = jQuery( target ); + return this.filter(function() { + for ( var i = 0, l = targets.length; i < l; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false), "not", selector); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true), "filter", selector ); + }, + + is: function( selector ) { + return !!selector && ( + typeof selector === "string" ? + // If this is a positional selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + POS.test( selector ) ? + jQuery( selector, this.context ).index( this[0] ) >= 0 : + jQuery.filter( selector, this ).length > 0 : + this.filter( selector ).length > 0 ); + }, + + closest: function( selectors, context ) { + var ret = [], i, l, cur = this[0]; + + // Array (deprecated as of jQuery 1.7) + if ( jQuery.isArray( selectors ) ) { + var level = 1; + + while ( cur && cur.ownerDocument && cur !== context ) { + for ( i = 0; i < selectors.length; i++ ) { + + if ( jQuery( cur ).is( selectors[ i ] ) ) { + ret.push({ selector: selectors[ i ], elem: cur, level: level }); + } + } + + cur = cur.parentNode; + level++; + } + + return ret; + } + + // String + var pos = POS.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( i = 0, l = this.length; i < l; i++ ) { + cur = this[i]; + + while ( cur ) { + if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { + ret.push( cur ); + break; + + } else { + cur = cur.parentNode; + if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { + break; + } + } + } + } + + ret = ret.length > 1 ? jQuery.unique( ret ) : ret; + + return this.pushStack( ret, "closest", selectors ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; + } + + // index in selector + if ( typeof elem === "string" ) { + return jQuery.inArray( this[0], jQuery( elem ) ); + } + + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? + all : + jQuery.unique( all ) ); + }, + + andSelf: function() { + return this.add( this.prevObject ); + } +}); + +// A painfully simple check to see if an element is disconnected +// from a document (should be improved, where feasible). +function isDisconnected( node ) { + return !node || !node.parentNode || node.parentNode.nodeType === 11; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return jQuery.nth( elem, 2, "nextSibling" ); + }, + prev: function( elem ) { + return jQuery.nth( elem, 2, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.makeArray( elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; + + if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, name, slice.call( arguments ).join(",") ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 ? + jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : + jQuery.find.matches(expr, elems); + }, + + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + nth: function( cur, result, dir, elem ) { + result = result || 1; + var num = 0; + + for ( ; cur; cur = cur[dir] ) { + if ( cur.nodeType === 1 && ++num === result ) { + break; + } + } + + return cur; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, keep ) { + + // Can't pass null or undefined to indexOf in Firefox 4 + // Set to 0 to skip string check + qualifier = qualifier || 0; + + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + var retVal = !!qualifier.call( elem, i, elem ); + return retVal === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem, i ) { + return ( elem === qualifier ) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem, i ) { + return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; + }); +} + + + + +function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + +var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", + rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rtagName = /<([\w:]+)/, + rtbody = /]", "i"), + // checked="checked" or checked + rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, + rscriptType = /\/(java|ecma)script/i, + rcleanScript = /^\s*", "" ], + legend: [ 1, "
", "
" ], + thead: [ 1, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + col: [ 2, "", "
" ], + area: [ 1, "", "" ], + _default: [ 0, "", "" ] + }, + safeFragment = createSafeFragment( document ); + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// IE can't serialize and + + + + + + + + + + + +
+
+
+
+ +
+

Configuration¶

+

Almost all configurable data is placed in config.inc.php. If this file +does not exist, please refer to the Installation section to create one. This +file only needs to contain the parameters you want to change from their +corresponding default value in libraries/config.default.php.

+

If a directive is missing from your file, you can just add another line with +the file. This file is for over-writing the defaults; if you wish to use the +default value there’s no need to add a line here.

+

The parameters which relate to design (like colors) are placed in +themes/themename/layout.inc.php. You might also want to create +config.footer.inc.php and config.header.inc.php files to add +your site specific code to be included on start and end of each page.

+
+

Note

+

Some distributions (eg. Debian or Ubuntu) store config.inc.php in +/etc/phpmyadmin instead of within phpMyAdmin sources.

+
+
+

Warning

+

Mac users should note that if you are on a version before +Mac OS X, PHP does not seem to +like Mac end of lines character (\r). So +ensure you choose the option that allows to use the *nix end of line +character (\n) in your text editor before saving a script you have +modified.

+
+
+

Basic settings¶

+
+
+$cfg['PmaAbsoluteUri']¶
+
+++ + + + + + +
Type:string
Default value:''
+

Sets here the complete URL (with full path) to your phpMyAdmin +installation’s directory. E.g. +http://www.example.net/path_to_your_phpMyAdmin_directory/. Note also +that the URL on most of web servers are case–sensitive. Don’t +forget the trailing slash at the end.

+

Starting with version 2.3.0, it is advisable to try leaving this blank. In +most cases phpMyAdmin automatically detects the proper setting. Users of +port forwarding will need to set $cfg['PmaAbsoluteUri'] +(more info).

+

A good test is to browse a table, edit a row and save it. There should be +an error message if phpMyAdmin is having trouble auto–detecting the correct +value. If you get an error that this must be set or if the autodetect code +fails to detect your path, please post a bug report on our bug tracker so +we can improve the code.

+ +
+ +
+
+$cfg['PmaNoRelation_DisableWarning']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Starting with version 2.3.0 phpMyAdmin offers a lot of features to +work with master / foreign – tables (see $cfg['Servers'][$i]['pmadb']).

+

If you tried to set this +up and it does not work for you, have a look on the Structure page +of one database where you would like to use it. You will find a link +that will analyze why those features have been disabled.

+

If you do not want to use those features set this variable to true to +stop this message from appearing.

+
+ +
+
+$cfg['SuhosinDisableWarning']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

A warning is displayed on the main page if Suhosin is detected.

+

You can set this parameter to true to stop this message from appearing.

+
+ +
+
+$cfg['McryptDisableWarning']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Disable the default warning that is displayed if mcrypt is missing for +cookie authentication.

+

You can set this parameter to true to stop this message from appearing.

+
+ +
+
+$cfg['ServerLibraryDifference_DisableWarning']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

A warning is displayed on the main page if there is a difference +between the MySQL library and server version.

+

You can set this parameter to true to stop this message from appearing.

+
+ +
+
+$cfg['ReservedWordDisableWarning']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

This warning is displayed on the Structure page of a table if one or more +column names match with words which are MySQL reserved.

+

If you want to turn off this warning, you can set it to true and +warning will no longer be displayed.

+
+ +
+
+$cfg['TranslationWarningThreshold']¶
+
+++ + + + + + +
Type:integer
Default value:80
+

Show warning about incomplete translations on certain threshold.

+
+ +
+
+$cfg['SendErrorReports']¶
+
+++ + + + + + +
Type:string
Default value:'ask'
+

Sets the default behavior for JavaScript error reporting.

+

Whenever an error is detected in the JavaScript execution, an error report +may be sent to the phpMyAdmin team if the user agrees.

+

The default setting of 'ask' will ask the user everytime there is a new +error report. However you can set this parameter to 'always' to send error +reports without asking for confirmation or you can set it to 'never' to +never send error reports.

+

This directive is available both in the configuration file and in users +preferences. If the person in charge of a multi-user installation prefers +to disable this feature for all users, a value of 'never' should be +set, and the $cfg['UserprefsDisallow'] directive should +contain 'SendErrorReports' in one of its array values.

+
+ +
+
+$cfg['AllowThirdPartyFraming']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Setting this to true allows phpMyAdmin to be included inside a frame, +and is a potential security hole allowing cross-frame scripting attacks or +clickjacking.

+
+ +
+
+

Server connection settings¶

+
+
+$cfg['Servers']¶
+
+++ + + + + + +
Type:array
Default value:one server array with settings listed bellow
+

Since version 1.4.2, phpMyAdmin supports the administration of multiple +MySQL servers. Therefore, a $cfg['Servers']-array has been +added which contains the login information for the different servers. The +first $cfg['Servers'][$i]['host'] contains the hostname of +the first server, the second $cfg['Servers'][$i]['host'] +the hostname of the second server, etc. In +libraries/config.default.php, there is only one section for server +definition, however you can put as many as you need in +config.inc.php, copy that block or needed parts (you don’t have to +define all settings, just those you need to change).

+
+

Note

+

The $cfg['Servers'] array starts with +$cfg[‘Servers’][1]. Do not use $cfg[‘Servers’][0]. If you want more +than one server, just copy following section (including $i +incrementation) serveral times. There is no need to define full server +array, just define values you need to change.

+
+
+ +
+
+$cfg['Servers'][$i]['host']¶
+
+++ + + + + + +
Type:string
Default value:'localhost'
+

The hostname or IP address of your $i-th MySQL-server. E.g. +localhost.

+

Possible values are:

+
    +
  • hostname, e.g., 'localhost' or 'mydb.example.org'
  • +
  • IP address, e.g., '127.0.0.1' or '192.168.10.1'
  • +
  • dot - '.', i.e., use named pipes on windows systems
  • +
  • empty - '', disables this server
  • +
+
+

Note

+
+
phpMyAdmin supports connecting to MySQL servers reachable via IPv6 only.
+
To connect to an IPv6 MySQL server, enter its IPv6 address in this field.
+
+
+
+ +
+
+$cfg['Servers'][$i]['port']¶
+
+++ + + + + + +
Type:string
Default value:''
+

The port-number of your $i-th MySQL-server. Default is 3306 (leave +blank).

+
+

Note

+

If you use localhost as the hostname, MySQL ignores this port number +and connects with the socket, so if you want to connect to a port +different from the default port, use 127.0.0.1 or the real hostname +in $cfg['Servers'][$i]['host'].

+
+
+ +
+
+$cfg['Servers'][$i]['socket']¶
+
+++ + + + + + +
Type:string
Default value:''
+

The path to the socket to use. Leave blank for default. To determine +the correct socket, check your MySQL configuration or, using the +mysql command–line client, issue the status command. Among the +resulting information displayed will be the socket used.

+
+ +
+
+$cfg['Servers'][$i]['ssl']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Whether to enable SSL for the connection between phpMyAdmin and the MySQL server.

+

When using $cfg['Servers'][$i]['extension'] = 'mysql', +none of the remaining 'ssl...' configuration options apply.

+

We strongly recommend using $cfg['Servers'][$i]['extension'] = 'mysqli' +when using this option.

+
+ +
+
+$cfg['Servers'][$i]['ssl_key']¶
+
+++ + + + + + +
Type:string
Default value:NULL
+

Path to the key file when using SSL for connecting to the MySQL server.

+

For example:

+
$cfg['Servers'][$i]['ssl_key'] = '/etc/mysql/server-key.pem';
+
+
+
+ +
+
+$cfg['Servers'][$i]['ssl_cert']¶
+
+++ + + + + + +
Type:string
Default value:NULL
+

Path to the cert file when using SSL for connecting to the MySQL server.

+
+ +
+
+$cfg['Servers'][$i]['ssl_ca']¶
+
+++ + + + + + +
Type:string
Default value:NULL
+

Path to the CA file when using SSL for connecting to the MySQL server.

+
+ +
+
+$cfg['Servers'][$i]['ssl_ca_path']¶
+
+++ + + + + + +
Type:string
Default value:NULL
+

Directory containing trusted SSL CA certificates in PEM format.

+
+ +
+
+$cfg['Servers'][$i]['ssl_ciphers']¶
+
+++ + + + + + +
Type:string
Default value:NULL
+

List of allowable ciphers for SSL connections to the MySQL server.

+
+ +
+
+$cfg['Servers'][$i]['connect_type']¶
+
+++ + + + + + +
Type:string
Default value:'tcp'
+

What type connection to use with the MySQL server. Your options are +'socket' and 'tcp'. It defaults to tcp as that is nearly guaranteed +to be available on all MySQL servers, while sockets are not supported on +some platforms. To use the socket mode, your MySQL server must be on the +same machine as the Web server.

+
+ +
+
+$cfg['Servers'][$i]['extension']¶
+
+++ + + + + + +
Type:string
Default value:'mysqli'
+

What php MySQL extension to use for the connection. Valid options are:

+
+
mysql
+
The classic MySQL extension.
+
mysqli
+
The improved MySQL extension. This extension became available with PHP +5.0.0 and is the recommended way to connect to a server running MySQL +4.1.x or newer.
+
+
+ +
+
+$cfg['Servers'][$i]['compress']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Whether to use a compressed protocol for the MySQL server connection +or not (experimental).

+
+ +
+
+$cfg['Servers'][$i]['controlhost']¶
+
+++ + + + + + +
Type:string
Default value:''
+

Permits to use an alternate host to hold the configuration storage +data.

+
+ +
+
+$cfg['Servers'][$i]['controlport']¶
+
+++ + + + + + +
Type:string
Default value:''
+

Permits to use an alternate port to connect to the host that +holds the configuration storage.

+
+ +
+
+$cfg['Servers'][$i]['controluser']¶
+
+++ + + + + + +
Type:string
Default value:''
+
+ +
+
+$cfg['Servers'][$i]['controlpass']¶
+
+++ + + + + + +
Type:string
Default value:''
+

This special account is used for 2 distinct purposes: to make possible all +relational features (see $cfg['Servers'][$i]['pmadb']) and, +for a MySQL server running with --skip-show-database, to enable a +multi-user installation (HTTP or cookie +authentication mode).

+

When using HTTP or +cookie authentication modes (or ‘config’ authentication mode since phpMyAdmin +2.2.1), you need to supply the details of a MySQL account that has SELECT +privilege on the mysql.user (all columns except “Password”), mysql.db (all +columns) and mysql.tables_priv (all columns except “Grantor” and +“Timestamp”) tables. This account is used to check what databases the user +will see at login.

+

+Changed in version 2.2.5: those were called stduser and stdpass

+ +
+ +
+
+$cfg['Servers'][$i]['auth_type']¶
+
+++ + + + + + +
Type:string
Default value:'cookie'
+

Whether config or cookie or HTTP or signon authentication should be +used for this server.

+
    +
  • ‘config’ authentication ($auth_type = 'config') is the plain old +way: username and password are stored in config.inc.php.
  • +
  • ‘cookie’ authentication mode ($auth_type = 'cookie') as +introduced in 2.2.3 allows you to log in as any valid MySQL user with +the help of cookies. Username and password are stored in cookies +during the session and password is deleted when it ends. This can also +allow you to log in in arbitrary server if $cfg['AllowArbitraryServer'] enabled.
  • +
  • ‘http’ authentication (was +called ‘advanced’ in previous versions and can be written also as +‘http’) ($auth_type = 'http';') as introduced in 1.3.0 allows you to log in as any +valid MySQL user via HTTP-Auth.
  • +
  • ‘signon’ authentication mode ($auth_type = 'signon') as +introduced in 2.10.0 allows you to log in from prepared PHP session +data or using supplied PHP script. This is useful for implementing +single signon from another application. Sample way how to seed session +is in signon example: examples/signon.php. There is also +alternative example using OpenID - examples/openid.php and example +for scripts based solution - examples/signon-script.php. You need +to configure $cfg['Servers'][$i]['SignonSession'] or +$cfg['Servers'][$i]['SignonScript'] and +$cfg['Servers'][$i]['SignonURL'] to use this authentication +method.
  • +
+ +
+ +
+
+$cfg['Servers'][$i]['auth_http_realm']¶
+
+++ + + + + + +
Type:string
Default value:''
+

When using auth_type = http, this field allows to define a custom +HTTP Basic Auth Realm which will be displayed to the user. If not +explicitly specified in your configuration, a string combined of +“phpMyAdmin ” and either $cfg['Servers'][$i]['verbose'] or +$cfg['Servers'][$i]['host'] will be used.

+
+ +
+
+$cfg['Servers'][$i]['auth_swekey_config']¶
+
+++ + + + + + +
Type:string
Default value:''
+

The name of the file containing Swekey authentication mode ids and login names for hardware +authentication. Leave empty to deactivate this feature.

+
+ +
+
+$cfg['Servers'][$i]['user']¶
+
+++ + + + + + +
Type:string
Default value:'root'
+
+ +
+
+$cfg['Servers'][$i]['password']¶
+
+++ + + + + + +
Type:string
Default value:''
+

When using $cfg['Servers'][$i]['auth_type'] set to +‘config’, this is the user/password-pair which phpMyAdmin will use to +connect to the MySQL server. This user/password pair is not needed when +HTTP or cookie authentication is used +and should be empty.

+
+ +
+
+$cfg['Servers'][$i]['nopassword']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Allow attempt to log in without password when a login with password +fails. This can be used together with http authentication, when +authentication is done some other way and phpMyAdmin gets user name +from auth and uses empty password for connecting to MySQL. Password +login is still tried first, but as fallback, no password method is +tried.

+
+ +
+
+$cfg['Servers'][$i]['only_db']¶
+
+++ + + + + + +
Type:string or array
Default value:''
+

If set to a (an array of) database name(s), only this (these) +database(s) will be shown to the user. Since phpMyAdmin 2.2.1, +this/these database(s) name(s) may contain MySQL wildcards characters +(“_” and “%”): if you want to use literal instances of these +characters, escape them (I.E. use 'my\_db' and not 'my_db').

+

This setting is an efficient way to lower the server load since the +latter does not need to send MySQL requests to build the available +database list. But it does not replace the privileges rules of the +MySQL database server. If set, it just means only these databases +will be displayed but not that all other databases can’t be used.

+

An example of using more that one database:

+
$cfg['Servers'][$i]['only_db'] = array('db1', 'db2');
+
+
+

+Changed in version 4.0.0: Previous versions permitted to specify the display order of +the database names via this directive.

+
+ +
+
+$cfg['Servers'][$i]['hide_db']¶
+
+++ + + + + + +
Type:string
Default value:''
+

Regular expression for hiding some databases from unprivileged users. +This only hides them from listing, but a user is still able to access +them (using, for example, the SQL query area). To limit access, use +the MySQL privilege system. For example, to hide all databases +starting with the letter “a”, use

+
$cfg['Servers'][$i]['hide_db'] = '^a';
+
+
+

and to hide both “db1” and “db2” use

+
$cfg['Servers'][$i]['hide_db'] = '^(db1|db2)$';
+
+
+

More information on regular expressions can be found in the PCRE +pattern syntax portion +of the PHP reference manual.

+
+ +
+
+$cfg['Servers'][$i]['verbose']¶
+
+++ + + + + + +
Type:string
Default value:''
+

Only useful when using phpMyAdmin with multiple server entries. If +set, this string will be displayed instead of the hostname in the +pull-down menu on the main page. This can be useful if you want to +show only certain databases on your system, for example. For HTTP +auth, all non-US-ASCII characters will be stripped.

+
+ +
+
+$cfg['Servers'][$i]['pmadb']¶
+
+++ + + + + + +
Type:string
Default value:''
+

The name of the database containing the phpMyAdmin configuration +storage.

+

See the phpMyAdmin configuration storage section in this document to see the benefits of +this feature, and for a quick way of creating this database and the needed +tables.

+

If you are the only user of this phpMyAdmin installation, you can use your +current database to store those special tables; in this case, just put your +current database name in $cfg['Servers'][$i]['pmadb']. For a +multi-user installation, set this parameter to the name of your central +database containing the phpMyAdmin configuration storage.

+
+ +
+
+$cfg['Servers'][$i]['bookmarktable']¶
+
+++ + + + + + +
Type:string
Default value:''
+

Since release 2.2.0 phpMyAdmin allows users to bookmark queries. This +can be useful for queries you often run. To allow the usage of this +functionality:

+ +
+ +
+
+$cfg['Servers'][$i]['relation']¶
+
+++ + + + + + +
Type:string
Default value:''
+

Since release 2.2.4 you can describe, in a special ‘relation’ table, +which column is a key in another table (a foreign key). phpMyAdmin +currently uses this to:

+ +

The keys can be numeric or character.

+

To allow the usage of this functionality:

+
    +
  • set up $cfg['Servers'][$i]['pmadb'] and the phpMyAdmin configuration storage
  • +
  • put the relation table name in $cfg['Servers'][$i]['relation']
  • +
  • now as normal user open phpMyAdmin and for each one of your tables +where you want to use this feature, click Structure/Relation view/ +and choose foreign columns.
  • +
+
+

Note

+

In the current version, master_db must be the same as foreign_db. +Those columns have been put in future development of the cross-db +relations.

+
+
+ +
+
+$cfg['Servers'][$i]['table_info']¶
+
+++ + + + + + +
Type:string
Default value:''
+

Since release 2.3.0 you can describe, in a special ‘table_info’ +table, which column is to be displayed as a tool-tip when moving the +cursor over the corresponding key. This configuration variable will +hold the name of this special table. To allow the usage of this +functionality:

+ + +
+ +
+
+$cfg['Servers'][$i]['table_coords']¶
+
+++ + + + + + +
Type:string
Default value:''
+
+ +
+
+$cfg['Servers'][$i]['pdf_pages']¶
+
+++ + + + + + +
Type:string
Default value:''
+

Since release 2.3.0 you can have phpMyAdmin create PDF pages +showing the relations between your tables. To do this it needs two tables +“pdf_pages” (storing information about the available PDF pages) +and “table_coords” (storing coordinates where each table will be placed on +a PDF schema output). You must be using the “relation” feature.

+

To allow the usage of this functionality:

+ + +
+ +
+
+$cfg['Servers'][$i]['column_info']¶
+
+++ + + + + + +
Type:string
Default value:''
+

This part requires a content update! Since release 2.3.0 you can +store comments to describe each column for each table. These will then +be shown on the “printview”.

+

Starting with release 2.5.0, comments are consequently used on the table +property pages and table browse view, showing up as tool-tips above the +column name (properties page) or embedded within the header of table in +browse view. They can also be shown in a table dump. Please see the +relevant configuration directives later on.

+

Also new in release 2.5.0 is a MIME- transformation system which is also +based on the following table structure. See Transformations for +further information. To use the MIME- transformation system, your +column_info table has to have the three new columns ‘mimetype’, +‘transformation’, ‘transformation_options’.

+

To allow the usage of this functionality:

+
    +
  • set up $cfg['Servers'][$i]['pmadb'] and the phpMyAdmin configuration storage

    +
  • +
  • put the table name in $cfg['Servers'][$i]['column_info'] (e.g. +pma__column_info)

    +
  • +
  • to update your PRE-2.5.0 Column_comments Table use this: and +remember that the Variable in config.inc.php has been renamed from +$cfg['Servers'][$i]['column_comments'] to +$cfg['Servers'][$i]['column_info']

    +
    ALTER TABLE `pma__column_comments`
    +ADD `mimetype` VARCHAR( 255 ) NOT NULL,
    +ADD `transformation` VARCHAR( 255 ) NOT NULL,
    +ADD `transformation_options` VARCHAR( 255 ) NOT NULL;
    +
    +
    +
  • +
+
+ +
+
+$cfg['Servers'][$i]['history']¶
+
+++ + + + + + +
Type:string
Default value:''
+

Since release 2.5.0 you can store your SQL history, which means all +queries you entered manually into the phpMyAdmin interface. If you don’t +want to use a table-based history, you can use the JavaScript-based +history.

+

Using that, all your history items are deleted when closing the window. +Using $cfg['QueryHistoryMax'] you can specify an amount of +history items you want to have on hold. On every login, this list gets cut +to the maximum amount.

+

The query history is only available if JavaScript is enabled in +your browser.

+

To allow the usage of this functionality:

+ +
+ +
+
+$cfg['Servers'][$i]['recent']¶
+
+++ + + + + + +
Type:string
Default value:''
+

Since release 3.5.0 you can show recently used tables in the +navigation panel. It helps you to jump across table directly, without +the need to select the database, and then select the table. Using +$cfg['NumRecentTables'] you can configure the maximum number +of recent tables shown. When you select a table from the list, it will jump to +the page specified in $cfg['NavigationTreeDefaultTabTable'].

+

Without configuring the storage, you can still access the recently used tables, +but it will disappear after you logout.

+

To allow the usage of this functionality persistently:

+ +
+ +
+
+$cfg['Servers'][$i]['table_uiprefs']¶
+
+++ + + + + + +
Type:string
Default value:''
+

Since release 3.5.0 phpMyAdmin can be configured to remember several +things (sorted column $cfg['RememberSorting'], column order, +and column visibility from a database table) for browsing tables. Without +configuring the storage, these features still can be used, but the values will +disappear after you logout.

+

To allow the usage of these functionality persistently:

+ +
+ +
+
+$cfg['Servers'][$i]['users']¶
+
+++ + + + + + +
Type:string
Default value:''
+
+ +
+
+$cfg['Servers'][$i]['usergroups']¶
+
+++ + + + + + +
Type:string
Default value:''
+

Since release 4.1.0 you can create different user groups with menu items +attached to them. Users can be assigned to these groups and the logged in +user would only see menu items configured to the usergroup he is assigned to. +To do this it needs two tables “usergroups” (storing allowed menu items for each +user group) and “users” (storing users and their assignments to user groups).

+

To allow the usage of this functionality:

+ +
+ +
+
+$cfg['Servers'][$i]['navigationhiding']¶
+
+++ + + + + + +
Type:string
Default value:''
+

Since release 4.1.0 you can hide/show items in the navigation tree.

+

To allow the usage of this functionality:

+ +
+ +
+
+$cfg['Servers'][$i]['tracking']¶
+
+++ + + + + + +
Type:string
Default value:''
+

Since release 3.3.x a tracking mechanism is available. It helps you to +track every SQL command which is +executed by phpMyAdmin. The mechanism supports logging of data +manipulation and data definition statements. After enabling it you can +create versions of tables.

+

The creation of a version has two effects:

+
    +
  • phpMyAdmin saves a snapshot of the table, including structure and +indexes.
  • +
  • phpMyAdmin logs all commands which change the structure and/or data of +the table and links these commands with the version number.
  • +
+

Of course you can view the tracked changes. On the Tracking +page a complete report is available for every version. For the report you +can use filters, for example you can get a list of statements within a date +range. When you want to filter usernames you can enter * for all names or +you enter a list of names separated by ‘,’. In addition you can export the +(filtered) report to a file or to a temporary database.

+

To allow the usage of this functionality:

+ +
+ +
+
+$cfg['Servers'][$i]['tracking_version_auto_create']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Whether the tracking mechanism creates versions for tables and views +automatically.

+

If this is set to true and you create a table or view with

+
    +
  • CREATE TABLE ...
  • +
  • CREATE VIEW ...
  • +
+

and no version exists for it, the mechanism will create a version for +you automatically.

+
+ +
+
+$cfg['Servers'][$i]['tracking_default_statements']¶
+
+++ + + + + + +
Type:string
Default value:'CREATE TABLE,ALTER TABLE,DROP TABLE,RENAME TABLE,CREATE INDEX,DROP INDEX,INSERT,UPDATE,DELETE,TRUNCATE,REPLACE,CREATE VIEW,ALTER VIEW,DROP VIEW,CREATE DATABASE,ALTER DATABASE,DROP DATABASE'
+

Defines the list of statements the auto-creation uses for new +versions.

+
+ +
+
+$cfg['Servers'][$i]['tracking_add_drop_view']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Whether a DROP VIEW IF EXISTS statement will be added as first line to +the log when creating a view.

+
+ +
+
+$cfg['Servers'][$i]['tracking_add_drop_table']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Whether a DROP TABLE IF EXISTS statement will be added as first line +to the log when creating a table.

+
+ +
+
+$cfg['Servers'][$i]['tracking_add_drop_database']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Whether a DROP DATABASE IF EXISTS statement will be added as first +line to the log when creating a database.

+
+ +
+
+$cfg['Servers'][$i]['userconfig']¶
+
+++ + + + + + +
Type:string
Default value:''
+

Since release 3.4.x phpMyAdmin allows users to set most preferences by +themselves and store them in the database.

+

If you don’t allow for storing preferences in +$cfg['Servers'][$i]['pmadb'], users can still personalize +phpMyAdmin, but settings will be saved in browser’s local storage, or, it +is is unavailable, until the end of session.

+

To allow the usage of this functionality:

+ +
+ +
+
+$cfg['Servers'][$i]['designer_coords']¶
+
+++ + + + + + +
Type:string
Default value:''
+

Since release 2.10.0 a Designer interface is available; it permits to +visually manage the relations.

+

To allow the usage of this functionality:

+ +
+ +
+
+$cfg['Servers'][$i]['MaxTableUiprefs']¶
+
+++ + + + + + +
Type:integer
Default value:100
+

Maximum number of rows saved in +$cfg['Servers'][$i]['table_uiprefs'] table.

+

When tables are dropped or renamed, +$cfg['Servers'][$i]['table_uiprefs'] may contain invalid data +(referring to tables which no longer exist). We only keep this number of newest +rows in $cfg['Servers'][$i]['table_uiprefs'] and automatically +delete older rows.

+
+ +
+
+$cfg['Servers'][$i]['AllowRoot']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Whether to allow root access. This is just a shortcut for the +$cfg['Servers'][$i]['AllowDeny']['rules'] below.

+
+ +
+
+$cfg['Servers'][$i]['AllowNoPassword']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Whether to allow logins without a password. The default value of +false for this parameter prevents unintended access to a MySQL +server with was left with an empty password for root or on which an +anonymous (blank) user is defined.

+
+ +
+
+$cfg['Servers'][$i]['AllowDeny']['order']¶
+
+++ + + + + + +
Type:string
Default value:''
+

If your rule order is empty, then IP +authorization is disabled.

+

If your rule order is set to +'deny,allow' then the system applies all deny rules followed by +allow rules. Access is allowed by default. Any client which does not +match a Deny command or does match an Allow command will be allowed +access to the server.

+

If your rule order is set to 'allow,deny' +then the system applies all allow rules followed by deny rules. Access +is denied by default. Any client which does not match an Allow +directive or does match a Deny directive will be denied access to the +server.

+

If your rule order is set to 'explicit', authorization is +performed in a similar fashion to rule order ‘deny,allow’, with the +added restriction that your host/username combination must be +listed in the allow rules, and not listed in the deny rules. This +is the most secure means of using Allow/Deny rules, and was +available in Apache by specifying allow and deny rules without setting +any order.

+

Please also see $cfg['TrustedProxies'] for +detecting IP address behind proxies.

+
+ +
+
+$cfg['Servers'][$i]['AllowDeny']['rules']¶
+
+++ + + + + + +
Type:array of strings
Default value:array()
+

The general format for the rules is as such:

+
<'allow' | 'deny'> <username> [from] <ipmask>
+
+
+

If you wish to match all users, it is possible to use a '%' as a +wildcard in the username field.

+

There are a few shortcuts you can +use in the ipmask field as well (please note that those containing +SERVER_ADDRESS might not be available on all webservers):

+
'all' -> 0.0.0.0/0
+'localhost' -> 127.0.0.1/8
+'localnetA' -> SERVER_ADDRESS/8
+'localnetB' -> SERVER_ADDRESS/16
+'localnetC' -> SERVER_ADDRESS/24
+
+
+

Having an empty rule list is equivalent to either using 'allow % +from all' if your rule order is set to 'deny,allow' or 'deny % +from all' if your rule order is set to 'allow,deny' or +'explicit'.

+

For the IP address matching +system, the following work:

+
    +
  • xxx.xxx.xxx.xxx (an exact IP address)
  • +
  • xxx.xxx.xxx.[yyy-zzz] (an IP address range)
  • +
  • xxx.xxx.xxx.xxx/nn (CIDR, Classless Inter-Domain Routing type IP addresses)
  • +
+

But the following does not work:

+
    +
  • xxx.xxx.xxx.xx[yyy-zzz] (partial IP address range)
  • +
+

For IPv6 addresses, the following work:

+
    +
  • xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx (an exact IPv6 address)
  • +
  • xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:[yyyy-zzzz] (an IPv6 address range)
  • +
  • xxxx:xxxx:xxxx:xxxx/nn (CIDR, Classless Inter-Domain Routing type IPv6 addresses)
  • +
+

But the following does not work:

+
    +
  • xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xx[yyy-zzz] (partial IPv6 address range)
  • +
+
+ +
+
+$cfg['Servers'][$i]['SignonScript']¶
+
+++ + + + + + +
Type:string
Default value:''
+

Name of PHP script to be sourced and executed to obtain login +credentials. This is alternative approach to session based single +signon. The script needs to provide function +get_login_credentials which returns list of username and +password, accepting single parameter of existing username (can be +empty). See examples/signon-script.php for an example.

+
+ +
+
+$cfg['Servers'][$i]['SignonSession']¶
+
+++ + + + + + +
Type:string
Default value:''
+

Name of session which will be used for signon authentication method. +You should use something different than phpMyAdmin, because this +is session which phpMyAdmin uses internally. Takes effect only if +$cfg['Servers'][$i]['SignonScript'] is not configured.

+
+ +
+
+$cfg['Servers'][$i]['SignonURL']¶
+
+++ + + + + + +
Type:string
Default value:''
+

URL where user will be redirected +to log in for signon authentication method. Should be absolute +including protocol.

+
+ +
+
+$cfg['Servers'][$i]['LogoutURL']¶
+
+++ + + + + + +
Type:string
Default value:''
+

URL where user will be redirected +after logout (doesn’t affect config authentication method). Should be +absolute including protocol.

+
+ +
+
+$cfg['Servers'][$i]['StatusCacheDatabases']¶
+
+++ + + + + + +
Type:array of strings
Default value:array()
+

Enables caching of TABLE STATUS outputs for specific databases on +this server (in some cases TABLE STATUS can be very slow, so you +may want to cache it). APC is used (if the PHP extension is available, +if not, this setting is ignored silently). You have to provide +$cfg['Servers'][$i]['StatusCacheLifetime'].

+
+ +
+
+$cfg['Servers'][$i]['StatusCacheLifetime']¶
+
+++ + + + + + +
Type:integer
Default value:0
+

Lifetime in seconds of the TABLE STATUS cache if +$cfg['Servers'][$i]['StatusCacheDatabases'] is used.

+
+ +
+
+

Generic settings¶

+
+
+$cfg['ServerDefault']¶
+
+++ + + + + + +
Type:integer
Default value:1
+

If you have more than one server configured, you can set +$cfg['ServerDefault'] to any one of them to autoconnect to that +server when phpMyAdmin is started, or set it to 0 to be given a list +of servers without logging in.

+

If you have only one server configured, +$cfg['ServerDefault'] MUST be set to that server.

+
+ +
+
+$cfg['VersionCheck']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Enables check for latest versions using javascript on main phpMyAdmin +page.

+
+

Note

+

This setting can be adjusted by your vendor.

+
+
+ +
+
+$cfg['ProxyUrl']¶
+
+++ + + + + + +
Type:string
Default value:“”
+

The url of the proxy to be used when phpmyadmin needs to access the outside +intenet such as when retrieving the latest version info or submitting error +reports. You need this if the server where phpMyAdmin is installed does not +have direct access to the internet. +The format is: “hostname:portnumber”

+
+ +
+
+$cfg['ProxyUser']¶
+
+++ + + + + + +
Type:string
Default value:“”
+

The username for authenticating with the proxy. By default, no +authentication is performed. If a username is supplied, Basic +Authentication will be performed. No other types of authentication +are currently supported.

+
+ +
+
+$cfg['ProxyPass']¶
+
+++ + + + + + +
Type:string
Default value:“”
+

The password for authenticating with the proxy.

+
+ +
+
+$cfg['MaxDbList']¶
+
+++ + + + + + +
Type:integer
Default value:100
+

The maximum number of database names to be displayed in the main panel’s +database list.

+
+ +
+
+$cfg['MaxTableList']¶
+
+++ + + + + + +
Type:integer
Default value:250
+

The maximum number of table names to be displayed in the main panel’s +list (except on the Export page). This limit is also enforced in the +navigation panel when in Light mode.

+
+ +
+
+$cfg['ShowHint']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Whether or not to show hints (for example, hints when hovering over +table headers).

+
+ +
+
+$cfg['MaxCharactersInDisplayedSQL']¶
+
+++ + + + + + +
Type:integer
Default value:1000
+

The maximum number of characters when a SQL query is displayed. The +default limit of 1000 should be correct to avoid the display of tons of +hexadecimal codes that represent BLOBs, but some users have real +SQL queries that are longer than 1000 characters. Also, if a +query’s length exceeds this limit, this query is not saved in the history.

+
+ +
+
+$cfg['PersistentConnections']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Whether persistent connections should be used or not. Works with +following extensions:

+ +
+ +
+
+$cfg['ForceSSL']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Whether to force using https while accessing phpMyAdmin.

+
+

Note

+

In some setups (like separate SSL proxy or load balancer) you might +have to set $cfg['PmaAbsoluteUri'] for correct +redirection.

+
+
+ +
+
+$cfg['ExecTimeLimit']¶
+
+++ + + + + + +
Type:integer [number of seconds]
Default value:300
+

Set the number of seconds a script is allowed to run. If seconds is +set to zero, no time limit is imposed. This setting is used while +importing/exporting dump files but has +no effect when PHP is running in safe mode.

+
+ +
+
+$cfg['SessionSavePath']¶
+
+++ + + + + + +
Type:string
Default value:''
+

Path for storing session data (session_save_path PHP parameter).

+
+ +
+
+$cfg['MemoryLimit']¶
+
+++ + + + + + +
Type:string [number of bytes]
Default value:'-1'
+

Set the number of bytes a script is allowed to allocate. If set to +'-1', no limit is imposed.

+

This setting is used while importing/exporting dump files and at some other +places in phpMyAdmin so you definitely don’t want to put here a too low +value. It has no effect when PHP is running in safe mode.

+

You can also use any string as in php.ini, eg. ‘16M’. Ensure you +don’t omit the suffix (16 means 16 bytes!)

+
+ +
+
+$cfg['SkipLockedTables']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Mark used tables and make it possible to show databases with locked +tables (since MySQL 3.23.30).

+
+ +
+
+$cfg['ShowSQL']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Defines whether SQL queries +generated by phpMyAdmin should be displayed or not.

+
+ +
+
+$cfg['RetainQueryBox']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Defines whether the SQL query box +should be kept displayed after its submission.

+
+ +
+
+$cfg['CodemirrorEnable']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Defines whether to use a Javascript code editor for SQL query boxes. +CodeMirror provides syntax highlighting and line numbers. However, +middle-clicking for pasting the clipboard contents in some Linux +distributions (such as Ubuntu) is not supported by all browsers.

+
+ +
+
+$cfg['AllowUserDropDatabase']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Defines whether normal users (non-administrator) are allowed to delete +their own database or not. If set as false, the link Drop +Database will not be shown, and even a DROP DATABASE mydatabase will +be rejected. Quite practical for ISP ‘s with many customers.

+
+

Note

+

This limitation of SQL queries is not +as strict as when using MySQL privileges. This is due to nature of +SQL queries which might be quite +complicated. So this choice should be viewed as help to avoid accidental +dropping rather than strict privilege limitation.

+
+
+ +
+
+$cfg['Confirm']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Whether a warning (“Are your really sure...”) should be displayed when +you’re about to lose data.

+
+ +
+
+$cfg['UseDbSearch']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Define whether the “search string inside database” is enabled or not.

+
+ +
+
+$cfg['IgnoreMultiSubmitErrors']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Define whether phpMyAdmin will continue executing a multi-query +statement if one of the queries fails. Default is to abort execution.

+
+ +
+ + +
+

Main panel¶

+
+
+$cfg['ShowStats']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Defines whether or not to display space usage and statistics about +databases and tables. Note that statistics requires at least MySQL +3.23.3 and that, at this date, MySQL doesn’t return such information +for Berkeley DB tables.

+
+ +
+
+$cfg['ShowServerInfo']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Defines whether to display detailed server information on main page. +You can additionally hide more information by using +$cfg['Servers'][$i]['verbose'].

+
+ +
+
+$cfg['ShowPhpInfo']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+
+ +
+
+$cfg['ShowChgPassword']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+
+ +
+
+$cfg['ShowCreateDb']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Defines whether to display the PHP information and +Change password links and form for creating database or not at +the starting main (right) frame. This setting does not check MySQL commands +entered directly.

+

Please note that to block the usage of phpinfo() in scripts, you have to +put this in your php.ini:

+
disable_functions = phpinfo()
+
+
+

Also note that enabling the Change password link has no effect +with config authentication mode: because of the hard coded password value +in the configuration file, end users can’t be allowed to change their +passwords.

+
+ +
+
+

Database structure¶

+
+
+$cfg['ShowDbStructureCreation']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Defines whether the database structure page (tables list) has a +“Creation” column that displays when each table was created.

+
+ +
+
+$cfg['ShowDbStructureLastUpdate']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Defines whether the database structure page (tables list) has a “Last +update” column that displays when each table was last updated.

+
+ +
+
+$cfg['ShowDbStructureLastCheck']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Defines whether the database structure page (tables list) has a “Last +check” column that displays when each table was last checked.

+
+ +
+
+$cfg['HideStructureActions']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Defines whether the table structure actions are hidden under a “More” +drop-down.

+
+ +
+
+

Browse mode¶

+
+
+$cfg['TableNavigationLinksMode']¶
+
+++ + + + + + +
Type:string
Default value:'icons'
+

Defines whether the table navigation links contain 'icons', 'text' +or 'both'.

+
+ +
+
+$cfg['ShowAll']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Defines whether a user should be displayed a “Show all” button in browse +mode or not in all cases. By default it is shown only on small tables (less +than 500 rows) to avoid performance issues while getting too many rows.

+
+ +
+
+$cfg['MaxRows']¶
+
+++ + + + + + +
Type:integer
Default value:25
+

Number of rows displayed when browsing a result set and no LIMIT +clause is used. If the result set contains more rows, “Previous” and +“Next” links will be shown. Possible values: 25,50,100,250,500.

+
+ +
+
+$cfg['Order']¶
+
+++ + + + + + +
Type:string
Default value:'SMART'
+

Defines whether columns are displayed in ascending (ASC) order, in +descending (DESC) order or in a “smart” (SMART) order - I.E. +descending order for columns of type TIME, DATE, DATETIME and +TIMESTAMP, ascending order else- by default.

+
+ +
+
+$cfg['DisplayBinaryAsHex']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Defines whether the “Show binary contents as HEX” browse option is +ticked by default.

+
+ +
+
+$cfg['GridEditing']¶
+
+++ + + + + + +
Type:string
Default value:'double-click'
+

Defines which action (double-click or click) triggers grid +editing. Can be deactived with the disabled value.

+
+ +
+
+$cfg['SaveCellsAtOnce']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Defines whether or not to save all edited cells at once for grid +editing.

+
+ +
+
+

Editing mode¶

+
+
+$cfg['ProtectBinary']¶
+
+++ + + + + + +
Type:boolean or string
Default value:'blob'
+

Defines whether BLOB or BINARY columns are protected from +editing when browsing a table’s content. Valid values are:

+
    +
  • false to allow editing of all columns;
  • +
  • 'blob' to allow editing of all columns except BLOBS;
  • +
  • 'noblob' to disallow editing of all columns except BLOBS (the +opposite of 'blob');
  • +
  • 'all' to disallow editing of all BINARY or BLOB columns.
  • +
+
+ +
+
+$cfg['ShowFunctionFields']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Defines whether or not MySQL functions fields should be initially +displayed in edit/insert mode. Since version 2.10, the user can toggle +this setting from the interface.

+
+ +
+
+$cfg['ShowFieldTypesInDataEditView']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Defines whether or not type fields should be initially displayed in +edit/insert mode. The user can toggle this setting from the interface.

+
+ +
+
+$cfg['InsertRows']¶
+
+++ + + + + + +
Type:integer
Default value:2
+

Defines the maximum number of concurrent entries for the Insert page.

+
+ +
+
+$cfg['ForeignKeyMaxLimit']¶
+
+++ + + + + + +
Type:integer
Default value:100
+

If there are fewer items than this in the set of foreign keys, then a +drop-down box of foreign keys is presented, in the style described by +the $cfg['ForeignKeyDropdownOrder'] setting.

+
+ +
+
+$cfg['ForeignKeyDropdownOrder']¶
+
+++ + + + + + +
Type:array
Default value:array(‘content-id’, ‘id-content’)
+

For the foreign key drop-down fields, there are several methods of +display, offering both the key and value data. The contents of the +array should be one or both of the following strings: content-id, +id-content.

+
+ +
+
+

Export and import settings¶

+
+
+$cfg['ZipDump']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+
+ +
+
+$cfg['GZipDump']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+
+ +
+
+$cfg['BZipDump']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Defines whether to allow the use of zip/GZip/BZip2 compression when +creating a dump file

+
+ +
+
+$cfg['CompressOnFly']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Defines whether to allow on the fly compression for GZip/BZip2 +compressed exports. This doesn’t affect smaller dumps and allows users +to create larger dumps that won’t otherwise fit in memory due to php +memory limit. Produced files contain more GZip/BZip2 headers, but all +normal programs handle this correctly.

+
+ +
+
+$cfg['Export']¶
+
+++ + + + + + +
Type:array
Default value:array(...)
+

In this array are defined default parameters for export, names of +items are similar to texts seen on export page, so you can easily +identify what they mean.

+
+ +
+
+$cfg['Export']['method']¶
+
+++ + + + + + +
Type:string
Default value:'quick'
+

Defines how the export form is displayed when it loads. Valid values +are:

+
    +
  • quick to display the minimum number of options to configure
  • +
  • custom to display every available option to configure
  • +
  • custom-no-form same as custom but does not display the option +of using quick export
  • +
+
+ +
+
+$cfg['Import']¶
+
+++ + + + + + +
Type:array
Default value:array(...)
+

In this array are defined default parameters for import, names of +items are similar to texts seen on import page, so you can easily +identify what they mean.

+
+ +
+
+

Tabs display settings¶

+
+
+$cfg['TabsMode']¶
+
+++ + + + + + +
Type:string
Default value:'both'
+

Defines whether the menu tabs contain 'icons', 'text' or 'both'.

+
+ +
+
+$cfg['ActionLinksMode']¶
+
+++ + + + + + +
Type:string
Default value:'both'
+

If set to icons, will display icons instead of text for db and table +properties links (like Browse, Select, +Insert, ...). Can be set to 'both' +if you want icons AND text. When set to text, will only show text.

+
+ +
+
+$cfg['PropertiesNumColumns']¶
+
+++ + + + + + +
Type:integer
Default value:1
+

How many columns will be utilized to display the tables on the database +property view? When setting this to a value larger than 1, the type of the +database will be omitted for more display space.

+
+ +
+
+$cfg['DefaultTabServer']¶
+
+++ + + + + + +
Type:string
Default value:'index.php'
+

Defines the tab displayed by default on server view. Possible values:

+
    +
  • main.php (recommended for multi-user setups)
  • +
  • server_databases.php,
  • +
  • server_status.php
  • +
  • server_variables.php
  • +
  • server_privileges.php
  • +
+
+ +
+
+$cfg['DefaultTabDatabase']¶
+
+++ + + + + + +
Type:string
Default value:'db_structure.php'
+

Defines the tab displayed by default on database view. Possible +values:

+
    +
  • db_structure.php
  • +
  • db_sql.php
  • +
  • db_search.php.
  • +
+
+ +
+
+$cfg['DefaultTabTable']¶
+
+++ + + + + + +
Type:string
Default value:'sql.php'
+

Defines the tab displayed by default on table view. Possible values:

+
    +
  • tbl_structure.php
  • +
  • tbl_sql.php
  • +
  • tbl_select.php
  • +
  • tbl_change.php
  • +
  • sql.php
  • +
+
+ +
+
+

PDF Options¶

+
+
+$cfg['PDFPageSizes']¶
+
+++ + + + + + +
Type:array
Default value:array('A3', 'A4', 'A5', 'letter', 'legal')
+

Array of possible paper sizes for creating PDF pages.

+

You should never need to change this.

+
+ +
+
+$cfg['PDFDefaultPageSize']¶
+
+++ + + + + + +
Type:string
Default value:'A4'
+

Default page size to use when creating PDF pages. Valid values are any +listed in $cfg['PDFPageSizes'].

+
+ +
+
+

Languages¶

+
+
+$cfg['DefaultLang']¶
+
+++ + + + + + +
Type:string
Default value:'en'
+

Defines the default language to use, if not browser-defined or user- +defined. The corresponding language file needs to be in +locale/code/LC_MESSAGES/phpmyadmin.mo.

+
+ +
+
+$cfg['DefaultConnectionCollation']¶
+
+++ + + + + + +
Type:string
Default value:'utf8_general_ci'
+

Defines the default connection collation to use, if not user-defined. +See the MySQL documentation for list of possible values. This setting is +ignored when connected to Drizzle server.

+
+ +
+
+$cfg['Lang']¶
+
+++ + + + + + +
Type:string
Default value:not set
+

Force language to use. The corresponding language file needs to be in +locale/code/LC_MESSAGES/phpmyadmin.mo.

+
+ +
+
+$cfg['FilterLanguages']¶
+
+++ + + + + + +
Type:string
Default value:''
+

Limit list of available languages to those matching the given regular +expression. For example if you want only Czech and English, you should +set filter to '^(cs|en)'.

+
+ +
+
+$cfg['RecodingEngine']¶
+
+++ + + + + + +
Type:string
Default value:'auto'
+

You can select here which functions will be used for character set +conversion. Possible values are:

+
    +
  • auto - automatically use available one (first is tested iconv, then +recode)
  • +
  • iconv - use iconv or libiconv functions
  • +
  • recode - use recode_string function
  • +
  • mb - use mbstring extension
  • +
  • none - disable encoding conversion
  • +
+

Enabled charset conversion activates a pull-down menu in the Export +and Import pages, to choose the character set when exporting a file. +The default value in this menu comes from +$cfg['Export']['charset'] and $cfg['Import']['charset'].

+
+ +
+
+$cfg['IconvExtraParams']¶
+
+++ + + + + + +
Type:string
Default value:'//TRANSLIT'
+

Specify some parameters for iconv used in charset conversion. See +iconv documentation for details. By default +//TRANSLIT is used, so that invalid characters will be +transliterated.

+
+ +
+
+$cfg['AvailableCharsets']¶
+
+++ + + + + + +
Type:array
Default value:array(..._
+

Available character sets for MySQL conversion. You can add your own +(any of supported by recode/iconv) or remove these which you don’t +use. Character sets will be shown in same order as here listed, so if +you frequently use some of these move them to the top.

+
+ +
+
+

Web server settings¶

+
+
+$cfg['OBGzip']¶
+
+++ + + + + + +
Type:string/boolean
Default value:'auto'
+

Defines whether to use GZip output buffering for increased speed in +HTTP transfers. Set to +true/false for enabling/disabling. When set to ‘auto’ (string), +phpMyAdmin tries to enable output buffering and will automatically +disable it if your browser has some problems with buffering. IE6 with +a certain patch is known to cause data corruption when having enabled +buffering.

+
+ +
+
+$cfg['TrustedProxies']¶
+
+++ + + + + + +
Type:array
Default value:array()
+

Lists proxies and HTTP headers which are trusted for +$cfg['Servers'][$i]['AllowDeny']['order']. This list is by +default empty, you need to fill in some trusted proxy servers if you +want to use rules for IP addresses behind proxy.

+

The following example specifies that phpMyAdmin should trust a +HTTP_X_FORWARDED_FOR (X -Forwarded-For) header coming from the proxy +1.2.3.4:

+
$cfg['TrustedProxies'] = array('1.2.3.4' => 'HTTP_X_FORWARDED_FOR');
+
+
+

The $cfg['Servers'][$i]['AllowDeny']['rules'] directive uses the +client’s IP address as usual.

+
+ +
+
+$cfg['GD2Available']¶
+
+++ + + + + + +
Type:string
Default value:'auto'
+

Specifies whether GD >= 2 is available. If yes it can be used for MIME +transformations. Possible values are:

+
    +
  • auto - automatically detect
  • +
  • yes - GD 2 functions can be used
  • +
  • no - GD 2 function cannot be used
  • +
+
+ +
+
+$cfg['CheckConfigurationPermissions']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

We normally check the permissions on the configuration file to ensure +it’s not world writable. However, phpMyAdmin could be installed on a +NTFS filesystem mounted on a non-Windows server, in which case the +permissions seems wrong but in fact cannot be detected. In this case a +sysadmin would set this parameter to false.

+
+ +
+
+$cfg['LinkLengthLimit']¶
+
+++ + + + + + +
Type:integer
Default value:1000
+

Limit for length of URL in links. When length would be above this +limit, it is replaced by form with button. This is required as some web +servers (IIS) have problems with long URL .

+
+ +
+
+$cfg['CSPAllow']¶
+
+++ + + + + + +
Type:string
Default value:''
+

Additional string to include in allowed script and image sources in Content +Security Policy header.

+

This can be useful when you want to include some external javascript files +in config.footer.inc.php or config.header.inc.php, which +would be normally not allowed by Content Security Policy.

+

To allow some sites, just list them within the string:

+
$cfg['CSPAllow'] = 'example.com example.net';
+
+
+

+New in version 4.0.4.

+
+ +
+
+$cfg['DisableMultiTableMaintenance']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

In the database Structure page, it’s possible to mark some tables then +choose an operation like optimizing for many tables. This can slow +down a server; therefore, setting this to true prevents this kind +of multiple maintenance operation.

+
+ +
+
+

Theme settings¶

+
+
+$cfg['NaviWidth']¶
+
+++ + + + + + +
Type:integer
Default value:
+

Navigation panel width in pixels. See +themes/themename/layout.inc.php.

+
+ +
+
+$cfg['NaviBackground']¶
+
+++ + + + + + +
Type:string [CSS color for background]
Default value:
+
+ +
+
+$cfg['MainBackground']¶
+
+++ + + + + + +
Type:string [CSS color for background]
Default value:
+

The background styles used for both the frames. See +themes/themename/layout.inc.php.

+
+ +
+
+$cfg['NaviPointerBackground']¶
+
+++ + + + + + +
Type:string [CSS color for background]
Default value:
+
+ +
+
+$cfg['NaviPointerColor']¶
+
+++ + + + + + +
Type:string [CSS color]
Default value:
+

The style used for the pointer in the navigation panel. See +themes/themename/layout.inc.php.

+
+ +
+
+$cfg['Border']¶
+
+++ + + + + + +
Type:integer
Default value:
+

The size of a table’s border. See themes/themename/layout.inc.php.

+
+ +
+
+$cfg['ThBackground']¶
+
+++ + + + + + +
Type:string [CSS color for background]
Default value:
+
+ +
+
+$cfg['ThColor']¶
+
+++ + + + + + +
Type:string [CSS color]
Default value:
+

The style used for table headers. See +themes/themename/layout.inc.php.

+
+ +
+
+$cfg['BgOne']¶
+
+++ + + + + + +
Type:string [CSS color]
Default value:
+

The color (HTML) #1 for table rows. See +themes/themename/layout.inc.php.

+
+ +
+
+$cfg['BgTwo']¶
+
+++ + + + + + +
Type:string [CSS color]
Default value:
+

The color (HTML) #2 for table rows. See +themes/themename/layout.inc.php.

+
+ +
+
+$cfg['BrowsePointerBackground']¶
+
+++ + + + + + +
Type:string [CSS color]
Default value:
+
+ +
+
+$cfg['BrowsePointerColor']¶
+
+++ + + + + + +
Type:string [CSS color]
Default value:
+
+ +
+
+$cfg['BrowseMarkerBackground']¶
+
+++ + + + + + +
Type:string [CSS color]
Default value:
+
+ +
+
+$cfg['BrowseMarkerColor']¶
+
+++ + + + + + +
Type:string [CSS color]
Default value:
+

The colors (HTML) uses for the pointer and the marker in browse mode. +The former feature highlights the row over which your mouse is passing +and the latter lets you visually mark/unmark rows by clicking on the +corresponding checkbox. Highlighting / marking a column is done by +hovering over / clicking the column’s header (outside of the text). +See themes/themename/layout.inc.php.

+
+ +
+
+$cfg['FontFamily']¶
+
+++ + + + + + +
Type:string
Default value:
+

You put here a valid CSS font family value, for example arial, sans- +serif. See themes/themename/layout.inc.php.

+
+ +
+
+$cfg['FontFamilyFixed']¶
+
+++ + + + + + +
Type:string
Default value:
+

You put here a valid CSS font family value, for example monospace. +This one is used in textarea. See themes/themename/layout.inc.php.

+
+ +
+
+

Design customization¶

+
+
+$cfg['NavigationTreePointerEnable']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

A value of true activates the navi pointer.

+
+ +
+
+$cfg['BrowsePointerEnable']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Whether to activate the browse pointer or not.

+
+ +
+
+$cfg['BrowseMarkerEnable']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Whether to activate the browse marker or not.

+
+ +
+
+$cfg['LimitChars']¶
+
+++ + + + + + +
Type:integer
Default value:50
+

Maximum number of characters shown in any non-numeric field on browse +view. Can be turned off by a toggle button on the browse page.

+
+ +
+ +
+++ + + + + + +
Type:string
Default value:'left'
+

Defines the place where table row links (Edit, Copy, Delete) would be +put when tables contents are displayed (you may have them displayed at +the left side, right side, both sides or nowhere). “left” and “right” +are parsed as “top” and “bottom” with vertical display mode.

+
+ +
+
+$cfg['DefaultDisplay']¶
+
+++ + + + + + +
Type:string
Default value:'horizonta'
+

There are 3 display modes: horizontal, horizontalflipped and vertical. +Define which one is displayed by default. The first mode displays each +row on a horizontal line, the second rotates the headers by 90 +degrees, so you can use descriptive headers even though columns only +contain small values and still print them out. The vertical mode sorts +each row on a vertical lineup.

+
+ +
+
+$cfg['RememberSorting']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

If enabled, remember the sorting of each table when browsing them.

+
+ +
+
+$cfg['HeaderFlipType']¶
+
+++ + + + + + +
Type:string
Default value:'auto'
+

The HeaderFlipType can be set to ‘auto’, ‘css’ or ‘fake’. When using +‘css’ the rotation of the header for horizontalflipped is done via +CSS. The CSS transformation currently works only in Internet +Explorer.If set to ‘fake’ PHP does the transformation for you, but of +course this does not look as good as CSS. The ‘auto’ option enables +CSS transformation when browser supports it and use PHP based one +otherwise.

+
+ +
+
+$cfg['ShowBrowseComments']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+
+ +
+
+$cfg['ShowPropertyComments']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

By setting the corresponding variable to true you can enable the +display of column comments in Browse or Property display. In browse +mode, the comments are shown inside the header. In property mode, +comments are displayed using a CSS-formatted dashed-line below the +name of the column. The comment is shown as a tool-tip for that +column.

+
+ +
+
+

Text fields¶

+
+
+$cfg['CharEditing']¶
+
+++ + + + + + +
Type:string
Default value:'input'
+

Defines which type of editing controls should be used for CHAR and +VARCHAR columns. Possible values are:

+
    +
  • input - this allows to limit size of text to size of columns in MySQL, +but has problems with newlines in columns
  • +
  • textarea - no problems with newlines in columns, but also no length +limitations
  • +
+
+ +
+
+$cfg['MinSizeForInputField']¶
+
+++ + + + + + +
Type:integer
Default value:4
+

Defines the minimum size for input fields generated for CHAR and +VARCHAR columns.

+
+ +
+
+$cfg['MaxSizeForInputField']¶
+
+++ + + + + + +
Type:integer
Default value:60
+

Defines the maximum size for input fields generated for CHAR and +VARCHAR columns.

+
+ +
+
+$cfg['TextareaCols']¶
+
+++ + + + + + +
Type:integer
Default value:40
+
+ +
+
+$cfg['TextareaRows']¶
+
+++ + + + + + +
Type:integer
Default value:15
+
+ +
+
+$cfg['CharTextareaCols']¶
+
+++ + + + + + +
Type:integer
Default value:40
+
+ +
+
+$cfg['CharTextareaRows']¶
+
+++ + + + + + +
Type:integer
Default value:2
+

Number of columns and rows for the textareas. This value will be +emphasized (*2) for SQL query +textareas and (*1.25) for SQL +textareas inside the query window.

+

The Char* values are used for CHAR +and VARCHAR editing (if configured via $cfg['CharEditing']).

+
+ +
+
+$cfg['LongtextDoubleTextarea']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Defines whether textarea for LONGTEXT columns should have double size.

+
+ +
+
+$cfg['TextareaAutoSelect']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Defines if the whole textarea of the query box will be selected on +click.

+
+ +
+
+

SQL query box settings¶

+
+
+$cfg['SQLQuery']['Edit']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Whether to display an edit link to change a query in any SQL Query +box.

+
+ +
+
+$cfg['SQLQuery']['Explain']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Whether to display a link to explain a SELECT query in any SQL Query +box.

+
+ +
+
+$cfg['SQLQuery']['ShowAsPHP']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Whether to display a link to wrap a query in PHP code in any SQL Query +box.

+
+ +
+
+$cfg['SQLQuery']['Validate']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Whether to display a link to validate a query in any SQL Query box.

+
+

See also

+

$cfg['SQLValidator']

+
+
+ +
+
+$cfg['SQLQuery']['Refresh']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Whether to display a link to refresh a query in any SQL Query box.

+
+ +
+
+

Web server upload/save/import directories¶

+
+
+$cfg['UploadDir']¶
+
+++ + + + + + +
Type:string
Default value:''
+

The name of the directory where SQL files have been uploaded by +other means than phpMyAdmin (for example, ftp). Those files are available +under a drop-down box when you click the database or table name, then the +Import tab.

+

If +you want different directory for each user, %u will be replaced with +username.

+

Please note that the file names must have the suffix ”.sql” +(or ”.sql.bz2” or ”.sql.gz” if support for compressed formats is +enabled).

+

This feature is useful when your file is too big to be +uploaded via HTTP, or when file +uploads are disabled in PHP.

+
+

Note

+

If PHP is running in safe mode, this directory must be owned by the same +user as the owner of the phpMyAdmin scripts. See also 1.16 I cannot upload big dump files (memory, HTTP or timeout problems). for +alternatives.

+
+
+ +
+
+$cfg['SaveDir']¶
+
+++ + + + + + +
Type:string
Default value:''
+

The name of the directory where dumps can be saved.

+

If you want different directory for each user, %u will be replaced with +username.

+

Please note that the directory must exist and has to be writable for +the user running webserver.

+
+

Note

+

If PHP is running in safe mode, this directory must be owned by the same +user as the owner of the phpMyAdmin scripts.

+
+
+ +
+
+$cfg['TempDir']¶
+
+++ + + + + + +
Type:string
Default value:''
+

The name of the directory where temporary files can be stored.

+

This is needed for importing ESRI Shapefiles, see 6.30 Import: How can I import ESRI Shapefiles? and to +work around limitations of open_basedir for uploaded files, see +1.11 I get an ‘open_basedir restriction’ while uploading a file from the query box..

+

If the directory where phpMyAdmin is installed is +subject to an open_basedir restriction, you need to create a +temporary directory in some directory accessible by the web server. +However for security reasons, this directory should be outside the +tree published by webserver. If you cannot avoid having this directory +published by webserver, place at least an empty index.html file +there, so that directory listing is not possible.

+

This directory should have as strict permissions as possible as the only +user required to access this directory is the one who runs the webserver. +If you have root privileges, simply make this user owner of this directory +and make it accessible only by it:

+
chown www-data:www-data tmp
+chmod 700 tmp
+
+
+

If you cannot change owner of the directory, you can achieve a similar +setup using ACL:

+
chmod 700 tmp
+setfacl -m "g:www-data:rwx" tmp
+setfacl -d -m "g:www-data:rwx" tmp
+
+
+

If neither of above works for you, you can still make the directory +chmod 777, but it might impose risk of other users on system +reading and writing data in this directory.

+
+ +
+
+

Various display setting¶

+
+
+$cfg['ShowDisplayDirection']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Defines whether or not type display direction option is shown when +browsing a table.

+
+ +
+
+$cfg['RepeatCells']¶
+
+++ + + + + + +
Type:integer
Default value:100
+

Repeat the headers every X cells, or 0 to deactivate.

+
+ +
+
+$cfg['EditInWindow']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+
+ +
+
+$cfg['QueryWindowWidth']¶
+
+++ + + + + + +
Type:integer
Default value:550
+
+ +
+
+$cfg['QueryWindowHeight']¶
+
+++ + + + + + +
Type:integer
Default value:310
+
+ +
+
+$cfg['QueryHistoryDB']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+
+ +
+
+$cfg['QueryWindowDefTab']¶
+
+++ + + + + + +
Type:string
Default value:'sql'
+
+ +
+
+$cfg['QueryHistoryMax']¶
+
+++ + + + + + +
Type:integer
Default value:25
+

All those variables affect the query window feature. A SQL link or +icon is always displayed in the navigation panel. If JavaScript is enabled +in your browser, a click on this opens a distinct query window, which is a +direct interface to enter SQL queries. Otherwise, the right panel +changes to display a query box.

+

The size of this query window can be customized with +$cfg['QueryWindowWidth'] and +$cfg['QueryWindowHeight'] - both integers for the size in +pixels. Note that normally, those parameters will be modified in +layout.inc.php` for the theme you are using.

+

If $cfg['EditInWindow'] is set to true, a click on [Edit] +from the results page (in the Showing Rows section) opens the +query window and puts the current query inside it. If set to false, +clicking on the link puts the SQL query +in the right panel’s query box.

+

If $cfg['QueryHistoryDB'] is set to true, all your +Queries are logged to a table, which has to be created by you (see +$cfg['Servers'][$i]['history']). If set to false, all your +queries will be appended to the form, but only as long as your window is +opened they remain saved.

+

When using the JavaScript based query window, it will always get updated +when you click on a new table/db to browse and will focus if you click on +Edit SQL after using a query. You can suppress updating the +query window by checking the box Do not overwrite this query +from outside the window below the query textarea. Then you can browse +tables/databases in the background without losing the contents of the +textarea, so this is especially useful when composing a query with tables +you first have to look in. The checkbox will get automatically checked +whenever you change the contents of the textarea. Please uncheck the button +whenever you definitely want the query window to get updated even though +you have made alterations.

+

If $cfg['QueryHistoryDB'] is set to true you can +specify the amount of saved history items using +$cfg['QueryHistoryMax'].

+

The query window also has a custom tabbed look to group the features. +Using the variable $cfg['QueryWindowDefTab'] you can +specify the default tab to be used when opening the query window. It can be +set to either sql, files, history or full.

+
+ +
+
+$cfg['BrowseMIME']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Enable Transformations.

+
+ +
+
+$cfg['MaxExactCount']¶
+
+++ + + + + + +
Type:integer
Default value:0
+

For InnoDB tables, determines for how large tables phpMyAdmin should +get the exact row count using SELECT COUNT. If the approximate row +count as returned by SHOW TABLE STATUS is smaller than this value, +SELECT COUNT will be used, otherwise the approximate count will be +used.

+
+ +
+
+$cfg['MaxExactCountViews']¶
+
+++ + + + + + +
Type:integer
Default value:0
+

For VIEWs, since obtaining the exact count could have an impact on +performance, this value is the maximum to be displayed, using a +SELECT COUNT ... LIMIT. Setting this to 0 bypasses any row +counting.

+
+ +
+
+$cfg['NaturalOrder']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Sorts database and table names according to natural order (for +example, t1, t2, t10). Currently implemented in the navigation panel +and in Database view, for the table list.

+
+ +
+
+$cfg['InitialSlidersState']¶
+
+++ + + + + + +
Type:string
Default value:'closed'
+

If set to 'closed', the visual sliders are initially in a closed +state. A value of 'open' does the reverse. To completely disable +all visual sliders, use 'disabled'.

+
+ +
+
+$cfg['UserprefsDisallow']¶
+
+++ + + + + + +
Type:array
Default value:array()
+

Contains names of configuration options (keys in $cfg array) that +users can’t set through user preferences. For possible values, refer +to libraries/config/user_preferences.forms.php.

+
+ +
+
+$cfg['UserprefsDeveloperTab']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Activates in the user preferences a tab containing options for +developers of phpMyAdmin.

+
+ +
+
+

Page titles¶

+
+
+$cfg['TitleTable']¶
+
+++ + + + + + +
Type:string
Default value:'@HTTP_HOST@ / @VSERVER@ / @DATABASE@ / @TABLE@ | @PHPMYADMIN@'
+
+ +
+
+$cfg['TitleDatabase']¶
+
+++ + + + + + +
Type:string
Default value:'@HTTP_HOST@ / @VSERVER@ / @DATABASE@ | @PHPMYADMIN@'
+
+ +
+
+$cfg['TitleServer']¶
+
+++ + + + + + +
Type:string
Default value:'@HTTP_HOST@ / @VSERVER@ | @PHPMYADMIN@'
+
+ +
+
+$cfg['TitleDefault']¶
+
+++ + + + + + +
Type:string
Default value:'@HTTP_HOST@ | @PHPMYADMIN@'
+

Allows you to specify window’s title bar. You can use 6.27 What format strings can I use?.

+
+ +
+
+

Theme manager settings¶

+
+
+$cfg['ThemePath']¶
+
+++ + + + + + +
Type:string
Default value:'./themes'
+

If theme manager is active, use this as the path of the subdirectory +containing all the themes.

+
+ +
+
+$cfg['ThemeManager']¶
+
+++ + + + + + +
Type:boolean
Default value:true
+

Enables user-selectable themes. See 2.7 Using and creating themes.

+
+ +
+
+$cfg['ThemeDefault']¶
+
+++ + + + + + +
Type:string
Default value:'pmahomme'
+

The default theme (a subdirectory under $cfg['ThemePath']).

+
+ +
+
+$cfg['ThemePerServer']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Whether to allow different theme for each server.

+
+ +
+
+

Default queries¶

+
+
+$cfg['DefaultQueryTable']¶
+
+++ + + + + + +
Type:string
Default value:'SELECT * FROM @TABLE@ WHERE 1'
+
+ +
+
+$cfg['DefaultQueryDatabase']¶
+
+++ + + + + + +
Type:string
Default value:''
+

Default queries that will be displayed in query boxes when user didn’t +specify any. You can use standard 6.27 What format strings can I use?.

+
+ +
+
+

SQL validator settings¶

+
+
+$cfg['SQLValidator']¶
+
+++ + + + + + +
Type:array
Default value:array(...)
+
+ +
+
+$cfg['SQLValidator']['use']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

phpMyAdmin now supports use of the Mimer SQL Validator service, as originally +published on Slashdot. For +help in setting up your system to use the service, see the +6.14 How do I set up the SQL Validator?.

+
+ +
+
+$cfg['SQLValidator']['username']¶
+
+++ + + + + + +
Type:string
Default value:''
+
+ +
+
+$cfg['SQLValidator']['password']¶
+
+++ + + + + + +
Type:string
Default value:''
+

The SOAP service allows you to log in with anonymous and any password, +so we use those by default. Instead, if you have an account with them, you +can put your login details here, and it will be used in place of the +anonymous login.

+
+ +
+
+

MySQL settings¶

+
+
+$cfg['DefaultFunctions']¶
+
+++ + + + + + +
Type:array
Default value:array(...)
+

Functions selected by default when inserting/changing row, Functions +are defined for meta types as (FUNC_NUMBER, FUNC_DATE, FUNC_CHAR, +FUNC_SPATIAL, FUNC_UUID) and for first_timestamp, which is used +for first timestamp column in table.

+
+ +
+
+

Developer¶

+
+

Warning

+

These settings might have huge effect on performance or security.

+
+
+
+$cfg['DBG']¶
+
+++ + + + + + +
Type:array
Default value:array(...)
+
+ +
+
+$cfg['DBG']['sql']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Enable logging queries and execution times to be +displayed in the bottom of main page (right frame).

+
+ +
+
+$cfg['DBG']['demo']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Enable to let server present itself as demo server. +This is used for <http://demo.phpmyadmin.net/>.

+
+ +
+
+$cfg['Error_Handler']['display']¶
+
+++ + + + + + +
Type:boolean
Default value:false
+

Whether to display errors from PHP or not.

+
+ +
+
+ + +
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/phpMyAdmin/doc/html/copyright.html b/phpMyAdmin/doc/html/copyright.html new file mode 100644 index 0000000..88af155 --- /dev/null +++ b/phpMyAdmin/doc/html/copyright.html @@ -0,0 +1,134 @@ + + + + + + + + + + Copyright — phpMyAdmin 4.1.7 documentation + + + + + + + + + + + + + + + + +
+
+
+
+ + + + +
+
+
+
+
+

Previous topic

+

Distributing and packaging phpMyAdmin

+

Next topic

+

Credits

+

This Page

+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/phpMyAdmin/doc/html/credits.html b/phpMyAdmin/doc/html/credits.html new file mode 100644 index 0000000..b1a1782 --- /dev/null +++ b/phpMyAdmin/doc/html/credits.html @@ -0,0 +1,684 @@ + + + + + + + + + + Credits — phpMyAdmin 4.1.7 documentation + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Credits¶

+
+

Credits, in chronological order¶

+
    +
  • Tobias Ratschiller <tobias_at_ratschiller.com>
      +
    • creator of the phpmyadmin project
    • +
    • maintainer from 1998 to summer 2000
    • +
    +
  • +
  • Marc Delisle <marc_at_infomarc.info>
      +
    • multi-language version in December 1998
    • +
    • various fixes and improvements
    • +
    • SQL analyser (most of it)
    • +
    • current project maintainer
    • +
    • maintains content on our website
    • +
    +
  • +
  • Olivier Müller <om_at_omnis.ch>
      +
    • started SourceForge phpMyAdmin project in March 2001
    • +
    • sync’ed different existing CVS trees with new features and bugfixes
    • +
    • multi-language improvements, dynamic language selection
    • +
    • many bugfixes and improvements
    • +
    +
  • +
  • Loïc Chapeaux <lolo_at_phpheaven.net>
      +
    • rewrote and optimized javascript, DHTML and DOM stuff
    • +
    • rewrote the scripts so they fit the PEAR coding standards and +generate XHTML1.0 and CSS2 compliant codes
    • +
    • improved the language detection system
    • +
    • many bugfixes and improvements
    • +
    +
  • +
  • Robin Johnson <robbat2_at_users.sourceforge.net>
      +
    • database maintenance controls
    • +
    • table type code
    • +
    • Host authentication IP Allow/Deny
    • +
    • DB-based configuration (Not completed)
    • +
    • SQL parser and pretty-printer
    • +
    • SQL validator
    • +
    • many bugfixes and improvements
    • +
    +
  • +
  • Armel Fauveau <armel.fauveau_at_globalis-ms.com>
      +
    • bookmarks feature
    • +
    • multiple dump feature
    • +
    • gzip dump feature
    • +
    • zip dump feature
    • +
    +
  • +
  • Geert Lund <glund_at_silversoft.dk>
      +
    • various fixes
    • +
    • moderator of the phpMyAdmin former users forum at phpwizard.net
    • +
    +
  • +
  • Korakot Chaovavanich <korakot_at_iname.com>
      +
    • “insert as new row” feature
    • +
    +
  • +
  • Pete Kelly <webmaster_at_trafficg.com>
      +
    • rewrote and fix dump code
    • +
    • bugfixes
    • +
    +
  • +
  • Steve Alberty <alberty_at_neptunlabs.de>
      +
    • rewrote dump code for PHP4
    • +
    • mySQL table statistics
    • +
    • bugfixes
    • +
    +
  • +
  • Benjamin Gandon <gandon_at_isia.cma.fr>
      +
    • main author of the version 2.1.0.1
    • +
    • bugfixes
    • +
    +
  • +
  • Alexander M. Turek <me_at_derrabus.de>
      +
    • MySQL 4.0 / 4.1 / 5.0 compatibility
    • +
    • abstract database interface (PMA_DBI) with MySQLi support
    • +
    • privileges administration
    • +
    • XML exports
    • +
    • various features and fixes
    • +
    • German language file updates
    • +
    +
  • +
  • Mike Beck <mike.beck_at_web.de>
      +
    • automatic joins in QBE
    • +
    • links column in printview
    • +
    • Relation view
    • +
    +
  • +
  • Michal ÄŒihaÅ™ <michal_at_cihar.com>
      +
    • enhanced index creation/display feature
    • +
    • feature to use a different charset for HTML than for MySQL
    • +
    • improvements of export feature
    • +
    • various features and fixes
    • +
    • Czech language file updates
    • +
    • created current website for phpMyAdmin
    • +
    +
  • +
  • Christophe Gesché from the “MySQL Form Generator for PHPMyAdmin” +(http://sf.net/projects/phpmysqlformgen/)
      +
    • suggested the patch for multiple table printviews
    • +
    +
  • +
  • Garvin Hicking <me_at_supergarv.de>
      +
    • built the patch for vertical display of table rows
    • +
    • built the Javascript based Query window + SQL history
    • +
    • Improvement of column/db comments
    • +
    • (MIME)-Transformations for columns
    • +
    • Use custom alias names for Databases in left frame
    • +
    • hierarchical/nested table display
    • +
    • PDF-scratchboard for WYSIWYG- +distribution of PDF relations
    • +
    • new icon sets
    • +
    • vertical display of column properties page
    • +
    • some bugfixes, features, support, German language additions
    • +
    +
  • +
  • Yukihiro Kawada <kawada_at_den.fujifilm.co.jp>
      +
    • japanese kanji encoding conversion feature
    • +
    +
  • +
  • Piotr Roszatycki <d3xter_at_users.sourceforge.net> and Dan Wilson
      +
    • the Cookie authentication mode
    • +
    +
  • +
  • Axel Sander <n8falke_at_users.sourceforge.net>
      +
    • table relation-links feature
    • +
    +
  • +
  • Maxime Delorme <delorme.maxime_at_free.fr> +
  • +
  • Olof Edlund <olof.edlund_at_upright.se>
      +
    • SQL validator server
    • +
    +
  • +
  • Ivan R. Lanin <ivanlanin_at_users.sourceforge.net>
      +
    • phpMyAdmin logo (until June 2004)
    • +
    +
  • +
  • Mike Cochrane <mike_at_graftonhall.co.nz>
      +
    • blowfish library from the Horde project (withdrawn in release 4.0)
    • +
    +
  • +
  • Marcel Tschopp <ne0x_at_users.sourceforge.net>
      +
    • mysqli support
    • +
    • many bugfixes and improvements
    • +
    +
  • +
  • Nicola Asuni (Tecnick.com) +
  • +
  • Michael Keck <mkkeck_at_users.sourceforge.net>
      +
    • redesign for 2.6.0
    • +
    • phpMyAdmin sailboat logo (June 2004)
    • +
    +
  • +
  • Mathias Landhäußer
      +
    • Representation at conferences
    • +
    +
  • +
  • Sebastian Mendel <cybot_tm_at_users.sourceforge.net>
      +
    • interface improvements
    • +
    • various bugfixes
    • +
    +
  • +
  • Ivan A Kirillov
      +
    • new relations Designer
    • +
    +
  • +
  • Raj Kissu Rajandran (Google Summer of Code 2008)
      +
    • BLOBstreaming support (withdrawn in release 4.0)
    • +
    +
  • +
  • Piotr Przybylski (Google Summer of Code 2008, 2010 and 2011)
      +
    • improved setup script
    • +
    • user preferences
    • +
    • Drizzle support
    • +
    +
  • +
  • Derek Schaefer (Google Summer of Code 2009)
      +
    • Improved the import system
    • +
    +
  • +
  • Alexander Rutkowski (Google Summer of Code 2009)
      +
    • Tracking mechanism
    • +
    +
  • +
  • Zahra Naeem (Google Summer of Code 2009)
      +
    • Synchronization feature (removed in release 4.0)
    • +
    +
  • +
  • Tomáš Srnka (Google Summer of Code 2009)
      +
    • Replication support
    • +
    +
  • +
  • Muhammad Adnan (Google Summer of Code 2010)
      +
    • Relation schema export to multiple formats
    • +
    +
  • +
  • Lori Lee (Google Summer of Code 2010)
      +
    • User interface improvements
    • +
    • ENUM/SET editor
    • +
    • Simplified interface for export/import
    • +
    +
  • +
  • Ninad Pundalik (Google Summer of Code 2010)
      +
    • AJAXifying the interface
    • +
    +
  • +
  • Martynas MickeviÄius (Google Summer of Code 2010)
      +
    • Charts
    • +
    +
  • +
  • Barrie Leslie
      +
    • BLOBstreaming support with PBMS PHP extension (withdrawn in release +4.0)
    • +
    +
  • +
  • Ankit Gupta (Google Summer of Code 2010)
      +
    • Visual query builder
    • +
    +
  • +
  • Madhura Jayaratne (Google Summer of Code 2011)
      +
    • OpenGIS support
    • +
    +
  • +
  • Ammar Yasir (Google Summer of Code 2011)
      +
    • Zoom search
    • +
    +
  • +
  • Aris Feryanto (Google Summer of Code 2011)
      +
    • Browse-mode improvements
    • +
    +
  • +
  • Thilanka Kaushalya (Google Summer of Code 2011)
      +
    • AJAXification
    • +
    +
  • +
  • Tyron Madlener (Google Summer of Code 2011)
      +
    • Query statistics and charts for the status page
    • +
    +
  • +
  • Zarubin Stas (Google Summer of Code 2011)
      +
    • Automated testing
    • +
    +
  • +
  • Rouslan Placella (Google Summer of Code 2011 and 2012)
      +
    • Improved support for Stored Routines, Triggers and Events
    • +
    • Italian translation updates
    • +
    • Removal of frames, new navigation
    • +
    +
  • +
  • Dieter Adriaenssens
      +
    • Various bugfixes
    • +
    • Dutch translation updates
    • +
    +
  • +
  • Alex Marin (Google Summer of Code 2012)
      +
    • New plugins and properties system
    • +
    +
  • +
  • Thilina Buddika Abeyrathna (Google Summer of Code 2012)
      +
    • Refactoring
    • +
    +
  • +
  • Atul Pratap Singh (Google Summer of Code 2012)
      +
    • Refactoring
    • +
    +
  • +
  • Chanaka Indrajith (Google Summer of Code 2012)
      +
    • Refactoring
    • +
    +
  • +
  • Yasitha Pandithawatta (Google Summer of Code 2012)
      +
    • Automated testing
    • +
    +
  • +
  • Jim Wigginton (phpseclib.sourceforge.net)
      +
    • phpseclib
    • +
    +
  • +
  • Bin Zu (Google Summer of Code 2013)
      +
    • Refactoring
    • +
    +
  • +
  • Supun Nakandala (Google Summer of Code 2013)
      +
    • Refactoring
    • +
    +
  • +
  • Mohamed Ashraf (Google Summer of Code 2013)
      +
    • AJAX error reporting
    • +
    +
  • +
  • Adam Kang (Google Summer of Code 2013)
      +
    • Automated testing
    • +
    +
  • +
  • Ayush Chaudhary (Google Summer of Code 2013)
      +
    • Automated testing
    • +
    +
  • +
  • Kasun Chathuranga (Google Summer of Code 2013)
      +
    • Interface 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:

+

Bora Alioglu, Ricardo ?, Sven-Erik Andersen, Alessandro Astarita, +Péter Bakondy, Borges Botelho, Olivier Bussier, Neil Darlow, Mats +Engstrom, Ian Davidson, Laurent Dhima, Kristof Hamann, Thomas Kläger, +Lubos Klokner, Martin Marconcini, Girish Nair, David Nordenberg, +Andreas Pauley, Bernard M. Piller, Laurent Haas, “Sakamoto”, Yuval +Sarna, www.securereality.com.au, Alexis Soulard, Alvar Soome, Siu Sun, +Peter Svec, Michael Tacelosky, Rachim Tamsjadi, Kositer Uros, Luís V., +Martijn W. van der Lee, Algis Vainauskas, Daniel Villanueva, Vinay, +Ignacio Vazquez-Abrams, Chee Wai, Jakub Wilk, Thomas Michael +Winningham, Vilius Zigmantas, “Manuzhai”.

+
+
+

Translators¶

+

Following people have contributed to translation of phpMyAdmin:

+
    +
  • Arabic
      +
    • Abdullah Al-Saedi <abdullah.10_at_windowslive.com>
    • +
    +
  • +
  • Bulgarian
      +
    • stoyanster <stoyanster_at_gmail.com>
    • +
    +
  • +
  • Catalan
      +
    • Xavier Navarro <xvnavarro_at_gmail.com>
    • +
    +
  • +
  • Czech
      +
    • Michal ÄŒihaÅ™ <michal_at_cihar.com>
    • +
    +
  • +
  • Danish
      +
    • opensource <opensource_at_jth.net>
    • +
    • Jørgen Thomsen <opensource_at_jth.net>
    • +
    +
  • +
  • German
      +
    • mrbendig <mrbendig_at_mrbendig.com>
    • +
    • torsten.funck <torsten.funck_at_googlemail.com>
    • +
    • Sven Strickroth <email_at_cs-ware.de>
    • +
    • typo3 <typo3_at_dirk-weise.de>
    • +
    • Jo Michael <me_at_mynetx.net>
    • +
    +
  • +
  • Greek
      +
    • Panagiotis Papazoglou <papaz_p_at_yahoo.com>
    • +
    +
  • +
  • English (United Kingdom)
      +
    • Robert Readman <robert_readman_at_hotmail.com>
    • +
    +
  • +
  • Spanish
      +
    • Matías Bellone <matiasbellone_at_gmail.com>
    • +
    +
  • +
  • French
      +
    • Marc Delisle <marc_at_infomarc.info>
    • +
    +
  • +
  • Hindi
      +
    • u4663530 <u4663530_at_anu.edu.au>
    • +
    • rsedwardian <rsedwardian_at_gmail.com>
    • +
    +
  • +
  • Hungarian
      +
    • gergo314 <gergo314_at_gmail.com>
    • +
    +
  • +
  • Italian
      +
    • Rouslan Placella <rouslan_at_placella.com>
    • +
    +
  • +
  • Japanese
      +
    • Yuichiro <yuichiro_at_pop07.odn.ne.jp>
    • +
    +
  • +
  • Lithuanian
      +
    • KÄ™stutis <forkik_at_gmail.com>
    • +
    +
  • +
  • Norwegian BokmÃ¥l
      +
    • Sven-Erik Andersen <sven.erik.andersen_at_gmail.com>
    • +
    +
  • +
  • Dutch
      +
    • Dieter Adriaenssens <ruleant_at_users.sourceforge.net>
    • +
    • Herman van Rink <rink_at_initfour.nl>
    • +
    +
  • +
  • Polish
      +
    • StanisÅ‚aw Krukowski <stankruk_at_neostrada.pl>
    • +
    • Marcin KozioÅ‚ <lord_dark_at_wp.pl>
    • +
    +
  • +
  • Portuguese
      +
    • JoaoTMDias <contacto_at_joaodias.me>
    • +
    +
  • +
  • Portuguese (Brazil)
      +
    • wiltave <wiltave_at_gmail.com>
    • +
    • emerson4br <emerson4br_at_gmail.com>
    • +
    +
  • +
  • Romanian
      +
    • alexukf <alex.ukf_at_gmail.com>
    • +
    +
  • +
  • Russian
      +
    • Victor Volkov <hanut_at_php-myadmin.ru>
    • +
    +
  • +
  • Sinhala
      +
    • Madhura Jayaratne <madhura.cj_at_gmail.com>
    • +
    +
  • +
  • Slovak
      +
    • Martin Lacina <martin_at_whistler.sk>
    • +
    +
  • +
  • Slovenian
      +
    • Domen <dbc334_at_gmail.com>
    • +
    +
  • +
  • Swedish
      +
    • stefan <stefan_at_inkopsforum.se>
    • +
    +
  • +
  • Tamil
      +
    • ysajeepan <ysajeepan_at_live.com>
    • +
    +
  • +
  • Telugu
      +
    • veeven <veeven_at_gmail.com>
    • +
    +
  • +
  • Thai
      +
    • kanitchet <kanichet_at_hotmail.com>
    • +
    +
  • +
  • Turkish
      +
    • Burak Yavuz <hitowerdigit_at_hotmail.com>
    • +
    +
  • +
  • Uighur
      +
    • gheni <gheni_at_yahoo.cn>
    • +
    +
  • +
  • Ukrainian
      +
    • typim <duke3d_at_ukr.net>
    • +
    • oleg-ilnytskyi <ukraine.oleg_at_gmail.com>
    • +
    +
  • +
  • Urdu
      +
    • Mehbooob Khan <mehboobbugti_at_gmail.com>
    • +
    +
  • +
  • Simplified Chinese
      +
    • shanyan baishui <Siramizu_at_gmail.com>
    • +
    +
  • +
  • Traditional Chinese
      +
    • star <star_at_origin.club.tw>
    • +
    +
  • +
+
+
+

Documentation translators¶

+

Following people have contributed to translation of phpMyAdmin documentation:

+
    +
  • Czech
      +
    • Michal ÄŒihaÅ™ <michal_at_cihar.com>
    • +
    +
  • +
  • Greek
      +
    • Panagiotis Papazoglou <papaz_p_at_yahoo.com>
    • +
    +
  • +
  • English (United Kingdom)
      +
    • Robert Readman <robert_readman_at_hotmail.com>
    • +
    +
  • +
  • French
      +
    • Cédric Corazza <cedric.corazza_at_wanadoo.fr>
    • +
    +
  • +
  • Japanese
      +
    • Yuichiro Takahashi <yuichiro_at_pop07.odn.ne.jp>
    • +
    +
  • +
  • Polish
      +
    • StanisÅ‚aw Krukowski <stankruk_at_neostrada.pl>
    • +
    +
  • +
  • Portuguese (Brazil)
      +
    • mjaning <mjaning_at_gmail.com>
    • +
    +
  • +
  • Slovenian
      +
    • Domen <dbc334_at_gmail.com>
    • +
    +
  • +
+
+
+

Original Credits of Version 2.1.0¶

+

This work is based on Peter Kuppelwieser’s MySQL-Webadmin. It was his +idea to create a web-based interface to MySQL using PHP3. Although I +have not used any of his source-code, there are some concepts I’ve +borrowed from him. phpMyAdmin was created because Peter told me he +wasn’t going to further develop his (great) tool.

+

Thanks go to

+
    +
  • Amalesh Kempf <ak-lsml_at_living-source.com> who contributed the +code for the check when dropping a table or database. He also +suggested that you should be able to specify the primary key on +tbl_create.php3. To version 1.1.1 he contributed the ldi_*.php3-set +(Import text-files) as well as a bug-report. Plus many smaller +improvements.
  • +
  • Jan Legenhausen <jan_at_nrw.net>: He made many of the changes that +were introduced in 1.3.0 (including quite significant ones like the +authentication). For 1.4.1 he enhanced the table-dump feature. Plus +bug-fixes and help.
  • +
  • Marc Delisle <DelislMa_at_CollegeSherbrooke.qc.ca> made phpMyAdmin +language-independent by outsourcing the strings to a separate file. He +also contributed the French translation.
  • +
  • Alexandr Bravo <abravo_at_hq.admiral.ru> who contributed +tbl_select.php3, a feature to display only some columns from a table.
  • +
  • Chris Jackson <chrisj_at_ctel.net> added support for MySQL functions +in tbl_change.php3. He also added the “Query by Example” feature in +2.0.
  • +
  • Dave Walton <walton_at_nordicdms.com> added support for multiple +servers and is a regular contributor for bug-fixes.
  • +
  • Gabriel Ash <ga244_at_is8.nyu.edu> contributed the random access +features for 2.0.6.
  • +
+

The following people have contributed minor changes, enhancements, +bugfixes or support for a new language:

+

Jim Kraai, Jordi Bruguera, Miquel Obrador, Geert Lund, Thomas +Kleemann, Alexander Leidinger, Kiko Albiol, Daniel C. Chao, Pavel +Piankov, Sascha Kettler, Joe Pruett, Renato Lins, Mark Kronsbein, +Jannis Hermanns, G. Wieggers.

+

And thanks to everyone else who sent me email with suggestions, bug- +reports and or just some feedback.

+
+
+ + +
+
+
+
+
+

Table Of Contents

+ + +

Previous topic

+

Copyright

+

Next topic

+

Glossary

+

This Page

+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/phpMyAdmin/doc/html/developers.html b/phpMyAdmin/doc/html/developers.html new file mode 100644 index 0000000..4434417 --- /dev/null +++ b/phpMyAdmin/doc/html/developers.html @@ -0,0 +1,118 @@ + + + + + + + + + + Developers Information — phpMyAdmin 4.1.7 documentation + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Developers Information¶

+

phpMyAdmin is Open Source, so you’re invited to contribute to it. Many +great features have been written by other people and you too can help +to make phpMyAdmin a useful tool.

+

You can check out all the possibilities to contribute in the +contribute section on our website.

+
+ + +
+
+
+
+
+

Previous topic

+

FAQ - Frequently Asked Questions

+

Next topic

+

Distributing and packaging phpMyAdmin

+

This Page

+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/phpMyAdmin/doc/html/faq.html b/phpMyAdmin/doc/html/faq.html new file mode 100644 index 0000000..4038c61 --- /dev/null +++ b/phpMyAdmin/doc/html/faq.html @@ -0,0 +1,1791 @@ + + + + + + + + + + FAQ - Frequently Asked Questions — phpMyAdmin 4.1.7 documentation + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

FAQ - Frequently Asked Questions¶

+

Please have a look at our Link section on the official +phpMyAdmin homepage for in-depth coverage of phpMyAdmin’s features and +or interface.

+
+

Server¶

+
+

1.1 My server is crashing each time a specific action is required or phpMyAdmin sends a blank page or a page full of cryptic characters to my browser, what can I do?¶

+

Try to set the $cfg['OBGzip'] directive to false in your +config.inc.php file and the zlib.output_compression directive to +Off in your php configuration file.

+
+
+

1.2 My Apache server crashes when using phpMyAdmin.¶

+

You should first try the latest versions of Apache (and possibly MySQL). If +your server keeps crashing, please ask for help in the various Apache support +groups.

+ +
+
+

1.3 (withdrawn).¶

+
+
+

1.4 Using phpMyAdmin on IIS, I’m displayed the error message: “The specified CGI application misbehaved by not returning a complete set of HTTP headers ...”.¶

+

You just forgot to read the install.txt file from the PHP +distribution. Have a look at the last message in this PHP bug report #12061 from the official PHP bug +database.

+
+
+

1.5 Using phpMyAdmin on IIS, I’m facing crashes and/or many error messages with the HTTP.¶

+

This is a known problem with the PHP ISAPI filter: it’s not so stable. +Please use instead the cookie authentication mode.

+
+
+

1.6 I can’t use phpMyAdmin on PWS: nothing is displayed!¶

+

This seems to be a PWS bug. Filippo Simoncini found a workaround (at +this time there is no better fix): remove or comment the DOCTYPE +declarations (2 lines) from the scripts libraries/Header.class.php +and index.php.

+
+
+

1.7 How can I GZip a dump or a CSV export? It does not seem to work.¶

+

This feature is based on the gzencode() +PHP function to be more independent of the platform (Unix/Windows, +Safe Mode or not, and so on). So, you must have Zlib support +(--with-zlib).

+
+
+

1.8 I cannot insert a text file in a table, and I get an error about safe mode being in effect.¶

+

Your uploaded file is saved by PHP in the “upload dir”, as defined in +php.ini by the variable upload_tmp_dir (usually the system +default is /tmp). We recommend the following setup for Apache +servers running in safe mode, to enable uploads of files while being +reasonably secure:

+
    +
  • create a separate directory for uploads: mkdir /tmp/php
  • +
  • give ownership to the Apache server’s user.group: chown +apache.apache /tmp/php
  • +
  • give proper permission: chmod 600 /tmp/php
  • +
  • put upload_tmp_dir = /tmp/php in php.ini
  • +
  • restart Apache
  • +
+
+
+

1.9 (withdrawn).¶

+
+
+

1.10 I’m having troubles when uploading files with phpMyAdmin running on a secure server. My browser is Internet Explorer and I’m using the Apache server.¶

+

As suggested by “Rob M” in the phpWizard forum, add this line to your +httpd.conf:

+
SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown
+
+
+

It seems to clear up many problems between Internet Explorer and SSL.

+
+
+

1.11 I get an ‘open_basedir restriction’ while uploading a file from the query box.¶

+

Since version 2.2.4, phpMyAdmin supports servers with open_basedir +restrictions. However you need to create temporary directory and configure it +as $cfg['TempDir']. The uploaded files will be moved there, +and after execution of your SQL commands, removed.

+
+
+

1.12 I have lost my MySQL root password, what can I do?¶

+

The MySQL manual explains how to reset the permissions.

+
+
+

1.13 (withdrawn).¶

+
+
+

1.14 (withdrawn).¶

+
+
+

1.15 I have problems with mysql.user column names.¶

+

In previous MySQL versions, the User and Password``columns were +named ``user and password. Please modify your column names to +align with current standards.

+
+
+

1.16 I cannot upload big dump files (memory, HTTP or timeout problems).¶

+

Starting with version 2.7.0, the import engine has been re–written and +these problems should not occur. If possible, upgrade your phpMyAdmin +to the latest version to take advantage of the new import features.

+

The first things to check (or ask your host provider to check) are the +values of upload_max_filesize, memory_limit and +post_max_size in the php.ini configuration file. All of these +three settings limit the maximum size of data that can be submitted +and handled by PHP. One user also said that post_max_size and +memory_limit need to be larger than upload_max_filesize. +There exist several workarounds if your upload is too big or your +hosting provider is unwilling to change the settings:

+
    +
  • Look at the $cfg['UploadDir'] feature. This allows one to upload a file to the server +via scp, ftp, or your favorite file transfer method. PhpMyAdmin is +then able to import the files from the temporary directory. More +information is available in the Configuration of this document.

    +
  • +
  • Using a utility (such as BigDump) to split the files before +uploading. We cannot support this or any third party applications, but +are aware of users having success with it.

    +
  • +
  • If you have shell (command line) access, use MySQL to import the files +directly. You can do this by issuing the “source” command from within +MySQL:

    +
    source filename.sql;
    +
    +
    +
  • +
+
+
+

1.17 Which MySQL versions does phpMyAdmin support?¶

+

Since phpMyAdmin 3.0.x, only MySQL 5.0.1 and newer are supported. For +older MySQL versions, you need to use the latest 2.x branch. +phpMyAdmin can connect to your MySQL server using PHP’s classic MySQL +extension as well as the improved MySQL +extension (MySQLi) that is available in PHP +5.0. The latter one should be used unless you have a good reason not +to do so. When compiling PHP, we strongly recommend that you manually +link the MySQL extension of your choice to a MySQL client library of +at least the same minor version since the one that is bundled with +some PHP distributions is rather old and might cause problems see +1.17a I cannot connect to the MySQL server. It always returns the error message, “Client does not support authentication protocol requested by server; consider upgrading MySQL client”. MariaDB is also supported +(versions 5.1 and 5.2 were tested).

+

+Changed in version 3.5: Since phpMyAdmin 3.5 Drizzle is supported.

+
+
+

1.17a I cannot connect to the MySQL server. It always returns the error message, “Client does not support authentication protocol requested by server; consider upgrading MySQL client”¶

+

You tried to access MySQL with an old MySQL client library. The +version of your MySQL client library can be checked in your phpinfo() +output. In general, it should have at least the same minor version as +your server - as mentioned in 1.17 Which MySQL versions does phpMyAdmin support?. This problem is +generally caused by using MySQL version 4.1 or newer. MySQL changed +the authentication hash and your PHP is trying to use the old method. +The proper solution is to use the mysqli extension with the proper client library to match +your MySQL installation. Your chosen extension is specified in +$cfg['Servers'][$i]['extension']. More +information (and several workarounds) are located in the MySQL +Documentation.

+
+
+

1.18 (withdrawn).¶

+
+
+

1.19 I can’t run the “display relations” feature because the script seems not to know the font face I’m using!¶

+

The TCPDF library we’re using for this feature requires some special +files to use font faces. Please refers to the TCPDF manual to build these files.

+
+
+

1.20 I receive the error “cannot load MySQL extension, please check PHP Configuration”.¶

+

To connect to a MySQL server, PHP needs a set of MySQL functions +called “MySQL extension”. This extension may be part of the PHP +distribution (compiled-in), otherwise it needs to be loaded +dynamically. Its name is probably mysql.so or php_mysql.dll. +phpMyAdmin tried to load the extension but failed. Usually, the +problem is solved by installing a software package called “PHP-MySQL” +or something similar.

+

There are currently two interfaces PHP provides as MySQL extensions - mysql +and mysqli and you can change which of then is being used by +$cfg['Servers'][$i]['extension'].

+
+ +
+

1.22 I don’t see the “Location of text file” field, so I cannot upload.¶

+

This is most likely because in php.ini, your file_uploads +parameter is not set to “on”.

+
+
+

1.23 I’m running MySQL on a Win32 machine. Each time I create a new table the table and column names are changed to lowercase!¶

+

This happens because the MySQL directive lower_case_table_names +defaults to 1 (ON) in the Win32 version of MySQL. You can change +this behavior by simply changing the directive to 0 (OFF): Just +edit your my.ini file that should be located in your Windows +directory and add the following line to the group [mysqld]:

+
set-variable = lower_case_table_names=0
+
+
+

Next, save the file and restart the MySQL service. You can always +check the value of this directive using the query

+
SHOW VARIABLES LIKE 'lower_case_table_names';
+
+
+
+
+

1.24 (withdrawn).¶

+
+
+

1.25 I am running Apache with mod_gzip-1.3.26.1a on Windows XP, and I get problems, such as undefined variables when I run a SQL query.¶

+

A tip from Jose Fandos: put a comment on the following two lines in +httpd.conf, like this:

+
# mod_gzip_item_include file \.php$
+# mod_gzip_item_include mime "application/x-httpd-php.*"
+
+
+

as this version of mod_gzip on Apache (Windows) has problems handling +PHP scripts. Of course you have to restart Apache.

+
+
+

1.26 I just installed phpMyAdmin in my document root of IIS but I get the error “No input file specified” when trying to run phpMyAdmin.¶

+

This is a permission problem. Right-click on the phpmyadmin folder and +choose properties. Under the tab Security, click on “Add” and select +the user “IUSR_machine” from the list. Now set his permissions and it +should work.

+
+
+

1.27 I get empty page when I want to view huge page (eg. db_structure.php with plenty of tables).¶

+

This was caused by a PHP bug that occur when +GZIP output buffering is enabled. If you turn off it (by +$cfg['OBGzip'] in config.inc.php), it should work. +This bug will has been fixed in PHP 5.0.0.

+
+
+

1.28 My MySQL server sometimes refuses queries and returns the message ‘Errorcode: 13’. What does this mean?¶

+

This can happen due to a MySQL bug when having database / table names +with upper case characters although lower_case_table_names is +set to 1. To fix this, turn off this directive, convert all database +and table names to lower case and turn it on again. Alternatively, +there’s a bug-fix available starting with MySQL 3.23.56 / +4.0.11-gamma.

+
+
+

1.29 When I create a table or modify a column, I get an error and the columns are duplicated.¶

+

It is possible to configure Apache in such a way that PHP has problems +interpreting .php files.

+

The problems occur when two different (and conflicting) set of +directives are used:

+
SetOutputFilter PHP
+SetInputFilter PHP
+
+
+

and

+
AddType application/x-httpd-php .php
+
+
+

In the case we saw, one set of directives was in +/etc/httpd/conf/httpd.conf, while the other set was in +/etc/httpd/conf/addon-modules/php.conf. The recommended way is +with AddType, so just comment out the first set of lines and +restart Apache:

+
#SetOutputFilter PHP
+#SetInputFilter PHP
+
+
+
+
+

1.30 I get the error “navigation.php: Missing hash”.¶

+

This problem is known to happen when the server is running Turck +MMCache but upgrading MMCache to version 2.3.21 solves the problem.

+
+
+

1.31 Does phpMyAdmin support PHP 5?¶

+

Yes.

+

Since release 4.1 phpMyAdmin supports only PHP 5.3 and newer. For PHP 5.2 you +can use 4.0.x releases.

+
+
+

1.32 Can I use HTTP authentication with IIS?¶

+

Yes. This procedure was tested with phpMyAdmin 2.6.1, PHP 4.3.9 in +ISAPI mode under IIS 5.1.

+
    +
  1. In your php.ini file, set cgi.rfc2616_headers = 0
  2. +
  3. In Web Site Properties -> File/Directory Security -> Anonymous +Access dialog box, check the Anonymous access checkbox and +uncheck any other checkboxes (i.e. uncheck Basic authentication, +Integrated Windows authentication, and Digest if it’s +enabled.) Click OK.
  4. +
  5. In Custom Errors, select the range of 401;1 through 401;5 +and click the Set to Default button.
  6. +
+
+

See also

+

RFC 2616

+
+
+
+

1.33 (withdrawn).¶

+
+
+

1.34 Can I access directly to database or table pages?¶

+

Yes. Out of the box, you can use URL like +http://server/phpMyAdmin/index.php?server=X&db=database&table=table&target=script. +For server you use the server number +which refers to the order of the server paragraph in +config.inc.php. Table and script parts are optional. If you want +http://server/phpMyAdmin/database[/table][/script] URL, you need to do some configuration. Following +lines apply only for Apache web server. +First make sure, that you have enabled some features within global +configuration. You need Options FollowSymLinks and AllowOverride +FileInfo enabled for directory where phpMyAdmin is installed and you +need mod_rewrite to be enabled. Then you just need to create +following .htaccess file in root folder of phpMyAdmin installation (don’t +forget to change directory name inside of it):

+
RewriteEngine On
+RewriteBase /path_to_phpMyAdmin
+RewriteRule ^([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)/([a-z_]+\.php)$ index.php?db=$1&table=$2&target=$3 [R]
+RewriteRule ^([a-zA-Z0-9_]+)/([a-z_]+\.php)$ index.php?db=$1&target=$2 [R]
+RewriteRule ^([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)$ index.php?db=$1&table=$2 [R]
+RewriteRule ^([a-zA-Z0-9_]+)$ index.php?db=$1 [R]
+
+
+
+
+

1.35 Can I use HTTP authentication with Apache CGI?¶

+

Yes. However you need to pass authentication variable to CGI using +following rewrite rule:

+
RewriteEngine On
+RewriteRule .* - [E=REMOTE_USER:%{HTTP:Authorization},L]
+
+
+
+
+

1.36 I get an error “500 Internal Server Error”.¶

+

There can be many explanations to this and a look at your server’s +error log file might give a clue.

+
+ +
+

1.38 Can I use phpMyAdmin on a server on which Suhosin is enabled?¶

+

Yes but the default configuration values of Suhosin are known to cause +problems with some operations, for example editing a table with many +columns and no primary key or with textual primary key.

+

Suhosin configuration might lead to malfunction in some cases and it +can not be fully avoided as phpMyAdmin is kind of application which +needs to transfer big amounts of columns in single HTTP request, what +is something what Suhosin tries to prevent. Generally all +suhosin.request.*, suhosin.post.* and suhosin.get.* +directives can have negative effect on phpMyAdmin usability. You can +always find in your error logs which limit did cause dropping of +variable, so you can diagnose the problem and adjust matching +configuration variable.

+

The default values for most Suhosin configuration options will work in +most scenarios, however you might want to adjust at least following +parameters:

+ +

You can also disable the warning using the $cfg['SuhosinDisableWarning'].

+
+
+

1.39 When I try to connect via https, I can log in, but then my connection is redirected back to http. What can cause this behavior?¶

+

Be sure that you have enabled SSLOptions and StdEnvVars in +your Apache configuration.

+ +
+ +
+

1.41 When I view a database and ask to see its privileges, I get an error about an unknown column.¶

+

The MySQL server’s privilege tables are not up to date, you need to +run the mysql_upgrade command on the server.

+
+
+

1.42 How can I prevent robots from accessing phpMyAdmin?¶

+

You can add various rules to .htaccess to filter access based on user agent +field. This is quite easy to circumvent, but could prevent at least +some robots accessing your installation.

+
RewriteEngine on
+
+# Allow only GET and POST verbs
+RewriteCond %{REQUEST_METHOD} !^(GET|POST)$ [NC,OR]
+
+# Ban Typical Vulnerability Scanners and others
+# Kick out Script Kiddies
+RewriteCond %{HTTP_USER_AGENT} ^(java|curl|wget).* [NC,OR]
+RewriteCond %{HTTP_USER_AGENT} ^.*(libwww-perl|curl|wget|python|nikto|wkito|pikto|scan|acunetix).* [NC,OR]
+RewriteCond %{HTTP_USER_AGENT} ^.*(winhttp|HTTrack|clshttp|archiver|loader|email|harvest|extract|grab|miner).* [NC,OR]
+
+# Ban Search Engines, Crawlers to your administrative panel
+# No reasons to access from bots
+# Ultimately Better than the useless robots.txt
+# Did google respect robots.txt?
+# Try google: intitle:phpMyAdmin intext:"Welcome to phpMyAdmin *.*.*" intext:"Log in" -wiki -forum -forums -questions intext:"Cookies must be enabled"
+RewriteCond %{HTTP_USER_AGENT} ^.*(AdsBot-Google|ia_archiver|Scooter|Ask.Jeeves|Baiduspider|Exabot|FAST.Enterprise.Crawler|FAST-WebCrawler|www\.neomo\.de|Gigabot|Mediapartners-Google|Google.Desktop|Feedfetcher-Google|Googlebot|heise-IT-Markt-Crawler|heritrix|ibm.com\cs/crawler|ICCrawler|ichiro|MJ12bot|MetagerBot|msnbot-NewsBlogs|msnbot|msnbot-media|NG-Search|lucene.apache.org|NutchCVS|OmniExplorer_Bot|online.link.validator|psbot0|Seekbot|Sensis.Web.Crawler|SEO.search.Crawler|Seoma.\[SEO.Crawler\]|SEOsearch|Snappy|www.urltrends.com|www.tkl.iis.u-tokyo.ac.jp/~crawler|SynooBot|crawleradmin.t-info@telekom.de|TurnitinBot|voyager|W3.SiteSearch.Crawler|W3C-checklink|W3C_Validator|www.WISEnutbot.com|yacybot|Yahoo-MMCrawler|Yahoo\!.DE.Slurp|Yahoo\!.Slurp|YahooSeeker).* [NC]
+RewriteRule .* - [F]
+
+
+
+
+

1.43 Why can’t I display the structure of my table containing hundreds of columns?¶

+

Because your PHP’s memory_limit is too low; adjust it in php.ini.

+
+
+
+

Configuration¶

+
+

2.1 The error message “Warning: Cannot add header information - headers already sent by ...” is displayed, what’s the problem?¶

+

Edit your config.inc.php file and ensure there is nothing (I.E. no +blank lines, no spaces, no characters...) neither before the <?php tag at +the beginning, neither after the ?> tag at the end. We also got a report +from a user under IIS, that used a zipped distribution kit: the file +libraries/Config.class.php contained an end-of-line character (hex 0A) +at the end; removing this character cleared his errors.

+
+
+

2.2 phpMyAdmin can’t connect to MySQL. What’s wrong?¶

+

Either there is an error with your PHP setup or your username/password +is wrong. Try to make a small script which uses mysql_connect and see +if it works. If it doesn’t, it may be you haven’t even compiled MySQL +support into PHP.

+
+
+

2.3 The error message “Warning: MySQL Connection Failed: Can’t connect to local MySQL server through socket ‘/tmp/mysql.sock’ (111) ...” is displayed. What can I do?¶

+

For RedHat users, Harald Legner suggests this on the mailing list:

+

On my RedHat-Box the socket of MySQL is /var/lib/mysql/mysql.sock. +In your php.ini you will find a line

+
mysql.default_socket = /tmp/mysql.sock
+
+
+

change it to

+
mysql.default_socket = /var/lib/mysql/mysql.sock
+
+
+

Then restart apache and it will work.

+

Here is a fix suggested by Brad Ummer:

+
    +
  • First, you need to determine what socket is being used by MySQL. To do +this, telnet to your server and go to the MySQL bin directory. In this +directory there should be a file named mysqladmin. Type +./mysqladmin variables, and this should give you a bunch of info +about your MySQL server, including the socket (/tmp/mysql.sock, for +example).
  • +
  • Then, you need to tell PHP to use this socket. To do this in +phpMyAdmin, you need to complete the socket information in the +config.inc.php. For example: +$cfg['Servers'][$i]['socket'] Please also make sure that +the permissions of this file allow to be readable by your webserver (i.e. +‘0755’).
  • +
+

Have also a look at the corresponding section of the MySQL +documentation.

+
+
+

2.4 Nothing is displayed by my browser when I try to run phpMyAdmin, what can I do?¶

+

Try to set the $cfg['OBGzip'] directive to false in the phpMyAdmin configuration +file. It helps sometime. Also have a look at your PHP version number: +if it contains “b” or “alpha” it means you’re running a testing +version of PHP. That’s not a so good idea, please upgrade to a plain +revision.

+
+ +
+

2.6 I get an “Access denied for user: 'root@localhost‘ (Using password: YES)”-error when trying to access a MySQL-Server on a host which is port-forwarded for my localhost.¶

+

When you are using a port on your localhost, which you redirect via +port-forwarding to another host, MySQL is not resolving the localhost +as expected. Erik Wasser explains: The solution is: if your host is +“localhost” MySQL (the command line tool mysql as well) always +tries to use the socket connection for speeding up things. And that +doesn’t work in this configuration with port forwarding. If you enter +“127.0.0.1” as hostname, everything is right and MySQL uses the +TCP connection.

+
+
+

2.7 Using and creating themes¶

+

Themes are configured with $cfg['ThemePath'], +$cfg['ThemeManager'] and $cfg['ThemeDefault']. +Under $cfg['ThemePath'], you should not delete the +directory pmahomme or its underlying structure, because this is the +system theme used by phpMyAdmin. pmahomme contains all images and +styles, for backwards compatibility and for all themes that would not +include images or css-files. If $cfg['ThemeManager'] +is enabled, you can select your favorite theme on the main page. Your selected +theme will be stored in a cookie.

+

To create a theme:

+
    +
  • make a new subdirectory (for example “your_theme_name”) under $cfg['ThemePath'] (by +default themes)
  • +
  • copy the files and directories from pmahomme to “your_theme_name”
  • +
  • edit the css-files in “your_theme_name/css”
  • +
  • put your new images in “your_theme_name/img”
  • +
  • edit layout.inc.php in “your_theme_name”
  • +
  • edit info.inc.php in “your_theme_name” to contain your chosen +theme name, that will be visible in user interface
  • +
  • make a new screenshot of your theme and save it under +“your_theme_name/screen.png”
  • +
+

In theme directory there is file info.inc.php which contains theme +verbose name, theme generation and theme version. These versions and +generations are enumerated from 1 and do not have any direct +dependence on phpMyAdmin version. Themes within same generation should +be backwards compatible - theme with version 2 should work in +phpMyAdmin requiring version 1. Themes with different generation are +incompatible.

+

If you do not want to use your own symbols and buttons, remove the +directory “img” in “your_theme_name”. phpMyAdmin will use the +default icons and buttons (from the system-theme pmahomme).

+
+
+

2.8 I get “Missing parameters” errors, what can I do?¶

+

Here are a few points to check:

+
    +
  • In config.inc.php, try to leave the $cfg['PmaAbsoluteUri'] directive empty. See also +4.7 Authentication window is displayed more than once, why?.
  • +
  • Maybe you have a broken PHP installation or you need to upgrade your +Zend Optimizer. See <http://bugs.php.net/bug.php?id=31134>.
  • +
  • If you are using Hardened PHP with the ini directive +varfilter.max_request_variables set to the default (200) or +another low value, you could get this error if your table has a high +number of columns. Adjust this setting accordingly. (Thanks to Klaus +Dorninger for the hint).
  • +
  • In the php.ini directive arg_separator.input, a value of ”;” +will cause this error. Replace it with “&;”.
  • +
  • If you are using Hardened-PHP, you +might want to increase request limits.
  • +
  • The directory specified in the php.ini directive +session.save_path does not exist or is read-only.
  • +
+
+
+

2.9 Seeing an upload progress bar¶

+

To be able to see a progress bar during your uploads, your server must +have the APC extension, the +uploadprogress one, or +you must be running PHP 5.4.0 or higher. Moreover, the JSON extension +has to be enabled in your PHP.

+

If using APC, you must set apc.rfc1867 to on in your php.ini.

+

If using PHP 5.4.0 or higher, you must set +session.upload_progress.enabled to 1 in your php.ini. However, +starting from phpMyAdmin version 4.0.4, session-based upload progress has +been temporarily deactivated due to its problematic behavior.

+
+

See also

+

RFC 1867

+
+
+
+
+

Known limitations¶

+
+

3.1 When using HTTP authentication, a user who logged out can not log in again in with the same nick.¶

+

This is related to the authentication mechanism (protocol) used by +phpMyAdmin. To bypass this problem: just close all the opened browser +windows and then go back to phpMyAdmin. You should be able to log in +again.

+
+
+

3.2 When dumping a large table in compressed mode, I get a memory limit error or a time limit error.¶

+

Compressed dumps are built in memory and because of this are limited +to php’s memory limit. For GZip/BZip2 exports this can be overcome +since 2.5.4 using $cfg['CompressOnFly'] (enabled by default). +Zip exports can not be handled this way, so if you need Zip files for larger +dump, you have to use another way.

+
+
+

3.3 With InnoDB tables, I lose foreign key relationships when I rename a table or a column.¶

+

This is an InnoDB bug, see <http://bugs.mysql.com/bug.php?id=21704>.

+
+
+

3.4 I am unable to import dumps I created with the mysqldump tool bundled with the MySQL server distribution.¶

+

The problem is that older versions of mysqldump created invalid +comments like this:

+
-- MySQL dump 8.22
+--
+-- Host: localhost Database: database
+---------------------------------------------------------
+-- Server version 3.23.54
+
+
+

The invalid part of the code is the horizontal line made of dashes +that appears once in every dump created with mysqldump. If you want to +run your dump you have to turn it into valid MySQL. This means, you +have to add a whitespace after the first two dashes of the line or add +a # before it: -- ------------------------------------------------------- or +#---------------------------------------------------------

+
+
+

3.5 When using nested folders, multiple hierarchies are displayed in a wrong manner.¶

+

Please note that you should not use the separating string multiple +times without any characters between them, or at the beginning/end of +your table name. If you have to, think about using another +TableSeparator or disabling that feature.

+ +
+
+

3.6 What is currently not supported in phpMyAdmin about InnoDB?¶

+

In Relation view, having more than one index column in the foreign key. In Query-by- +example (Query), automatic generation of the query LEFT JOIN from the +foreign table.

+
+
+

3.7 I have table with many (100+) columns and when I try to browse table I get series of errors like “Warning: unable to parse url”. How can this be fixed?¶

+

Your table neither have a primary key nor an unique one, so we must +use a long expression to identify this row. This causes problems to +parse_url function. The workaround is to create a primary or unique +key.

+
+
+

3.8 I cannot use (clickable) HTML-forms in columns where I put a MIME-Transformation onto!¶

+

Due to a surrounding form-container (for multi-row delete checkboxes), +no nested forms can be put inside the table where phpMyAdmin displays +the results. You can, however, use any form inside of a table if keep +the parent form-container with the target to tbl_row_delete.php and +just put your own input-elements inside. If you use a custom submit +input field, the form will submit itself to the displaying page again, +where you can validate the $HTTP_POST_VARS in a transformation. For +a tutorial on how to effectively use transformations, see our Link +section on the +official phpMyAdmin-homepage.

+
+
+

3.9 I get error messages when using “–sql_mode=ANSI” for the MySQL server.¶

+

When MySQL is running in ANSI-compatibility mode, there are some major +differences in how SQL is structured (see +<http://dev.mysql.com/doc/mysql/en/ansi-mode.html>). Most important of all, the +quote-character (”) is interpreted as an identifier quote character and not as +a string quote character, which makes many internal phpMyAdmin operations into +invalid SQL statements. There is no +workaround to this behaviour. News to this item will be posted in Bug report +#1013.

+
+
+

3.10 Homonyms and no primary key: When the results of a SELECT display more that one column with the same value (for example SELECT lastname from employees where firstname like 'A%' and two “Smith” values are displayed), if I click Edit I cannot be sure that I am editing the intended row.¶

+

Please make sure that your table has a primary key, so that phpMyAdmin +can use it for the Edit and Delete links.

+
+
+

3.11 The number of rows for InnoDB tables is not correct.¶

+

phpMyAdmin uses a quick method to get the row count, and this method only +returns an approximate count in the case of InnoDB tables. See +$cfg['MaxExactCount'] for a way to modify those results, but +this could have a serious impact on performance.

+
+
+

3.12 (withdrawn).¶

+
+
+

3.13 I get an error when entering USE followed by a db name containing an hyphen.¶

+

The tests I have made with MySQL 5.1.49 shows that the API does not +accept this syntax for the USE command.

+
+
+

3.14 I am not able to browse a table when I don’t have the right to SELECT one of the columns.¶

+

This has been a known limitation of phpMyAdmin since the beginning and +it’s not likely to be solved in the future.

+
+
+

3.15 (withdrawn).¶

+
+
+

3.16 (withdrawn).¶

+
+
+

3.17 (withdrawn).¶

+
+
+

3.18 When I import a CSV file that contains multiple tables, they are lumped together into a single table.¶

+

There is no reliable way to differentiate tables in CSV format. For the +time being, you will have to break apart CSV files containing multiple +tables.

+
+
+

3.19 When I import a file and have phpMyAdmin determine the appropriate data structure it only uses int, decimal, and varchar types.¶

+

Currently, the import type-detection system can only assign these +MySQL types to columns. In future, more will likely be added but for +the time being you will have to edit the structure to your liking +post-import. Also, you should note the fact that phpMyAdmin will use +the size of the largest item in any given column as the column size +for the appropriate type. If you know you will be adding larger items +to that column then you should manually adjust the column sizes +accordingly. This is done for the sake of efficiency.

+
+
+

3.20 After upgrading, some bookmarks are gone or their content cannot be shown.¶

+

At some point, the character set used to store bookmark content has changed. +It’s better to recreate your bookmark from the newer phpMyAdmin version.

+
+
+
+

ISPs, multi-user installations¶

+
+

4.1 I’m an ISP. Can I setup one central copy of phpMyAdmin or do I need to install it for each customer?¶

+

Since version 2.0.3, you can setup a central copy of phpMyAdmin for all your +users. The development of this feature was kindly sponsored by NetCologne GmbH. +This requires a properly setup MySQL user management and phpMyAdmin +HTTP or cookie authentication.

+ +
+
+

4.2 What’s the preferred way of making phpMyAdmin secure against evil access?¶

+

This depends on your system. If you’re running a server which cannot be +accessed by other people, it’s sufficient to use the directory protection +bundled with your webserver (with Apache you can use .htaccess files, +for example). If other people have telnet access to your server, you should use +phpMyAdmin’s HTTP or cookie authentication features.

+

Suggestions:

+
    +
  • Your config.inc.php file should be chmod 660.
  • +
  • All your phpMyAdmin files should be chown -R phpmy.apache, where phpmy +is a user whose password is only known to you, and apache is the group +under which Apache runs.
  • +
  • Follow security recommendations for PHP and your webserver.
  • +
+
+
+

4.3 I get errors about not being able to include a file in /lang or in /libraries.¶

+

Check php.ini, or ask your sysadmin to check it. The +include_path must contain ”.” somewhere in it, and +open_basedir, if used, must contain ”.” and ”./lang” to allow +normal operation of phpMyAdmin.

+
+
+

4.4 phpMyAdmin always gives “Access denied” when using HTTP authentication.¶

+

This could happen for several reasons:

+ +
+
+

4.5 Is it possible to let users create their own databases?¶

+

Starting with 2.2.5, in the user management page, you can enter a +wildcard database name for a user (for example “joe%”), and put the +privileges you want. For example, adding SELECT, INSERT, UPDATE, +DELETE, CREATE, DROP, INDEX, ALTER would let a user create/manage +his/her database(s).

+
+
+

4.6 How can I use the Host-based authentication additions?¶

+

If you have existing rules from an old .htaccess file, you can take them and +add a username between the 'deny'/'allow' and 'from' +strings. Using the username wildcard of '%' would be a major +benefit here if your installation is suited to using it. Then you can +just add those updated lines into the +$cfg['Servers'][$i]['AllowDeny']['rules'] array.

+

If you want a pre-made sample, you can try this fragment. It stops the +‘root’ user from logging in from any networks other than the private +network IP blocks.

+
//block root from logging in except from the private networks
+$cfg['Servers'][$i]['AllowDeny']['order'] = 'deny,allow';
+$cfg['Servers'][$i]['AllowDeny']['rules'] = array(
+    'deny root from all',
+    'allow root from localhost',
+    'allow root from 10.0.0.0/8',
+    'allow root from 192.168.0.0/16',
+    'allow root from 172.16.0.0/12',
+);
+
+
+
+
+

4.7 Authentication window is displayed more than once, why?¶

+

This happens if you are using a URL to start phpMyAdmin which is +different than the one set in your $cfg['PmaAbsoluteUri']. For +example, a missing “www”, or entering with an IP address while a domain +name is defined in the config file.

+
+
+

4.8 Which parameters can I use in the URL that starts phpMyAdmin?¶

+

When starting phpMyAdmin, you can use the db, pma_username, +pma_password and server parameters. This last one can contain +either the numeric host index (from $i of the configuration file) +or one of the host names present in the configuration file. Using +pma_username and pma_password has been tested along with the +usage of ‘cookie’ auth_type.

+
+
+
+

Browsers or client OS¶

+
+

5.1 I get an out of memory error, and my controls are non-functional, when trying to create a table with more than 14 columns.¶

+

We could reproduce this problem only under Win98/98SE. Testing under +WinNT4 or Win2K, we could easily create more than 60 columns. A +workaround is to create a smaller number of columns, then come back to +your table properties and add the other columns.

+
+
+

5.2 With Xitami 2.5b4, phpMyAdmin won’t process form fields.¶

+

This is not a phpMyAdmin problem but a Xitami known bug: you’ll face +it with each script/website that use forms. Upgrade or downgrade your +Xitami server.

+
+
+

5.3 I have problems dumping tables with Konqueror (phpMyAdmin 2.2.2).¶

+

With Konqueror 2.1.1: plain dumps, zip and GZip dumps work ok, except +that the proposed file name for the dump is always ‘tbl_dump.php’. +Bzip2 dumps don’t seem to work. With Konqueror 2.2.1: plain dumps +work; zip dumps are placed into the user’s temporary directory, so +they must be moved before closing Konqueror, or else they disappear. +GZip dumps give an error message. Testing needs to be done for +Konqueror 2.2.2.

+
+ +
+

5.5 In Internet Explorer 5.0, I get JavaScript errors when browsing my rows.¶

+

Upgrade to at least Internet Explorer 5.5 SP2.

+
+
+

5.6 In Internet Explorer 5.0, 5.5 or 6.0, I get an error (like “Page not found”) when trying to modify a row in a table with many columns, or with a text column.¶

+

Your table neither have a primary key nor an unique one, so we must use a long +URL to identify this row. There is a limit on the length of the +URL in those browsers, and this not happen in Netscape, for example. +The workaround is to create a primary or unique key, or use another browser.

+
+
+

5.7 I refresh (reload) my browser, and come back to the welcome page.¶

+

Some browsers support right-clicking into the frame you want to +refresh, just do this in the right frame.

+
+
+

5.8 With Mozilla 0.9.7 I have problems sending a query modified in the query box.¶

+

Looks like a Mozilla bug: 0.9.6 was OK. We will keep an eye on future +Mozilla versions.

+
+
+

5.9 With Mozilla 0.9.? to 1.0 and Netscape 7.0-PR1 I can’t type a whitespace in the SQL-Query edit area: the page scrolls down.¶

+

This is a Mozilla bug (see bug #26882 at BugZilla).

+
+
+

5.10 With Netscape 4.75 I get empty rows between each row of data in a CSV exported file.¶

+

This is a known Netscape 4.75 bug: it adds some line feeds when +exporting data in octet-stream mode. Since we can’t detect the +specific Netscape version, we cannot workaround this bug.

+
+
+

5.11 Extended-ASCII characters like German umlauts are displayed wrong.¶

+

Please ensure that you have set your browser’s character set to the +one of the language file you have selected on phpMyAdmin’s start page. +Alternatively, you can try the auto detection mode that is supported +by the recent versions of the most browsers.

+
+
+

5.12 Mac OS X Safari browser changes special characters to ”?”.¶

+

This issue has been reported by a Mac OS X user, who adds that Chimera, +Netscape and Mozilla do not have this problem.

+
+
+

5.13 With Internet Explorer 5.5 or 6, and HTTP authentication type, I cannot manage two servers: I log in to the first one, then the other one, but if I switch back to the first, I have to log in on each operation.¶

+

This is a bug in Internet Explorer, other browsers do not behave this +way.

+
+
+

5.14 Using Opera6, I can manage to get to the authentication, but nothing happens after that, only a blank screen.¶

+

Please upgrade to Opera7 at least.

+
+
+

5.15 I have display problems with Safari.¶

+

Please upgrade to at least version 1.2.3.

+
+
+

5.16 With Internet Explorer, I get “Access is denied” Javascript errors. Or I cannot make phpMyAdmin work under Windows.¶

+

Please check the following points:

+
    +
  • Maybe you have defined your $cfg['PmaAbsoluteUri'] setting in +config.inc.php to an IP address and you are starting phpMyAdmin +with a URL containing a domain name, or the reverse situation.
  • +
  • Security settings in IE and/or Microsoft Security Center are too high, +thus blocking scripts execution.
  • +
  • The Windows Firewall is blocking Apache and MySQL. You must allow +HTTP ports (80 or 443) and MySQL +port (usually 3306) in the “in” and “out” directions.
  • +
+
+
+

5.17 With Firefox, I cannot delete rows of data or drop a database.¶

+

Many users have confirmed that the Tabbrowser Extensions plugin they +installed in their Firefox is causing the problem.

+
+
+

5.18 With Konqueror 4.2.x an invalid LIMIT clause is generated when I browse a table.¶

+

This happens only when both of these conditions are met: using the +http authentication mode and register_globals being set to +On on the server. It seems to be a browser-specific problem; +meanwhile use the cookie authentication mode.

+
+
+

5.19 I get JavaScript errors in my browser.¶

+

Issues have been reported with some combinations of browser +extensions. To troubleshoot, disable all extensions then clear your +browser cache to see if the problem goes away.

+
+
+
+

Using phpMyAdmin¶

+
+

6.1 I can’t insert new rows into a table / I can’t create a table - MySQL brings up a SQL error.¶

+

Examine the SQL error with care. +Often the problem is caused by specifying a wrong column-type. Common +errors include:

+
    +
  • Using VARCHAR without a size argument
  • +
  • Using TEXT or BLOB with a size argument
  • +
+

Also, look at the syntax chapter in the MySQL manual to confirm that +your syntax is correct.

+
+
+

6.2 When I create a table, I set an index for two columns and phpMyAdmin generates only one index with those two columns.¶

+

This is the way to create a multi-columns index. If you want two +indexes, create the first one when creating the table, save, then +display the table properties and click the Index link to create the +other index.

+
+
+

6.3 How can I insert a null value into my table?¶

+

Since version 2.2.3, you have a checkbox for each column that can be +null. Before 2.2.3, you had to enter “null”, without the quotes, as +the column’s value. Since version 2.5.5, you have to use the checkbox +to get a real NULL value, so if you enter “NULL” this means you want a +literal NULL in the column, and not a NULL value (this works in PHP4).

+
+
+

6.4 How can I backup my database or table?¶

+

Click on a database or table name in the navigation panel, the properties will +be displayed. Then on the menu, click “Export”, you can dump the structure, the +data, or both. This will generate standard SQL statements that can be +used to recreate your database/table. You will need to choose “Save as file”, +so that phpMyAdmin can transmit the resulting dump to your station. Depending +on your PHP configuration, you will see options to compress the dump. See also +the $cfg['ExecTimeLimit'] configuration variable. For +additional help on this subject, look for the word “dump” in this document.

+
+
+

6.5 How can I restore (upload) my database or table using a dump? How can I run a ”.sql” file?¶

+

Click on a database name in the navigation panel, the properties will +be displayed. Select “Import” from the list of tabs in the right–hand +frame (or “SQL” if your phpMyAdmin +version is previous to 2.7.0). In the “Location of the text file” +section, type in the path to your dump filename, or use the Browse +button. Then click Go. With version 2.7.0, the import engine has been +re–written, if possible it is suggested that you upgrade to take +advantage of the new features. For additional help on this subject, +look for the word “upload” in this document.

+
+
+

6.6 How can I use the relation table in Query-by-example?¶

+

Here is an example with the tables persons, towns and countries, all +located in the database “mydb”. If you don’t have a pma__relation +table, create it as explained in the configuration section. Then +create the example tables:

+
CREATE TABLE REL_countries (
+country_code char(1) NOT NULL default '',
+description varchar(10) NOT NULL default '',
+PRIMARY KEY (country_code)
+) TYPE=MyISAM;
+
+INSERT INTO REL_countries VALUES ('C', 'Canada');
+
+CREATE TABLE REL_persons (
+id tinyint(4) NOT NULL auto_increment,
+person_name varchar(32) NOT NULL default '',
+town_code varchar(5) default '0',
+country_code char(1) NOT NULL default '',
+PRIMARY KEY (id)
+) TYPE=MyISAM;
+
+INSERT INTO REL_persons VALUES (11, 'Marc', 'S', '');
+INSERT INTO REL_persons VALUES (15, 'Paul', 'S', 'C');
+
+CREATE TABLE REL_towns (
+town_code varchar(5) NOT NULL default '0',
+description varchar(30) NOT NULL default '',
+PRIMARY KEY (town_code)
+) TYPE=MyISAM;
+
+INSERT INTO REL_towns VALUES ('S', 'Sherbrooke');
+INSERT INTO REL_towns VALUES ('M', 'Montréal');
+
+
+

To setup appropriate links and display information:

+
    +
  • on table “REL_persons” click Structure, then Relation view
  • +
  • for “town_code”, choose from dropdowns, “mydb”, “REL_towns”, “code” +for foreign database, table and column respectively
  • +
  • for “country_code”, choose from dropdowns, “mydb”, “REL_countries”, +“country_code” for foreign database, table and column respectively
  • +
  • on table “REL_towns” click Structure, then Relation view
  • +
  • in “Choose column to display”, choose “description”
  • +
  • repeat the two previous steps for table “REL_countries”
  • +
+

Then test like this:

+
    +
  • Click on your db name in the navigation panel
  • +
  • Choose “Query”
  • +
  • Use tables: persons, towns, countries
  • +
  • Click “Update query”
  • +
  • In the columns row, choose persons.person_name and click the “Show” +tickbox
  • +
  • Do the same for towns.description and countries.descriptions in the +other 2 columns
  • +
  • Click “Update query” and you will see in the query box that the +correct joins have been generated
  • +
  • Click “Submit query”
  • +
+
+
+

6.7 How can I use the “display column” feature?¶

+

Starting from the previous example, create the pma__table_info as +explained in the configuration section, then browse your persons +table, and move the mouse over a town code or country code. See also +6.21 In edit/insert mode, how can I see a list of possible values for a column, based on some foreign table? for an additional feature that “display column” +enables: drop-down list of possible values.

+
+
+

6.8 How can I produce a PDF schema of my database?¶

+

First the configuration variables “relation”, “table_coords” and +“pdf_pages” have to be filled in. Then you need to think about your +schema layout. Which tables will go on which pages?

+
    +
  • Select your database in the navigation panel.
  • +
  • Choose “Operations” in the navigation bar at the top.
  • +
  • Choose “Edit PDF Pages” near the +bottom of the page.
  • +
  • Enter a name for the first PDF page +and click Go. If you like, you can use the “automatic layout,” which +will put all your linked tables onto the new page.
  • +
  • Select the name of the new page (making sure the Edit radio button is +selected) and click Go.
  • +
  • Select a table from the list, enter its coordinates and click Save. +Coordinates are relative; your diagram will be automatically scaled to +fit the page. When initially placing tables on the page, just pick any +coordinates – say, 50x50. After clicking Save, you can then use the +6.28 How can I easily edit relational schema for export? to position the element correctly.
  • +
  • When you’d like to look at your PDF, first be sure to click the Save +button beneath the list of tables and coordinates, to save any changes you +made there. Then scroll all the way down, select the PDF options you +want, and click Go.
  • +
  • Internet Explorer for Windows may suggest an incorrect filename when +you try to save a generated PDF. +When saving a generated PDF, be +sure that the filename ends in ”.pdf”, for example “schema.pdf”. +Browsers on other operating systems, and other browsers on Windows, do +not have this problem.
  • +
+
+
+

6.9 phpMyAdmin is changing the type of one of my columns!¶

+

No, it’s MySQL that is doing silent column type changing.

+
+
+

6.10 When creating a privilege, what happens with underscores in the database name?¶

+

If you do not put a backslash before the underscore, this is a +wildcard grant, and the underscore means “any character”. So, if the +database name is “john_db”, the user would get rights to john1db, +john2db ... If you put a backslash before the underscore, it means +that the database name will have a real underscore.

+
+
+

6.11 What is the curious symbol ø in the statistics pages?¶

+

It means “average”.

+
+
+

6.12 I want to understand some Export options.¶

+

Structure:

+
    +
  • “Add DROP TABLE” will add a line telling MySQL to drop the table, if it already +exists during the import. It does NOT drop the table after your +export, it only affects the import file.
  • +
  • “If Not Exists” will only create the table if it doesn’t exist. +Otherwise, you may get an error if the table name exists but has a +different structure.
  • +
  • “Add AUTO_INCREMENT value” ensures that AUTO_INCREMENT value (if +any) will be included in backup.
  • +
  • “Enclose table and column names with backquotes” ensures that column +and table names formed with special characters are protected.
  • +
  • “Add into comments” includes column comments, relations, and MIME +types set in the pmadb in the dump as SQL comments +(/* xxx */).
  • +
+

Data:

+
    +
  • “Complete inserts” adds the column names on every INSERT command, for +better documentation (but resulting file is bigger).
  • +
  • “Extended inserts” provides a shorter dump file by using only once the +INSERT verb and the table name.
  • +
  • “Delayed inserts” are best explained in the MySQL manual - INSERT DELAYED Syntax.
  • +
  • “Ignore inserts” treats errors as a warning instead. Again, more info +is provided in the MySQL manual - INSERT Syntax, but basically with +this selected, invalid values are adjusted and inserted rather than +causing the entire statement to fail.
  • +
+
+
+

6.13 I would like to create a database with a dot in its name.¶

+

This is a bad idea, because in MySQL the syntax “database.table” is +the normal way to reference a database and table name. Worse, MySQL +will usually let you create a database with a dot, but then you cannot +work with it, nor delete it.

+
+
+

6.14 How do I set up the SQL Validator?¶

+

To use SQL Validator, you need PHP with XML, PCRE and +PEAR support. In addition you need a SOAP support, either as a +PHP extension or as a PEAR SOAP module.

+

To install PEAR SOAP module, run pear install +Net_Socket Net_URL HTTP_Request Mail_Mime Net_DIME SOAP to get the necessary +PEAR modules for usage.

+

If you use the Validator, you should be aware that any SQL statement +you submit will be stored anonymously (database/table/column names, strings, +numbers replaced with generic values). The Mimer SQL Validator itself, +is © 2001 Upright Database Technology. We utilize it as free SOAP service.

+
+
+

6.15 I want to add a BLOB column and put an index on it, but MySQL says “BLOB column ‘...’ used in key specification without a key length”.¶

+

The right way to do this, is to create the column without any indexes, +then display the table structure and use the “Create an index” dialog. +On this page, you will be able to choose your BLOB column, and set a +size to the index, which is the condition to create an index on a BLOB +column.

+
+
+

6.16 How can I simply move in page with plenty editing fields?¶

+

You can use Ctrl+arrows (Option+Arrows in Safari) for moving on +most pages with many editing fields (table structure changes, row editing, +etc.).

+
+
+

6.17 Transformations: I can’t enter my own mimetype! WTF is this feature then useful for?¶

+

Slow down :). Defining mimetypes is of no use, if you can’t put +transformations on them. Otherwise you could just put a comment on the +column. Because entering your own mimetype will cause serious syntax +checking issues and validation, this introduces a high-risk false- +user-input situation. Instead you have to initialize mimetypes using +functions or empty mimetype definitions.

+

Plus, you have a whole overview of available mimetypes. Who knows all those +mimetypes by heart so he/she can enter it at will?

+
+
+

6.18 Bookmarks: Where can I store bookmarks? Why can’t I see any bookmarks below the query box? What is this variable for?¶

+

Any query you have executed can be stored as a bookmark on the page +where the results are displayed. You will find a button labeled +‘Bookmark this query’ just at the end of the page. As soon as you have +stored a bookmark, it is related to the database you run the query on. +You can now access a bookmark dropdown on each page, the query box +appears on for that database.

+

You can also have, inside the query, a placeholder for a variable. +This is done by inserting into the query a SQL comment between /* and +*/. Inside the comment, the special string [VARIABLE] is used. +Be aware that the whole query minus the SQL comment must be +valid by itself, otherwise you won’t be able to store it as a bookmark.

+

When you execute the bookmark, everything typed into the value +input box on the query box page will replace the string /*[VARIABLE]*/ in +your stored query.

+

Also remember, that everything else inside the /*[VARIABLE]*/ string for +your query will remain the way it is, but will be stripped of the /**/ +chars. So you can use:

+
/*, [VARIABLE] AS myname */
+
+
+

which will be expanded to

+
, VARIABLE as myname
+
+
+

in your query, where VARIABLE is the string you entered in the input box. If an +empty string is provided, no replacements are made.

+

A more complex example. Say you have stored +this query:

+
SELECT Name, Address FROM addresses WHERE 1 /* AND Name LIKE '%[VARIABLE]%' */
+
+
+

Say, you now enter “phpMyAdmin” as the variable for the stored query, the full +query will be:

+
SELECT Name, Address FROM addresses WHERE 1 AND Name LIKE '%phpMyAdmin%'
+
+
+

You can use multiple occurrences of /*[VARIABLE]*/ in a single query +(that is, multiple occurrences of the same variable).

+

NOTE THE ABSENCE OF SPACES inside the /**/ construct. Any spaces +inserted there will be later also inserted as spaces in your query and may lead +to unexpected results especially when using the variable expansion inside of a +“LIKE ‘’” expression.

+

Your initial query which is going to be stored as a bookmark has to yield at +least one result row so you can store the bookmark. You may have that to work +around using well positioned /**/ comments.

+
+
+

6.19 How can I create simple LATEX document to include exported table?¶

+

You can simply include table in your LATEX documents, +minimal sample document should look like following one (assuming you +have table exported in file table.tex):

+
\documentclass{article} % or any class you want
+\usepackage{longtable}  % for displaying table
+\begin{document}        % start of document
+\include{table}         % including exported table
+\end{document}          % end of document
+
+
+
+
+

6.20 I see a lot of databases which are not mine, and cannot access them.¶

+

You have one of these global privileges: CREATE TEMPORARY TABLES, SHOW +DATABASES, LOCK TABLES. Those privileges also enable users to see all the +database names. So if your users do not need those privileges, you can remove +them and their databases list will shorten.

+ +
+
+

6.21 In edit/insert mode, how can I see a list of possible values for a column, based on some foreign table?¶

+

You have to setup appropriate links between the tables, and also setup +the “display column” in the foreign table. See 6.6 How can I use the relation table in Query-by-example? for an +example. Then, if there are 100 values or less in the foreign table, a +drop-down list of values will be available. You will see two lists of +values, the first list containing the key and the display column, the +second list containing the display column and the key. The reason for +this is to be able to type the first letter of either the key or the +display column. For 100 values or more, a distinct window will appear, +to browse foreign key values and choose one. To change the default +limit of 100, see $cfg['ForeignKeyMaxLimit'].

+
+
+

6.22 Bookmarks: Can I execute a default bookmark automatically when entering Browse mode for a table?¶

+

Yes. If a bookmark has the same label as a table name and it’s not a +public bookmark, it will be executed.

+
+
+

6.23 Export: I heard phpMyAdmin can export Microsoft Excel files?¶

+

You can use CSV for Microsoft Excel, +which works out of the box.

+

+Changed in version 3.4.5: Since phpMyAdmin 3.4.5 support for direct export to Microsoft Excel version +97 and newer was dropped.

+
+
+

6.24 Now that phpMyAdmin supports native MySQL 4.1.x column comments, what happens to my column comments stored in pmadb?¶

+

Automatic migration of a table’s pmadb-style column comments to the +native ones is done whenever you enter Structure page for this table.

+
+
+

6.25 (withdrawn).¶

+
+
+

6.26 How can I select a range of rows?¶

+

Click the first row of the range, hold the shift key and click the +last row of the range. This works everywhere you see rows, for example +in Browse mode or on the Structure page.

+
+
+

6.27 What format strings can I use?¶

+

In all places where phpMyAdmin accepts format strings, you can use +@VARIABLE@ expansion and strftime +format strings. The expanded variables depend on a context (for +example, if you haven’t chosen a table, you can not get the table +name), but the following variables can be used:

+
+
@HTTP_HOST@
+
HTTP host that runs phpMyAdmin
+
@SERVER@
+
MySQL server name
+
@VERBOSE@
+
Verbose MySQL server name as defined in $cfg['Servers'][$i]['verbose']
+
@VSERVER@
+
Verbose MySQL server name if set, otherwise normal
+
@DATABASE@
+
Currently opened database
+
@TABLE@
+
Currently opened table
+
@COLUMNS@
+
Columns of the currently opened table
+
@PHPMYADMIN@
+
phpMyAdmin with version
+
+
+
+

6.28 How can I easily edit relational schema for export?¶

+

By clicking on the button ‘toggle scratchboard’ on the page where you +edit x/y coordinates of those elements you can activate a scratchboard +where all your elements are placed. By clicking on an element, you can +move them around in the pre-defined area and the x/y coordinates will +get updated dynamically. Likewise, when entering a new position +directly into the input field, the new position in the scratchboard +changes after your cursor leaves the input field.

+

You have to click on the ‘OK’-button below the tables to save the new +positions. If you want to place a new element, first add it to the +table of elements and then you can drag the new element around.

+

By changing the paper size and the orientation you can change the size +of the scratchboard as well. You can do so by just changing the +dropdown field below, and the scratchboard will resize automatically, +without interfering with the current placement of the elements.

+

If ever an element gets out of range you can either enlarge the paper +size or click on the ‘reset’ button to place all elements below each +other.

+
+
+

6.29 Why can’t I get a chart from my query result table?¶

+

Not every table can be put to the chart. Only tables with one, two or +three columns can be visualised as a chart. Moreover the table must be +in a special format for chart script to understand it. Currently +supported formats can be found in the wiki.

+
+
+

6.30 Import: How can I import ESRI Shapefiles?¶

+

An ESRI Shapefile is actually a set of several files, where .shp file +contains geometry data and .dbf file contains data related to those +geometry data. To read data from .dbf file you need to have PHP +compiled with the dBase extension (–enable-dbase). Otherwise only +geometry data will be imported.

+

To upload these set of files you can use either of the following +methods:

+

Configure upload directory with $cfg['UploadDir'], upload both .shp and .dbf files with +the same filename and chose the .shp file from the import page.

+

Create a Zip archive with .shp and .dbf files and import it. For this +to work, you need to set $cfg['TempDir'] to a place where the web server user can +write (for example './tmp').

+

To create the temporary directory on a UNIX-based system, you can do:

+
cd phpMyAdmin
+mkdir tmp
+chmod o+rwx tmp
+
+
+
+
+

6.31 How do I create a relation in designer?¶

+

To select relation, click: The display column is shown in pink. To +set/unset a column as the display column, click the “Choose column to +display” icon, then click on the appropriate column name.

+
+
+

6.32 How can I use the zoom search feature?¶

+

The Zoom search feature is an alternative to table search feature. It allows +you to explore a table by representing its data in a scatter plot. You can +locate this feature by selecting a table and clicking the Search +tab. One of the sub-tabs in the Table Search page is +Zoom Search.

+

Consider the table REL_persons in 6.6 How can I use the relation table in Query-by-example? for +an example. To use zoom search, two columns need to be selected, for +example, id and town_code. The id values will be represented on one +axis and town_code values on the other axis. Each row will be +represented as a point in a scatter plot based on its id and +town_code. You can include two additional search criteria apart from +the two fields to display.

+

You can choose which field should be +displayed as label for each point. If a display column has been set +for the table (see 6.7 How can I use the “display column” feature?), it is taken as the label unless +you specify otherwise. You can also select the maximum number of rows +you want to be displayed in the plot by specifing it in the ‘Max rows +to plot’ field. Once you have decided over your criteria, click ‘Go’ +to display the plot.

+

After the plot is generated, you can use the +mousewheel to zoom in and out of the plot. In addition, panning +feature is enabled to navigate through the plot. You can zoom-in to a +certail level of detail and use panning to locate your area of +interest. Clicking on a point opens a dialogue box, displaying field +values of the data row represented by the point. You can edit the +values if required and click on submit to issue an update query. Basic +instructions on how to use can be viewed by clicking the ‘How to use?’ +link located just above the plot.

+
+
+

6.33 When browsing a table, how can I copy a column name?¶

+

Selecting the name of the column within the browse table header cell +for copying is difficult, as the columns support reordering by +dragging the header cells as well as sorting by clicking on the linked +column name. To copy a column name, double-click on the empty area +next to the column name, when the tooltip tells you to do so. This +will show you an input box with the column name. You may right-click +the column name within this input box to copy it to your clipboard.

+
+
+
+

phpMyAdmin project¶

+
+

7.1 I have found a bug. How do I inform developers?¶

+

Our Bug Tracker is located at <http://sf.net/projects/phpmyadmin/> under the +Bugs section. But please first discuss your bug with other users: +<https://sourceforge.net/projects/phpmyadmin/forums>.

+
+
+

7.2 I want to translate the messages to a new language or upgrade an existing language, where do I start?¶

+

Translations are very welcome and all you need to have are the +language skills. The easiest way is to use our online translation +service. You can check +out all the possibilities to translate in the translate section on +our website.

+
+
+

7.3 I would like to help out with the development of phpMyAdmin. How should I proceed?¶

+

We welcome every contribution to the development of phpMyAdmin. You +can check out all the possibilities to contribute in the contribute +section on our website.

+ +
+
+
+

Security¶

+
+

8.1 Where can I get information about the security alerts issued for phpMyAdmin?¶

+

Please refer to <http://www.phpmyadmin.net/home_page/security.php>.

+
+
+

8.2 How can I protect phpMyAdmin against brute force attacks?¶

+

If you use Apache web server, phpMyAdmin exports information about +authentication to the Apache environment and it can be used in Apache +logs. Currently there are two variables available:

+
+
userID
+
User name of currently active user (he does not have to be logged in).
+
userStatus
+
Status of currently active user, one of ok (user is logged in), +mysql-denied (MySQL denied user login), allow-denied (user denied +by allow/deny rules), root-denied (root is denied in configuration), +empty-denied (empty password is denied).
+
+

LogFormat directive for Apache can look like following:

+
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %{userID}n %{userStatus}n"   pma_combined
+
+
+

You can then use any log analyzing tools to detect possible break-in +attempts.

+
+
+
+

Synchronization¶

+
+

9.1 (withdrawn).¶

+
+
+

9.2 (withdrawn).¶

+
+
+
+ + +
+
+
+
+
+

Table Of Contents

+ + +

Previous topic

+

Other sources of information

+

Next topic

+

Developers Information

+

This Page

+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/phpMyAdmin/doc/html/genindex.html b/phpMyAdmin/doc/html/genindex.html new file mode 100644 index 0000000..8c96c43 --- /dev/null +++ b/phpMyAdmin/doc/html/genindex.html @@ -0,0 +1,3847 @@ + + + + + + + + + + + + Index — phpMyAdmin 4.1.7 documentation + + + + + + + + + + + + + + +
+
+
+
+ + +

Index

+ +
+ Symbols + | A + | B + | C + | D + | E + | F + | G + | H + | I + | J + | K + | L + | M + | N + | O + | P + | Q + | R + | S + | T + | U + | V + | W + | X + | Z + +
+

Symbols

+ + + +
+ +
$cfg['ActionLinksMode'] +
+ + +
$cfg['AllowArbitraryServer'], [1], [2] +
+ + +
$cfg['AllowThirdPartyFraming'] +
+ + +
$cfg['AllowUserDropDatabase'] +
+ + +
$cfg['AvailableCharsets'] +
+ + +
$cfg['BgOne'] +
+ + +
$cfg['BgTwo'] +
+ + +
$cfg['blowfish_secret'], [1] +
+ + +
$cfg['Border'] +
+ + +
$cfg['BrowseMarkerBackground'] +
+ + +
$cfg['BrowseMarkerColor'] +
+ + +
$cfg['BrowseMarkerEnable'] +
+ + +
$cfg['BrowseMIME'] +
+ + +
$cfg['BrowsePointerBackground'] +
+ + +
$cfg['BrowsePointerColor'] +
+ + +
$cfg['BrowsePointerEnable'] +
+ + +
$cfg['BZipDump'] +
+ + +
$cfg['CaptchaLoginPrivateKey'], [1] +
+ + +
$cfg['CaptchaLoginPublicKey'], [1] +
+ + +
$cfg['CharEditing'], [1] +
+ + +
$cfg['CharTextareaCols'] +
+ + +
$cfg['CharTextareaRows'] +
+ + +
$cfg['CheckConfigurationPermissions'] +
+ + +
$cfg['CodemirrorEnable'] +
+ + +
$cfg['CompressOnFly'], [1] +
+ + +
$cfg['Confirm'] +
+ + +
$cfg['CSPAllow'] +
+ + +
$cfg['DBG'] +
+ + +
$cfg['DBG']['demo'] +
+ + +
$cfg['DBG']['sql'] +
+ + +
$cfg['DefaultConnectionCollation'] +
+ + +
$cfg['DefaultDisplay'] +
+ + +
$cfg['DefaultFunctions'] +
+ + +
$cfg['DefaultLang'] +
+ + +
$cfg['DefaultQueryDatabase'] +
+ + +
$cfg['DefaultQueryTable'] +
+ + +
$cfg['DefaultTabDatabase'] +
+ + +
$cfg['DefaultTabServer'] +
+ + +
$cfg['DefaultTabTable'] +
+ + +
$cfg['DisableMultiTableMaintenance'] +
+ + +
$cfg['DisplayBinaryAsHex'] +
+ + +
$cfg['DisplayServersList'] +
+ + +
$cfg['EditInWindow'], [1] +
+ + +
$cfg['Error_Handler']['display'] +
+ + +
$cfg['ExecTimeLimit'], [1] +
+ + +
$cfg['Export'] +
+ + +
$cfg['Export']['charset'] +
+ + +
$cfg['Export']['method'] +
+ + +
$cfg['FilterLanguages'] +
+ + +
$cfg['FontFamily'] +
+ + +
$cfg['FontFamilyFixed'] +
+ + +
$cfg['ForceSSL'] +
+ + +
$cfg['ForeignKeyDropdownOrder'], [1] +
+ + +
$cfg['ForeignKeyMaxLimit'], [1] +
+ + +
$cfg['GD2Available'] +
+ + +
$cfg['GridEditing'] +
+ + +
$cfg['GZipDump'] +
+ + +
$cfg['HeaderFlipType'] +
+ + +
$cfg['HideStructureActions'] +
+ + +
$cfg['IconvExtraParams'] +
+ + +
$cfg['IgnoreMultiSubmitErrors'] +
+ + +
$cfg['Import'] +
+ + +
$cfg['Import']['charset'] +
+ + +
$cfg['InitialSlidersState'] +
+ + +
$cfg['InsertRows'] +
+ + +
$cfg['Lang'] +
+ + +
$cfg['LimitChars'] +
+ + +
$cfg['LinkLengthLimit'] +
+ + +
$cfg['LoginCookieDeleteAll'] +
+ + +
$cfg['LoginCookieRecall'] +
+ + +
$cfg['LoginCookieStore'] +
+ + +
$cfg['LoginCookieValidity'], [1] +
+ + +
$cfg['LongtextDoubleTextarea'] +
+ + +
$cfg['MainBackground'] +
+ + +
$cfg['MaxCharactersInDisplayedSQL'] +
+ + +
$cfg['MaxDbList'] +
+ + +
$cfg['MaxExactCount'], [1] +
+ + +
$cfg['MaxExactCountViews'] +
+ + +
$cfg['MaxNavigationItems'] +
+ + +
$cfg['MaxRows'] +
+ + +
$cfg['MaxSizeForInputField'] +
+ + +
$cfg['MaxTableList'] +
+ + +
$cfg['McryptDisableWarning'] +
+ + +
$cfg['MemoryLimit'] +
+ + +
$cfg['MinSizeForInputField'] +
+ + +
$cfg['NaturalOrder'] +
+ + +
$cfg['NaviBackground'] +
+ + +
$cfg['NavigationDisplayLogo'] +
+ + +
$cfg['NavigationDisplayServers'] +
+ + +
$cfg['NavigationLogoLink'] +
+ + +
$cfg['NavigationLogoLinkWindow'] +
+ + +
$cfg['NavigationTreeDbSeparator'], [1] +
+ + +
$cfg['NavigationTreeDefaultTabTable'], [1] +
+ + +
$cfg['NavigationTreeDisplayDbFilterMinimum'] +
+ + +
$cfg['NavigationTreeDisplayItemFilterMinimum'] +
+ + +
$cfg['NavigationTreeEnableGrouping'] +
+ + +
$cfg['NavigationTreePointerEnable'] +
+ + +
$cfg['NavigationTreeTableLevel'] +
+ + +
$cfg['NavigationTreeTableSeparator'], [1] +
+ + +
$cfg['NaviPointerBackground'] +
+ + +
$cfg['NaviPointerColor'] +
+ + +
$cfg['NaviWidth'] +
+ + +
$cfg['NumRecentTables'], [1] +
+ + +
$cfg['OBGzip'], [1], [2], [3] +
+ + +
$cfg['Order'] +
+ + +
$cfg['PDFDefaultPageSize'] +
+ + +
$cfg['PDFPageSizes'], [1] +
+ + +
$cfg['PersistentConnections'] +
+ + +
$cfg['PmaAbsoluteUri'], [1], [2], [3], [4], [5], [6] +
+ + +
$cfg['PmaNoRelation_DisableWarning'] +
+ + +
$cfg['PropertiesNumColumns'] +
+ + +
$cfg['ProtectBinary'] +
+ + +
$cfg['ProxyPass'] +
+ + +
$cfg['ProxyUrl'] +
+ + +
$cfg['ProxyUser'] +
+ + +
$cfg['QueryHistoryDB'], [1], [2] +
+ + +
$cfg['QueryHistoryMax'], [1], [2] +
+ + +
$cfg['QueryWindowDefTab'], [1] +
+ + +
$cfg['QueryWindowHeight'], [1] +
+ + +
$cfg['QueryWindowWidth'], [1] +
+ + +
$cfg['RecodingEngine'] +
+ + +
$cfg['RememberSorting'], [1] +
+ +
+ +
$cfg['RepeatCells'] +
+ + +
$cfg['ReservedWordDisableWarning'] +
+ + +
$cfg['RetainQueryBox'] +
+ + +
$cfg['RowActionLinks'] +
+ + +
$cfg['SaveCellsAtOnce'] +
+ + +
$cfg['SaveDir'] +
+ + +
$cfg['SendErrorReports'] +
+ + +
$cfg['ServerDefault'], [1], [2] +
+ + +
$cfg['ServerLibraryDifference_DisableWarning'] +
+ + +
$cfg['Servers'], [1], [2], [3] +
+ + +
$cfg['Servers'][$i]['AllowDeny']['order'], [1], [2] +
+ + +
$cfg['Servers'][$i]['AllowDeny']['rules'], [1], [2], [3], [4], [5] +
+ + +
$cfg['Servers'][$i]['AllowNoPassword'] +
+ + +
$cfg['Servers'][$i]['AllowRoot'] +
+ + +
$cfg['Servers'][$i]['auth_http_realm'] +
+ + +
$cfg['Servers'][$i]['auth_swekey_config'], [1] +
+ + +
$cfg['Servers'][$i]['auth_type'], [1], [2] +
+ + +
$cfg['Servers'][$i]['bookmarktable'], [1] +
+ + +
$cfg['Servers'][$i]['column_comments'] +
+ + +
$cfg['Servers'][$i]['column_info'], [1], [2] +
+ + +
$cfg['Servers'][$i]['compress'] +
+ + +
$cfg['Servers'][$i]['connect_type'] +
+ + +
$cfg['Servers'][$i]['controlhost'] +
+ + +
$cfg['Servers'][$i]['controlpass'], [1], [2] +
+ + +
$cfg['Servers'][$i]['controlport'] +
+ + +
$cfg['Servers'][$i]['controluser'], [1], [2], [3] +
+ + +
$cfg['Servers'][$i]['designer_coords'], [1] +
+ + +
$cfg['Servers'][$i]['extension'], [1], [2], [3], [4] +
+ + +
$cfg['Servers'][$i]['hide_db'] +
+ + +
$cfg['Servers'][$i]['history'], [1], [2] +
+ + +
$cfg['Servers'][$i]['host'], [1], [2], [3], [4] +
+ + +
$cfg['Servers'][$i]['LogoutURL'] +
+ + +
$cfg['Servers'][$i]['MaxTableUiprefs'] +
+ + +
$cfg['Servers'][$i]['navigationhiding'], [1] +
+ + +
$cfg['Servers'][$i]['nopassword'] +
+ + +
$cfg['Servers'][$i]['only_db'], [1] +
+ + +
$cfg['Servers'][$i]['password'], [1] +
+ + +
$cfg['Servers'][$i]['pdf_pages'], [1] +
+ + +
$cfg['Servers'][$i]['pmadb'], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12], [13], [14], [15], [16], [17] +
+ + +
$cfg['Servers'][$i]['port'] +
+ + +
$cfg['Servers'][$i]['recent'], [1] +
+ + +
$cfg['Servers'][$i]['relation'], [1] +
+ + +
$cfg['Servers'][$i]['SignonScript'], [1], [2], [3] +
+ + +
$cfg['Servers'][$i]['SignonSession'], [1], [2] +
+ + +
$cfg['Servers'][$i]['SignonURL'], [1], [2] +
+ + +
$cfg['Servers'][$i]['socket'], [1] +
+ + +
$cfg['Servers'][$i]['ssl'] +
+ + +
$cfg['Servers'][$i]['ssl_ca'] +
+ + +
$cfg['Servers'][$i]['ssl_ca_path'] +
+ + +
$cfg['Servers'][$i]['ssl_cert'] +
+ + +
$cfg['Servers'][$i]['ssl_ciphers'] +
+ + +
$cfg['Servers'][$i]['ssl_key'] +
+ + +
$cfg['Servers'][$i]['StatusCacheDatabases'], [1] +
+ + +
$cfg['Servers'][$i]['StatusCacheLifetime'], [1] +
+ + +
$cfg['Servers'][$i]['table_coords'], [1] +
+ + +
$cfg['Servers'][$i]['table_info'], [1] +
+ + +
$cfg['Servers'][$i]['table_uiprefs'], [1], [2], [3], [4] +
+ + +
$cfg['Servers'][$i]['tracking'], [1] +
+ + +
$cfg['Servers'][$i]['tracking_add_drop_database'] +
+ + +
$cfg['Servers'][$i]['tracking_add_drop_table'] +
+ + +
$cfg['Servers'][$i]['tracking_add_drop_view'] +
+ + +
$cfg['Servers'][$i]['tracking_default_statements'] +
+ + +
$cfg['Servers'][$i]['tracking_version_auto_create'] +
+ + +
$cfg['Servers'][$i]['user'], [1] +
+ + +
$cfg['Servers'][$i]['userconfig'], [1] +
+ + +
$cfg['Servers'][$i]['usergroups'], [1] +
+ + +
$cfg['Servers'][$i]['users'], [1] +
+ + +
$cfg['Servers'][$i]['verbose'], [1], [2], [3] +
+ + +
$cfg['SessionSavePath'] +
+ + +
$cfg['ShowAll'] +
+ + +
$cfg['ShowBrowseComments'] +
+ + +
$cfg['ShowChgPassword'] +
+ + +
$cfg['ShowCreateDb'] +
+ + +
$cfg['ShowDbStructureCreation'] +
+ + +
$cfg['ShowDbStructureLastCheck'] +
+ + +
$cfg['ShowDbStructureLastUpdate'] +
+ + +
$cfg['ShowDisplayDirection'] +
+ + +
$cfg['ShowFieldTypesInDataEditView'] +
+ + +
$cfg['ShowFunctionFields'] +
+ + +
$cfg['ShowHint'] +
+ + +
$cfg['ShowPhpInfo'] +
+ + +
$cfg['ShowPropertyComments'] +
+ + +
$cfg['ShowServerInfo'] +
+ + +
$cfg['ShowSQL'] +
+ + +
$cfg['ShowStats'] +
+ + +
$cfg['SkipLockedTables'] +
+ + +
$cfg['SQLQuery']['Edit'] +
+ + +
$cfg['SQLQuery']['Explain'] +
+ + +
$cfg['SQLQuery']['Refresh'] +
+ + +
$cfg['SQLQuery']['ShowAsPHP'] +
+ + +
$cfg['SQLQuery']['Validate'] +
+ + +
$cfg['SQLValidator'], [1] +
+ + +
$cfg['SQLValidator']['password'] +
+ + +
$cfg['SQLValidator']['use'] +
+ + +
$cfg['SQLValidator']['username'] +
+ + +
$cfg['SuhosinDisableWarning'], [1] +
+ + +
$cfg['TableNavigationLinksMode'] +
+ + +
$cfg['TabsMode'] +
+ + +
$cfg['TempDir'], [1], [2] +
+ + +
$cfg['TextareaAutoSelect'] +
+ + +
$cfg['TextareaCols'] +
+ + +
$cfg['TextareaRows'] +
+ + +
$cfg['ThBackground'] +
+ + +
$cfg['ThColor'] +
+ + +
$cfg['ThemeDefault'], [1] +
+ + +
$cfg['ThemeManager'], [1], [2] +
+ + +
$cfg['ThemePath'], [1], [2], [3], [4] +
+ + +
$cfg['ThemePerServer'] +
+ + +
$cfg['TitleDatabase'] +
+ + +
$cfg['TitleDefault'] +
+ + +
$cfg['TitleServer'] +
+ + +
$cfg['TitleTable'] +
+ + +
$cfg['TranslationWarningThreshold'] +
+ + +
$cfg['TrustedProxies'], [1] +
+ + +
$cfg['UploadDir'], [1], [2] +
+ + +
$cfg['UseDbSearch'] +
+ + +
$cfg['UserprefsDeveloperTab'] +
+ + +
$cfg['UserprefsDisallow'], [1] +
+ + +
$cfg['VersionCheck'] +
+ + +
$cfg['ZipDump'] +
+ + +
.htaccess +
+ +
+ +

A

+ + + +
+ +
ACL +
+ + +
ActionLinksMode +
+ + +
AllowArbitraryServer +
+ + +
AllowDeny, order +
+ + +
AllowDeny, rules +
+ + +
AllowNoPassword +
+ + +
AllowRoot +
+ +
+ +
AllowThirdPartyFraming +
+ + +
AllowUserDropDatabase +
+ + +
auth_http_realm +
+ + +
auth_swekey_config +
+ + +
auth_type +
+ + +
Authentication mode +
+ +
+ +
Config +
+ + +
Cookie +
+ + +
HTTP +
+ + +
Signon +
+ + +
Swekey +
+ +
+ +
AvailableCharsets +
+ +
+ +

B

+ + + +
+ +
BgOne +
+ + +
BgTwo +
+ + +
Blowfish +
+ + +
blowfish_secret +
+ + +
bookmarktable +
+ + +
Border +
+ + +
BrowseMarkerBackground +
+ + +
BrowseMarkerColor +
+ +
+ +
BrowseMarkerEnable +
+ + +
BrowseMIME +
+ + +
BrowsePointerBackground +
+ + +
BrowsePointerColor +
+ + +
BrowsePointerEnable +
+ + +
Browser +
+ + +
bzip2 +
+ + +
BZipDump +
+ +
+ +

C

+ + + +
+ +
CaptchaLoginPrivateKey +
+ + +
CaptchaLoginPublicKey +
+ + +
CGI +
+ + +
Changelog +
+ + +
CharEditing +
+ + +
CharTextareaCols +
+ + +
CharTextareaRows +
+ + +
CheckConfigurationPermissions +
+ + +
Client +
+ + +
CodemirrorEnable +
+ + +
column +
+ + +
column_info +
+ + +
compress +
+ + +
CompressOnFly +
+ +
+ +
+ Config +
+ +
+ +
Authentication mode +
+ +
+ +
config.inc.php +
+ + +
+ configuration option +
+ +
+ +
$cfg['ActionLinksMode'] +
+ + +
$cfg['AllowArbitraryServer'], [1], [2] +
+ + +
$cfg['AllowThirdPartyFraming'] +
+ + +
$cfg['AllowUserDropDatabase'] +
+ + +
$cfg['AvailableCharsets'] +
+ + +
$cfg['BZipDump'] +
+ + +
$cfg['BgOne'] +
+ + +
$cfg['BgTwo'] +
+ + +
$cfg['Border'] +
+ + +
$cfg['BrowseMIME'] +
+ + +
$cfg['BrowseMarkerBackground'] +
+ + +
$cfg['BrowseMarkerColor'] +
+ + +
$cfg['BrowseMarkerEnable'] +
+ + +
$cfg['BrowsePointerBackground'] +
+ + +
$cfg['BrowsePointerColor'] +
+ + +
$cfg['BrowsePointerEnable'] +
+ + +
$cfg['CSPAllow'] +
+ + +
$cfg['CaptchaLoginPrivateKey'], [1] +
+ + +
$cfg['CaptchaLoginPublicKey'], [1] +
+ + +
$cfg['CharEditing'], [1] +
+ + +
$cfg['CharTextareaCols'] +
+ + +
$cfg['CharTextareaRows'] +
+ + +
$cfg['CheckConfigurationPermissions'] +
+ + +
$cfg['CodemirrorEnable'] +
+ + +
$cfg['CompressOnFly'], [1] +
+ + +
$cfg['Confirm'] +
+ + +
$cfg['DBG'] +
+ + +
$cfg['DBG']['demo'] +
+ + +
$cfg['DBG']['sql'] +
+ + +
$cfg['DefaultConnectionCollation'] +
+ + +
$cfg['DefaultDisplay'] +
+ + +
$cfg['DefaultFunctions'] +
+ + +
$cfg['DefaultLang'] +
+ + +
$cfg['DefaultQueryDatabase'] +
+ + +
$cfg['DefaultQueryTable'] +
+ + +
$cfg['DefaultTabDatabase'] +
+ + +
$cfg['DefaultTabServer'] +
+ + +
$cfg['DefaultTabTable'] +
+ + +
$cfg['DisableMultiTableMaintenance'] +
+ + +
$cfg['DisplayBinaryAsHex'] +
+ + +
$cfg['DisplayServersList'] +
+ + +
$cfg['EditInWindow'], [1] +
+ + +
$cfg['Error_Handler']['display'] +
+ + +
$cfg['ExecTimeLimit'], [1] +
+ + +
$cfg['Export'] +
+ + +
$cfg['Export']['charset'] +
+ + +
$cfg['Export']['method'] +
+ + +
$cfg['FilterLanguages'] +
+ + +
$cfg['FontFamily'] +
+ + +
$cfg['FontFamilyFixed'] +
+ + +
$cfg['ForceSSL'] +
+ + +
$cfg['ForeignKeyDropdownOrder'], [1] +
+ + +
$cfg['ForeignKeyMaxLimit'], [1] +
+ + +
$cfg['GD2Available'] +
+ + +
$cfg['GZipDump'] +
+ + +
$cfg['GridEditing'] +
+ + +
$cfg['HeaderFlipType'] +
+ + +
$cfg['HideStructureActions'] +
+ + +
$cfg['IconvExtraParams'] +
+ + +
$cfg['IgnoreMultiSubmitErrors'] +
+ + +
$cfg['Import'] +
+ + +
$cfg['Import']['charset'] +
+ + +
$cfg['InitialSlidersState'] +
+ + +
$cfg['InsertRows'] +
+ + +
$cfg['Lang'] +
+ + +
$cfg['LimitChars'] +
+ + +
$cfg['LinkLengthLimit'] +
+ + +
$cfg['LoginCookieDeleteAll'] +
+ + +
$cfg['LoginCookieRecall'] +
+ + +
$cfg['LoginCookieStore'] +
+ + +
$cfg['LoginCookieValidity'], [1] +
+ + +
$cfg['LongtextDoubleTextarea'] +
+ + +
$cfg['MainBackground'] +
+ + +
$cfg['MaxCharactersInDisplayedSQL'] +
+ + +
$cfg['MaxDbList'] +
+ + +
$cfg['MaxExactCount'], [1] +
+ + +
$cfg['MaxExactCountViews'] +
+ + +
$cfg['MaxNavigationItems'] +
+ + +
$cfg['MaxRows'] +
+ + +
$cfg['MaxSizeForInputField'] +
+ + +
$cfg['MaxTableList'] +
+ + +
$cfg['McryptDisableWarning'] +
+ + +
$cfg['MemoryLimit'] +
+ + +
$cfg['MinSizeForInputField'] +
+ + +
$cfg['NaturalOrder'] +
+ + +
$cfg['NaviBackground'] +
+ + +
$cfg['NaviPointerBackground'] +
+ + +
$cfg['NaviPointerColor'] +
+ + +
$cfg['NaviWidth'] +
+ + +
$cfg['NavigationDisplayLogo'] +
+ + +
$cfg['NavigationDisplayServers'] +
+ + +
$cfg['NavigationLogoLink'] +
+ + +
$cfg['NavigationLogoLinkWindow'] +
+ + +
$cfg['NavigationTreeDbSeparator'], [1] +
+ + +
$cfg['NavigationTreeDefaultTabTable'], [1] +
+ + +
$cfg['NavigationTreeDisplayDbFilterMinimum'] +
+ + +
$cfg['NavigationTreeDisplayItemFilterMinimum'] +
+ + +
$cfg['NavigationTreeEnableGrouping'] +
+ + +
$cfg['NavigationTreePointerEnable'] +
+ + +
$cfg['NavigationTreeTableLevel'] +
+ + +
$cfg['NavigationTreeTableSeparator'], [1] +
+ + +
$cfg['NumRecentTables'], [1] +
+ + +
$cfg['OBGzip'], [1], [2], [3] +
+ + +
$cfg['Order'] +
+ + +
$cfg['PDFDefaultPageSize'] +
+ + +
$cfg['PDFPageSizes'], [1] +
+ + +
$cfg['PersistentConnections'] +
+ + +
$cfg['PmaAbsoluteUri'], [1], [2], [3], [4], [5], [6] +
+ + +
$cfg['PmaNoRelation_DisableWarning'] +
+ + +
$cfg['PropertiesNumColumns'] +
+ + +
$cfg['ProtectBinary'] +
+ + +
$cfg['ProxyPass'] +
+ + +
$cfg['ProxyUrl'] +
+ + +
$cfg['ProxyUser'] +
+ + +
$cfg['QueryHistoryDB'], [1], [2] +
+ + +
$cfg['QueryHistoryMax'], [1], [2] +
+ + +
$cfg['QueryWindowDefTab'], [1] +
+ + +
$cfg['QueryWindowHeight'], [1] +
+ + +
$cfg['QueryWindowWidth'], [1] +
+ + +
$cfg['RecodingEngine'] +
+ + +
$cfg['RememberSorting'], [1] +
+ + +
$cfg['RepeatCells'] +
+ + +
$cfg['ReservedWordDisableWarning'] +
+ + +
$cfg['RetainQueryBox'] +
+ + +
$cfg['RowActionLinks'] +
+ + +
$cfg['SQLQuery']['Edit'] +
+ + +
$cfg['SQLQuery']['Explain'] +
+ + +
$cfg['SQLQuery']['Refresh'] +
+ + +
$cfg['SQLQuery']['ShowAsPHP'] +
+ + +
$cfg['SQLQuery']['Validate'] +
+ + +
$cfg['SQLValidator'], [1] +
+ + +
$cfg['SQLValidator']['password'] +
+ + +
$cfg['SQLValidator']['use'] +
+ + +
$cfg['SQLValidator']['username'] +
+ + +
$cfg['SaveCellsAtOnce'] +
+ + +
$cfg['SaveDir'] +
+ + +
$cfg['SendErrorReports'] +
+ + +
$cfg['ServerDefault'], [1], [2] +
+ + +
$cfg['ServerLibraryDifference_DisableWarning'] +
+ + +
$cfg['Servers'], [1], [2], [3] +
+ + +
$cfg['Servers'][$i]['AllowDeny']['order'], [1], [2] +
+ + +
$cfg['Servers'][$i]['AllowDeny']['rules'], [1], [2], [3], [4], [5] +
+ + +
$cfg['Servers'][$i]['AllowNoPassword'] +
+ + +
$cfg['Servers'][$i]['AllowRoot'] +
+ + +
$cfg['Servers'][$i]['LogoutURL'] +
+ + +
$cfg['Servers'][$i]['MaxTableUiprefs'] +
+ + +
$cfg['Servers'][$i]['SignonScript'], [1], [2], [3] +
+ + +
$cfg['Servers'][$i]['SignonSession'], [1], [2] +
+ + +
$cfg['Servers'][$i]['SignonURL'], [1], [2] +
+ + +
$cfg['Servers'][$i]['StatusCacheDatabases'], [1] +
+ + +
$cfg['Servers'][$i]['StatusCacheLifetime'], [1] +
+ + +
$cfg['Servers'][$i]['auth_http_realm'] +
+ + +
$cfg['Servers'][$i]['auth_swekey_config'], [1] +
+ + +
$cfg['Servers'][$i]['auth_type'], [1], [2] +
+ + +
$cfg['Servers'][$i]['bookmarktable'], [1] +
+ + +
$cfg['Servers'][$i]['column_comments'] +
+ + +
$cfg['Servers'][$i]['column_info'], [1], [2] +
+ + +
$cfg['Servers'][$i]['compress'] +
+ + +
$cfg['Servers'][$i]['connect_type'] +
+ + +
$cfg['Servers'][$i]['controlhost'] +
+ + +
$cfg['Servers'][$i]['controlpass'], [1], [2] +
+ + +
$cfg['Servers'][$i]['controlport'] +
+ + +
$cfg['Servers'][$i]['controluser'], [1], [2], [3] +
+ + +
$cfg['Servers'][$i]['designer_coords'], [1] +
+ + +
$cfg['Servers'][$i]['extension'], [1], [2], [3], [4] +
+ + +
$cfg['Servers'][$i]['hide_db'] +
+ + +
$cfg['Servers'][$i]['history'], [1], [2] +
+ + +
$cfg['Servers'][$i]['host'], [1], [2], [3], [4] +
+ + +
$cfg['Servers'][$i]['navigationhiding'], [1] +
+ + +
$cfg['Servers'][$i]['nopassword'] +
+ + +
$cfg['Servers'][$i]['only_db'], [1] +
+ + +
$cfg['Servers'][$i]['password'], [1] +
+ + +
$cfg['Servers'][$i]['pdf_pages'], [1] +
+ + +
$cfg['Servers'][$i]['pmadb'], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12], [13], [14], [15], [16], [17] +
+ + +
$cfg['Servers'][$i]['port'] +
+ + +
$cfg['Servers'][$i]['recent'], [1] +
+ + +
$cfg['Servers'][$i]['relation'], [1] +
+ + +
$cfg['Servers'][$i]['socket'], [1] +
+ + +
$cfg['Servers'][$i]['ssl'] +
+ + +
$cfg['Servers'][$i]['ssl_ca'] +
+ + +
$cfg['Servers'][$i]['ssl_ca_path'] +
+ + +
$cfg['Servers'][$i]['ssl_cert'] +
+ + +
$cfg['Servers'][$i]['ssl_ciphers'] +
+ + +
$cfg['Servers'][$i]['ssl_key'] +
+ + +
$cfg['Servers'][$i]['table_coords'], [1] +
+ + +
$cfg['Servers'][$i]['table_info'], [1] +
+ + +
$cfg['Servers'][$i]['table_uiprefs'], [1], [2], [3], [4] +
+ + +
$cfg['Servers'][$i]['tracking'], [1] +
+ + +
$cfg['Servers'][$i]['tracking_add_drop_database'] +
+ + +
$cfg['Servers'][$i]['tracking_add_drop_table'] +
+ + +
$cfg['Servers'][$i]['tracking_add_drop_view'] +
+ + +
$cfg['Servers'][$i]['tracking_default_statements'] +
+ + +
$cfg['Servers'][$i]['tracking_version_auto_create'] +
+ + +
$cfg['Servers'][$i]['user'], [1] +
+ + +
$cfg['Servers'][$i]['userconfig'], [1] +
+ + +
$cfg['Servers'][$i]['usergroups'], [1] +
+ + +
$cfg['Servers'][$i]['users'], [1] +
+ + +
$cfg['Servers'][$i]['verbose'], [1], [2], [3] +
+ + +
$cfg['SessionSavePath'] +
+ + +
$cfg['ShowAll'] +
+ + +
$cfg['ShowBrowseComments'] +
+ + +
$cfg['ShowChgPassword'] +
+ + +
$cfg['ShowCreateDb'] +
+ + +
$cfg['ShowDbStructureCreation'] +
+ + +
$cfg['ShowDbStructureLastCheck'] +
+ + +
$cfg['ShowDbStructureLastUpdate'] +
+ + +
$cfg['ShowDisplayDirection'] +
+ + +
$cfg['ShowFieldTypesInDataEditView'] +
+ + +
$cfg['ShowFunctionFields'] +
+ + +
$cfg['ShowHint'] +
+ + +
$cfg['ShowPhpInfo'] +
+ + +
$cfg['ShowPropertyComments'] +
+ + +
$cfg['ShowSQL'] +
+ + +
$cfg['ShowServerInfo'] +
+ + +
$cfg['ShowStats'] +
+ + +
$cfg['SkipLockedTables'] +
+ + +
$cfg['SuhosinDisableWarning'], [1] +
+ + +
$cfg['TableNavigationLinksMode'] +
+ + +
$cfg['TabsMode'] +
+ + +
$cfg['TempDir'], [1], [2] +
+ + +
$cfg['TextareaAutoSelect'] +
+ + +
$cfg['TextareaCols'] +
+ + +
$cfg['TextareaRows'] +
+ + +
$cfg['ThBackground'] +
+ + +
$cfg['ThColor'] +
+ + +
$cfg['ThemeDefault'], [1] +
+ + +
$cfg['ThemeManager'], [1], [2] +
+ + +
$cfg['ThemePath'], [1], [2], [3], [4] +
+ + +
$cfg['ThemePerServer'] +
+ + +
$cfg['TitleDatabase'] +
+ + +
$cfg['TitleDefault'] +
+ + +
$cfg['TitleServer'] +
+ + +
$cfg['TitleTable'] +
+ + +
$cfg['TranslationWarningThreshold'] +
+ + +
$cfg['TrustedProxies'], [1] +
+ + +
$cfg['UploadDir'], [1], [2] +
+ + +
$cfg['UseDbSearch'] +
+ + +
$cfg['UserprefsDeveloperTab'] +
+ + +
$cfg['UserprefsDisallow'], [1] +
+ + +
$cfg['VersionCheck'] +
+ + +
$cfg['ZipDump'] +
+ + +
$cfg['blowfish_secret'], [1] +
+ +
+ +
Configuration storage +
+ + +
Confirm +
+ + +
connect_type +
+ + +
controlhost +
+ + +
controlpass +
+ + +
controlport +
+ + +
controluser +
+ + +
Cookie +
+ +
+ +
Authentication mode +
+ +
+ +
CSPAllow +
+ + +
CSV +
+ +
+ +

D

+ + + +
+ +
database +
+ + +
DB +
+ + +
DBG +
+ + +
DBG, demo +
+ + +
DBG, sql +
+ + +
DefaultConnectionCollation +
+ + +
DefaultDisplay +
+ + +
DefaultFunctions +
+ + +
DefaultLang +
+ +
+ +
DefaultQueryDatabase +
+ + +
DefaultQueryTable +
+ + +
DefaultTabDatabase +
+ + +
DefaultTabServer +
+ + +
DefaultTabTable +
+ + +
designer_coords +
+ + +
DisableMultiTableMaintenance +
+ + +
DisplayBinaryAsHex +
+ + +
DisplayServersList +
+ +
+ +

E

+ + + +
+ +
EditInWindow +
+ + +
Engine +
+ + +
Error_Handler, display +
+ + +
ExecTimeLimit +
+ +
+ +
Export +
+ + +
Export, method +
+ + +
extension, [1] +
+ +
+ +

F

+ + + +
+ +
FAQ +
+ + +
Field +
+ + +
FilterLanguages +
+ + +
FontFamily +
+ + +
FontFamilyFixed +
+ +
+ +
ForceSSL +
+ + +
foreign key +
+ + +
ForeignKeyDropdownOrder +
+ + +
ForeignKeyMaxLimit +
+ + +
FPDF +
+ +
+ +

G

+ + + +
+ +
GD +
+ + +
GD2 +
+ + +
GD2Available +
+ +
+ +
GridEditing +
+ + +
gzip +
+ + +
GZipDump +
+ +
+ +

H

+ + + +
+ +
HeaderFlipType +
+ + +
hide_db +
+ + +
HideStructureActions +
+ + +
history +
+ +
+ +
host, [1] +
+ + +
hostname +
+ + +
HTTP +
+ +
+ +
Authentication mode +
+ +
+ +
https +
+ +
+ +

I

+ + + +
+ +
IconvExtraParams +
+ + +
IEC +
+ + +
IgnoreMultiSubmitErrors +
+ + +
IIS +
+ + +
Import +
+ + +
Index +
+ + +
InitialSlidersState +
+ +
+ +
InsertRows +
+ + +
IP +
+ + +
IP Address +
+ + +
IPv6 +
+ + +
ISAPI +
+ + +
ISO +
+ + +
ISP +
+ +
+ +

J

+ + + +
+ +
JPEG +
+ +
+ +
JPG +
+ +
+ +

K

+ + +
+ +
Key +
+ +
+ +

L

+ + + +
+ +
Lang +
+ + +
LATEX +
+ + +
LimitChars +
+ + +
LinkLengthLimit +
+ + +
LoginCookieDeleteAll +
+ +
+ +
LoginCookieRecall +
+ + +
LoginCookieStore +
+ + +
LoginCookieValidity +
+ + +
LogoutURL +
+ + +
LongtextDoubleTextarea +
+ +
+ +

M

+ + + +
+ +
Mac +
+ + +
Mac OS X +
+ + +
MainBackground +
+ + +
MaxCharactersInDisplayedSQL +
+ + +
MaxDbList +
+ + +
MaxExactCount +
+ + +
MaxExactCountViews +
+ + +
MaxNavigationItems +
+ + +
MaxRows +
+ + +
MaxSizeForInputField +
+ + +
MaxTableList +
+ +
+ +
MaxTableUiprefs +
+ + +
MCrypt +
+ + +
mcrypt +
+ + +
McryptDisableWarning +
+ + +
MemoryLimit +
+ + +
MIME +
+ + +
MinSizeForInputField +
+ + +
module +
+ + +
MySQL +
+ + +
mysql +
+ + +
mysqli +
+ +
+ +

N

+ + + +
+ +
NaturalOrder +
+ + +
NaviBackground +
+ + +
NavigationDisplayLogo +
+ + +
NavigationDisplayServers +
+ + +
navigationhiding +
+ + +
NavigationLogoLink +
+ + +
NavigationLogoLinkWindow +
+ + +
NavigationTreeDbSeparator +
+ + +
NavigationTreeDefaultTabTable +
+ + +
NavigationTreeDisplayDbFilterMinimum +
+ +
+ +
NavigationTreeDisplayItemFilterMinimum +
+ + +
NavigationTreeEnableGrouping +
+ + +
NavigationTreePointerEnable +
+ + +
NavigationTreeTableLevel +
+ + +
NavigationTreeTableSeparator +
+ + +
NaviPointerBackground +
+ + +
NaviPointerColor +
+ + +
NaviWidth +
+ + +
nopassword +
+ + +
NumRecentTables +
+ +
+ +

O

+ + + +
+ +
OBGzip +
+ + +
only_db +
+ + +
OpenDocument +
+ +
+ +
Order +
+ + +
OS X +
+ +
+ +

P

+ + + +
+ +
password +
+ + +
PCRE +
+ + +
PDF +
+ + +
pdf_pages +
+ + +
PDFDefaultPageSize +
+ + +
PDFPageSizes +
+ + +
PEAR +
+ + +
PersistentConnections +
+ + +
PHP +
+ + +
phpMyAdmin configuration storage +
+ +
+ +
PmaAbsoluteUri +
+ + +
pmadb, [1] +
+ + +
PmaNoRelation_DisableWarning +
+ + +
port, [1] +
+ + +
PropertiesNumColumns +
+ + +
ProtectBinary +
+ + +
ProxyPass +
+ + +
ProxyUrl +
+ + +
ProxyUser +
+ +
+ +

Q

+ + + +
+ +
QueryHistoryDB +
+ + +
QueryHistoryMax +
+ + +
QueryWindowDefTab +
+ +
+ +
QueryWindowHeight +
+ + +
QueryWindowWidth +
+ +
+ +

R

+ + + +
+ +
recent +
+ + +
RecodingEngine +
+ + +
relation +
+ + +
RememberSorting +
+ + +
RepeatCells +
+ + +
ReservedWordDisableWarning +
+ +
+ +
RetainQueryBox +
+ + +
RFC +
+ +
+ +
RFC 1867 +
+ + +
RFC 1952 +
+ + +
RFC 2616 +
+ +
+ +
RFC 1952 +
+ + +
Row (record, tuple) +
+ + +
RowActionLinks +
+ +
+ +

S

+ + + +
+ +
SaveCellsAtOnce +
+ + +
SaveDir +
+ + +
SendErrorReports +
+ + +
Server +
+ + +
+ server configuration +
+ +
+ +
AllowDeny, order +
+ + +
AllowDeny, rules +
+ + +
AllowNoPassword +
+ + +
AllowRoot +
+ + +
LogoutURL +
+ + +
MaxTableUiprefs +
+ + +
SignonScript +
+ + +
SignonSession +
+ + +
SignonURL +
+ + +
StatusCacheDatabases +
+ + +
StatusCacheLifetime +
+ + +
auth_http_realm +
+ + +
auth_swekey_config +
+ + +
auth_type +
+ + +
bookmarktable +
+ + +
column_info +
+ + +
compress +
+ + +
connect_type +
+ + +
controlhost +
+ + +
controlpass +
+ + +
controlport +
+ + +
controluser +
+ + +
designer_coords +
+ + +
extension +
+ + +
hide_db +
+ + +
history +
+ + +
host +
+ + +
navigationhiding +
+ + +
nopassword +
+ + +
only_db +
+ + +
password +
+ + +
pdf_pages +
+ + +
pmadb +
+ + +
port +
+ + +
recent +
+ + +
relation +
+ + +
socket +
+ + +
ssl +
+ + +
ssl_ca +
+ + +
ssl_ca_path +
+ + +
ssl_cert +
+ + +
ssl_ciphers +
+ + +
ssl_key +
+ + +
table_coords +
+ + +
table_info +
+ + +
table_uiprefs +
+ + +
tracking +
+ + +
tracking_add_drop_database +
+ + +
tracking_add_drop_table +
+ + +
tracking_add_drop_view +
+ + +
tracking_default_statements +
+ + +
tracking_version_auto_create +
+ + +
user +
+ + +
userconfig +
+ + +
usergroups +
+ + +
users +
+ + +
verbose +
+ +
+ +
ServerDefault +
+ + +
ServerLibraryDifference_DisableWarning +
+ + +
Servers +
+ + +
SessionSavePath +
+ + +
Setup script +
+ + +
ShowAll +
+ + +
ShowBrowseComments +
+ + +
ShowChgPassword +
+ + +
ShowCreateDb +
+ + +
ShowDbStructureCreation +
+ + +
ShowDbStructureLastCheck +
+ + +
ShowDbStructureLastUpdate +
+ + +
ShowDisplayDirection +
+ + +
ShowFieldTypesInDataEditView +
+ + +
ShowFunctionFields +
+ + +
ShowHint +
+ + +
ShowPhpInfo +
+ + +
ShowPropertyComments +
+ + +
ShowServerInfo +
+ + +
ShowSQL +
+ + +
ShowStats +
+ + +
+ Signon +
+ +
+ +
Authentication mode +
+ +
+ +
SignonScript +
+ +
+ +
SignonSession +
+ + +
SignonURL +
+ + +
SkipLockedTables +
+ + +
SOAP +
+ + +
socket, [1] +
+ + +
SQL +
+ + +
SQLQuery, Edit +
+ + +
SQLQuery, Explain +
+ + +
SQLQuery, Refresh +
+ + +
SQLQuery, ShowAsPHP +
+ + +
SQLQuery, Validate +
+ + +
SQLValidator +
+ + +
SQLValidator, password +
+ + +
SQLValidator, use +
+ + +
SQLValidator, username +
+ + +
SSL +
+ + +
ssl +
+ + +
ssl_ca +
+ + +
ssl_ca_path +
+ + +
ssl_cert +
+ + +
ssl_ciphers +
+ + +
ssl_key +
+ + +
StatusCacheDatabases +
+ + +
StatusCacheLifetime +
+ + +
Storage Engines +
+ + +
Stored procedure +
+ + +
SuhosinDisableWarning +
+ + +
+ Swekey +
+ +
+ +
Authentication mode +
+ +
+
+ +

T

+ + + +
+ +
table +
+ + +
table_coords +
+ + +
table_info +
+ + +
table_uiprefs +
+ + +
TableNavigationLinksMode +
+ + +
TabsMode +
+ + +
tar +
+ + +
TCP +
+ + +
TCPDF +
+ + +
TempDir +
+ + +
TextareaAutoSelect +
+ + +
TextareaCols +
+ + +
TextareaRows +
+ + +
ThBackground +
+ + +
ThColor +
+ + +
ThemeDefault +
+ +
+ +
ThemeManager +
+ + +
ThemePath +
+ + +
ThemePerServer +
+ + +
TitleDatabase +
+ + +
TitleDefault +
+ + +
TitleServer +
+ + +
TitleTable +
+ + +
tracking +
+ + +
tracking_add_drop_database +
+ + +
tracking_add_drop_table +
+ + +
tracking_add_drop_view +
+ + +
tracking_default_statements +
+ + +
tracking_version_auto_create +
+ + +
TranslationWarningThreshold +
+ + +
trigger +
+ + +
TrustedProxies +
+ +
+ +

U

+ + + +
+ +
UFPDF +
+ + +
UploadDir +
+ + +
URL +
+ + +
UseDbSearch +
+ + +
user +
+ +
+ +
userconfig +
+ + +
usergroups +
+ + +
UserprefsDeveloperTab +
+ + +
UserprefsDisallow +
+ + +
users +
+ +
+ +

V

+ + + +
+ +
verbose +
+ +
+ +
VersionCheck +
+ +
+ +

W

+ + +
+ +
Webserver +
+ +
+ +

X

+ + +
+ +
XML +
+ +
+ +

Z

+ + + +
+ +
ZIP +
+ + +
ZipDump +
+ +
+ +
zlib +
+ +
+ + + +
+
+
+
+
+ + + + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/phpMyAdmin/doc/html/glossary.html b/phpMyAdmin/doc/html/glossary.html new file mode 100644 index 0000000..2cb9201 --- /dev/null +++ b/phpMyAdmin/doc/html/glossary.html @@ -0,0 +1,627 @@ + + + + + + + + + + Glossary — phpMyAdmin 4.1.7 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Glossary¶

+

From Wikipedia, the free encyclopedia

+
+
.htaccess
+

the default name of Apache’s directory-level configuration file.

+ +
+
ACL
+
Access Contol List
+
Blowfish
+

a keyed, symmetric block cipher, designed in 1993 by Bruce Schneier.

+ +
+
Browser
+

a software application that enables a user to display and interact with text, images, and other information typically located on a web page at a website on the World Wide Web.

+ +
+
bzip2
+

a free software/open source data compression algorithm and program developed by Julian Seward.

+ +
+
CGI
+

Common Gateway Interface is an important World Wide Web technology that +enables a client web browser to request data from a program executed on +the Web server.

+ +
+
Changelog
+

a log or record of changes made to a project.

+ +
+
Client
+

a computer system that accesses a (remote) service on another computer by some kind of network.

+ +
+
column
+

a set of data values of a particular simple type, one for each row of the table.

+ +
+ +

a packet of information sent by a server to a World Wide Web browser and then sent back by the browser each time it accesses that server.

+ +
+
CSV
+

Comma- separated values

+ +
+
DB
+
look at database
+
database
+

an organized collection of data.

+ +
+
Engine
+
look at storage engines
+
extension
+

a PHP module that extends PHP with additional functionality.

+ +
+
FAQ
+

Frequently Asked Questions is a list of commonly asked question and there +answers.

+ +
+
Field
+

one part of divided data/columns.

+ +
+
foreign key
+

a column or group of columns in a database row that point to a key column +or group of columns forming a key of another database row in some +(usually different) table.

+ +
+
FPDF
+

the free PDF library

+
+

See also

+

<http://www.fpdf.org/>

+
+
+
GD
+

Graphics Library by Thomas Boutell and others for dynamically manipulating images.

+ +
+
GD2
+
look at gd
+
gzip
+

gzip is short for GNU zip, a GNU free software file compression program.

+ +
+
host
+

any machine connected to a computer network, a node that has a hostname.

+ +
+
hostname
+

the unique name by which a network attached device is known on a network.

+ +
+
HTTP
+

HyperText Transfer Protocol is the primary method used to transfer or +convey information on the World Wide Web.

+ +
+
https
+

a HTTP-connection with additional security measures.

+ +
+
IEC
+
International Electrotechnical Commission
+
IIS
+

Internet Information Services is a set of Internet-based services for +servers using Microsoft Windows.

+ +
+
Index
+

a feature that allows quick access to the rows in a table.

+ +
+
IP
+

Internet Protocol is a data-oriented protocol used by source and +destination hosts for communicating data across a packet-switched +internetwork.

+ +
+
IP Address
+

a unique number that devices use in order to identify and communicate with each other on a network utilizing the Internet Protocol standard.

+ +
+
IPv6
+

IPv6 (Internet Protocol version 6) is the latest revision of the +Internet Protocol (IP), designed to deal with the +long-anticipated problem of its precedessor IPv4 running out of addresses.

+ +
+
ISAPI
+

Internet Server Application Programming Interface is the API of Internet Information Services (IIS).

+ +
+
ISP
+

Internet service provider is a business or organization that offers users +access to the Internet and related services.

+ +
+
ISO
+
International Standards Organisation
+
JPEG
+

a most commonly used standard method of lossy compression for photographic images.

+ +
+
JPG
+
look at jpeg
+
Key
+
look at index
+
LATEX
+

a document preparation system for the TEX typesetting program.

+ +
+
Mac
+

Apple Macintosh is line of personal computers is designed, developed, manufactured, and marketed by Apple Computer.

+

. seealso:: <http://www.wikipedia.org/wiki/Mac>

+
+
Mac OS X
+

the operating system which is included with all currently shipping Apple Macintosh computers in the consumer and professional markets.

+ +
+
MCrypt
+

a cryptographic library.

+ +
+
mcrypt
+

the MCrypt PHP extension.

+
+

See also

+

<http://php.net/mcrypt>

+
+
+
MIME
+

Multipurpose Internet Mail Extensions is +an Internet Standard for the format of e-mail.

+ +
+
module
+

some sort of extension for the Apache Webserver.

+ +
+
MySQL
+

a multithreaded, multi-user, SQL (Structured Query Language) Database Management System (DBMS).

+ +
+
mysqli
+

the improved MySQL client PHP extension.

+
+

See also

+

<http://php.net/mysqli>

+
+
+
mysql
+

the MySQL client PHP extension.

+
+

See also

+

<http://php.net/mysql>

+
+
+
OpenDocument
+

open standard for office documents.

+ +
+
OS X
+

look at Mac OS X.

+ +
+
PDF
+

Portable Document Format is a file format developed by Adobe Systems for +representing two dimensional documents in a device independent and +resolution independent format.

+ +
+
PEAR
+

the PHP Extension and Application Repository.

+
+

See also

+

<http://pear.php.net/>

+
+
+
PCRE
+

Perl Compatible Regular Expressions is the perl-compatible regular +expression functions for PHP

+
+

See also

+

<http://php.net/pcre>

+
+
+
PHP
+

short for “PHP: Hypertext Preprocessor”, is an open-source, reflective +programming language used mainly for developing server-side applications +and dynamic web content, and more recently, a broader range of software +applications.

+ +
+
port
+

a connection through which data is sent and received.

+ +
+
RFC
+

Request for Comments (RFC) documents are a series of memoranda +encompassing new research, innovations, and methodologies applicable to +Internet technologies.

+ +
+
RFC 1952
+

GZIP file format specification version 4.3

+
+

See also

+

RFC 1952

+
+
+
Row (record, tuple)
+

represents a single, implicitly structured data item in a table.

+ +
+
Server
+

a computer system that provides services to other computing systems over a network.

+ +
+
Storage Engines
+

handlers for different table types

+ +
+
SOAP
+

Simple Object Access Protocol is a protocol specification for exchanging +structured information in the implementation of Web Services in computer +networks.

+ +
+
socket
+

a form of inter-process communication.

+ +
+
SSL
+

Secure Sockets Layer is a cryptographic protocol which provides secure +communication on the Internet.

+ +
+
Stored procedure
+

a subroutine available to applications accessing a relational database system

+ +
+
SQL
+

Structured Query Language

+ +
+
table
+

a set of data elements (cells) that is organized, defined and stored as +horizontal rows and vertical columns where each item can be uniquely +identified by a label or key or by it?s position in relation to other +items.

+ +
+
tar
+

a type of archive file format: the Tape ARchive format.

+ +
+
TCP
+

Transmission Control Protocol is one of the core protocols of the +Internet protocol suite.

+ +
+
TCPDF
+

Rewrite of UFPDF with various improvements.

+
+

See also

+

<http://www.tcpdf.org/>

+
+
+
trigger
+

a procedural code that is automatically executed in response to certain events on a particular table or view in a database

+ +
+
UFPDF
+

Unicode/UTF-8 extension for FPDF

+ +
+
URL
+

Uniform Resource Locator is a sequence of characters, conforming to a +standardized format, that is used for referring to resources, such as +documents and images on the Internet, by their location.

+ +
+
Webserver
+

A computer (program) that is responsible for accepting HTTP requests from clients and serving them Web pages.

+ +
+
XML
+

Extensible Markup Language is a W3C-recommended general- purpose markup +language for creating special-purpose markup languages, capable of +describing many different kinds of data.

+ +
+
ZIP
+

a popular data compression and archival format.

+ +
+
zlib
+

an open-source, cross- platform data compression library by Jean-loup Gailly and Mark Adler.

+ +
+
+
+ + +
+
+
+
+
+

Previous topic

+

Credits

+

This Page

+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/phpMyAdmin/doc/html/index.html b/phpMyAdmin/doc/html/index.html new file mode 100644 index 0000000..e53a6d4 --- /dev/null +++ b/phpMyAdmin/doc/html/index.html @@ -0,0 +1,207 @@ + + + + + + + + + + Welcome to phpMyAdmin’s documentation! — phpMyAdmin 4.1.7 documentation + + + + + + + + + + + + + + + +
+
+
+
+ + +
+

Indices and tables¶

+ +
+ + +
+
+
+
+
+

Table Of Contents

+ + +

Next topic

+

Introduction

+

This Page

+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/phpMyAdmin/doc/html/intro.html b/phpMyAdmin/doc/html/intro.html new file mode 100644 index 0000000..8c6d15b --- /dev/null +++ b/phpMyAdmin/doc/html/intro.html @@ -0,0 +1,182 @@ + + + + + + + + + + Introduction — phpMyAdmin 4.1.7 documentation + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Introduction¶

+

phpMyAdmin can manage a whole MySQL server (needs a super-user) as +well as a single database. To accomplish the latter you’ll need a +properly set up MySQL user who can read/write only the desired +database. It’s up to you to look up the appropriate part in the MySQL +manual.

+
+

Supported features¶

+

Currently phpMyAdmin can:

+
    +
  • browse and drop databases, tables, views, columns and indexes
  • +
  • display multiple results sets through stored procedures or queries
  • +
  • create, copy, drop, rename and alter databases, tables, columns and +indexes
  • +
  • maintenance server, databases and tables, with proposals on server +configuration
  • +
  • execute, edit and bookmark any SQL-statement, even batch-queries
  • +
  • load text files into tables
  • +
  • create [1] and read dumps of tables
  • +
  • export [1] data to various formats: CSV, XML, PDF, +ISO/IEC 26300 - OpenDocument Text and Spreadsheet, Microsoft +Word 2000, and LATEX formats
  • +
  • import data and MySQL structures from OpenDocument spreadsheets, as +well as XML, CSV, and SQL files
  • +
  • administer multiple servers
  • +
  • manage MySQL users and privileges
  • +
  • check referential integrity in MyISAM tables
  • +
  • using Query-by-example (QBE), create complex queries automatically +connecting required tables
  • +
  • create PDF graphics of your +database layout
  • +
  • search globally in a database or a subset of it
  • +
  • transform stored data into any format using a set of predefined +functions, like displaying BLOB-data as image or download-link
  • +
  • track changes on databases, tables and views
  • +
  • support InnoDB tables and foreign keys see 3.6 What is currently not supported in phpMyAdmin about InnoDB?
  • +
  • support mysqli, the improved MySQL extension see 1.17 Which MySQL versions does phpMyAdmin support?
  • +
  • create, edit, call, export and drop stored procedures and functions
  • +
  • create, edit, export and drop events and triggers
  • +
  • communicate in 62 different languages
  • +
+
+
+

A word about users¶

+

Many people have difficulty understanding the concept of user +management with regards to phpMyAdmin. When a user logs in to +phpMyAdmin, that username and password are passed directly to MySQL. +phpMyAdmin does no account management on its own (other than allowing +one to manipulate the MySQL user account information); all users must +be valid MySQL users.

+

Footnotes

+ + + + + +
[1](1, 2) phpMyAdmin can compress (Zip, GZip or RFC 1952 +formats) dumps and CSV exports if you use PHP with +Zlib support (--with-zlib). +Proper support may also need changes in php.ini.
+
+
+ + +
+
+
+
+
+

Table Of Contents

+ + +

Previous topic

+

Welcome to phpMyAdmin’s documentation!

+

Next topic

+

Requirements

+

This Page

+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/phpMyAdmin/doc/html/objects.inv b/phpMyAdmin/doc/html/objects.inv new file mode 100644 index 0000000000000000000000000000000000000000..ca8d4017de101793f72748318e08179b22f361d8 GIT binary patch literal 9663 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 + + + + + + + Other sources of information — phpMyAdmin 4.1.7 documentation + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Other sources of information¶

+
+

Printed Book¶

+

The definitive guide to using phpMyAdmin is the book Mastering phpMyAdmin for +Effective MySQL Management by Marc Delisle. You can get information on that +book and other officially endorsed books at the phpMyAdmin site.

+
+
+

Tutorials¶

+

Third party tutorials and articles are listed on our wiki page.

+
+
+ + +
+
+
+
+
+

Table Of Contents

+ + +

Previous topic

+

User management

+

Next topic

+

FAQ - Frequently Asked Questions

+

This Page

+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/phpMyAdmin/doc/html/privileges.html b/phpMyAdmin/doc/html/privileges.html new file mode 100644 index 0000000..3fc35d7 --- /dev/null +++ b/phpMyAdmin/doc/html/privileges.html @@ -0,0 +1,169 @@ + + + + + + + + + + User management — phpMyAdmin 4.1.7 documentation + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

User management¶

+

User management is the process of controlling which users are allowed to +connect to the MySQL server and what permissions they have on each database. +phpMyAdmin does not handle user management, rather it passes the username and +password on to MySQL, which then determines whether a user is permitted to +perform a particular action. Within phpMyAdmin, administrators have full +control over creating users, viewing and editing privileges for existing users, +and removing users.

+

Within phpMyAdmin, user management is controlled via the Users link +from the main page. Users can be created, edited, and removed.

+
+

Creating a new user¶

+

To create a new user, click the Add a new user link near the bottom +of the Users page (you must be a “superuser”, e.g., user “root”). +Use the textboxes and drop-downs to configure the user to your particular +needs. You can then select whether to create a database for that user and grant +specific global privileges. Once you’ve created the user (by clicking Go), you +can define that user’s permissions on a specific database (don’t grant global +privileges in that case). In general, users do not need any global privileges +(other than USAGE), only permissions for their specific database.

+
+
+

Editing an existing user¶

+

To edit an existing user, simply click the pencil icon to the right of that +user in the Users page. You can then edit their global- and +database-specific privileges, change their password, or even copy those +privileges to a new user.

+
+
+

Deleting a user¶

+

From the Users page, check the checkbox for the user you wish to +remove, select whether or not to also remove any databases of the same name (if +they exist), and click Go.

+
+
+

Assigning privileges to user for a specific database¶

+

Users are assigned to databases by editing the user record (from the +Users link on the home page) not from within the Users +link under the table. If you are creating a user specifically for a given table +you will have to create the user first (with no global privileges) and then go +back and edit that user to add the table and privileges for the individual +table.

+
+
+ + +
+
+
+
+
+

Table Of Contents

+ + +

Previous topic

+

Transformations

+

Next topic

+

Other sources of information

+

This Page

+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/phpMyAdmin/doc/html/require.html b/phpMyAdmin/doc/html/require.html new file mode 100644 index 0000000..c3b074f --- /dev/null +++ b/phpMyAdmin/doc/html/require.html @@ -0,0 +1,168 @@ + + + + + + + + + + Requirements — phpMyAdmin 4.1.7 documentation + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Requirements¶

+
+

Web server¶

+

Since, phpMyAdmin’s interface is based entirely in your browser, you’ll need a +web server (such as Apache, IIS) to install phpMyAdmin’s files into.

+
+
+

PHP¶

+
    +
  • You need PHP 5.3.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.
  • +
  • You need GD2 support in PHP to display inline thumbnails of JPEGs +(“image/jpeg: inline”) with their original aspect ratio.
  • +
  • When using the cookie authentication (the default), the mcrypt extension is strongly suggested for most +users and is required for 64–bit machines. Not using mcrypt will +cause phpMyAdmin to load pages significantly slower.
  • +
  • To support upload progress bars, see 2.9 Seeing an upload progress bar.
  • +
  • To support XML and Open Document Spreadsheet importing, you need the +libxml extension.
  • +
  • Performance suggestion: install the ctype extension.
  • +
+ +
+
+

Database¶

+

phpMyAdmin supports MySQL-compatible databases.

+
    +
  • MySQL 5.5 or newer
  • +
  • MariaDB 5.5 or newer
  • +
  • Drizzle
  • +
+ +
+
+

Web browser¶

+

To access phpMyAdmin you need a web browser with cookies and javascript +enabled.

+
+
+ + +
+
+
+
+
+

Table Of Contents

+ + +

Previous topic

+

Introduction

+

Next topic

+

Installation

+

This Page

+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/phpMyAdmin/doc/html/search.html b/phpMyAdmin/doc/html/search.html new file mode 100644 index 0000000..21f2eb7 --- /dev/null +++ b/phpMyAdmin/doc/html/search.html @@ -0,0 +1,100 @@ + + + + + + + + + + Search — phpMyAdmin 4.1.7 documentation + + + + + + + + + + + + + + + + + + +
+
+
+
+ +

Search

+
+ +

+ Please activate JavaScript to enable the search + functionality. +

+
+

+ From here you can search these documents. Enter your search + words into the box below and click "search". Note that the search + function will automatically search for all of the words. Pages + containing fewer words won't appear in the result list. +

+
+ + + +
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ + + + \ No newline at end of file diff --git a/phpMyAdmin/doc/html/searchindex.js b/phpMyAdmin/doc/html/searchindex.js new file mode 100644 index 0000000..47a90c4 --- /dev/null +++ b/phpMyAdmin/doc/html/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({objects:{"":{"$cfg['ExecTimeLimit']":[13,0,1,"cfg_ExecTimeLimit"],"$cfg['Servers'][$i]['SignonURL']":[13,0,1,"cfg_Servers_SignonURL"],"$cfg['UploadDir']":[13,0,1,"cfg_UploadDir"],"$cfg['Servers'][$i]['socket']":[13,0,1,"cfg_Servers_socket"],"$cfg['SkipLockedTables']":[13,0,1,"cfg_SkipLockedTables"],"$cfg['Servers'][$i]['AllowRoot']":[13,0,1,"cfg_Servers_AllowRoot"],"$cfg['Servers'][$i]['AllowDeny']['order']":[13,0,1,"cfg_Servers_AllowDeny_order"],"$cfg['BrowseMarkerBackground']":[13,0,1,"cfg_BrowseMarkerBackground"],"$cfg['SQLValidator']":[13,0,1,"cfg_SQLValidator"],"$cfg['ShowBrowseComments']":[13,0,1,"cfg_ShowBrowseComments"],"$cfg['CompressOnFly']":[13,0,1,"cfg_CompressOnFly"],"$cfg['ThemeManager']":[13,0,1,"cfg_ThemeManager"],"$cfg['Servers'][$i]['recent']":[13,0,1,"cfg_Servers_recent"],"$cfg['OBGzip']":[13,0,1,"cfg_OBGzip"],"$cfg['MaxRows']":[13,0,1,"cfg_MaxRows"],"$cfg['SaveCellsAtOnce']":[13,0,1,"cfg_SaveCellsAtOnce"],"$cfg['NavigationTreeDisplayItemFilterMinimum']":[13,0,1,"cfg_NavigationTreeDisplayItemFilterMinimum"],"$cfg['Servers'][$i]['compress']":[13,0,1,"cfg_Servers_compress"],"$cfg['ProtectBinary']":[13,0,1,"cfg_ProtectBinary"],"$cfg['DisplayServersList']":[13,0,1,"cfg_DisplayServersList"],"$cfg['ShowPropertyComments']":[13,0,1,"cfg_ShowPropertyComments"],"$cfg['MaxDbList']":[13,0,1,"cfg_MaxDbList"],"$cfg['CheckConfigurationPermissions']":[13,0,1,"cfg_CheckConfigurationPermissions"],"$cfg['SQLValidator']['username']":[13,0,1,"cfg_SQLValidator_username"],"$cfg['Servers'][$i]['password']":[13,0,1,"cfg_Servers_password"],"$cfg['Export']['method']":[13,0,1,"cfg_Export_method"],"$cfg['FontFamilyFixed']":[13,0,1,"cfg_FontFamilyFixed"],"$cfg['NavigationLogoLink']":[13,0,1,"cfg_NavigationLogoLink"],"$cfg['ThemePath']":[13,0,1,"cfg_ThemePath"],"$cfg['Servers'][$i]['port']":[13,0,1,"cfg_Servers_port"],"$cfg['Confirm']":[13,0,1,"cfg_Confirm"],"$cfg['Servers'][$i]['tracking_version_auto_create']":[13,0,1,"cfg_Servers_tracking_version_auto_create"],"$cfg['Servers'][$i]['navigationhiding']":[13,0,1,"cfg_Servers_navigationhiding"],"$cfg['ReservedWordDisableWarning']":[13,0,1,"cfg_ReservedWordDisableWarning"],"$cfg['DefaultLang']":[13,0,1,"cfg_DefaultLang"],"$cfg['LinkLengthLimit']":[13,0,1,"cfg_LinkLengthLimit"],"$cfg['DBG']['sql']":[13,0,1,"cfg_DBG_sql"],"$cfg['Servers']":[13,0,1,"cfg_Servers"],"$cfg['NavigationTreeEnableGrouping']":[13,0,1,"cfg_NavigationTreeEnableGrouping"],"$cfg['Servers'][$i]['table_uiprefs']":[13,0,1,"cfg_Servers_table_uiprefs"],"$cfg['DefaultQueryTable']":[13,0,1,"cfg_DefaultQueryTable"],"$cfg['QueryWindowWidth']":[13,0,1,"cfg_QueryWindowWidth"],"$cfg['DefaultDisplay']":[13,0,1,"cfg_DefaultDisplay"],"$cfg['NaviPointerBackground']":[13,0,1,"cfg_NaviPointerBackground"],"$cfg['Servers'][$i]['user']":[13,0,1,"cfg_Servers_user"],"$cfg['ForceSSL']":[13,0,1,"cfg_ForceSSL"],"$cfg['ShowPhpInfo']":[13,0,1,"cfg_ShowPhpInfo"],"$cfg['Servers'][$i]['AllowNoPassword']":[13,0,1,"cfg_Servers_AllowNoPassword"],"$cfg['SQLQuery']['Refresh']":[13,0,1,"cfg_SQLQuery_Refresh"],"$cfg['Lang']":[13,0,1,"cfg_Lang"],"$cfg['EditInWindow']":[13,0,1,"cfg_EditInWindow"],"$cfg['SQLQuery']['Explain']":[13,0,1,"cfg_SQLQuery_Explain"],"$cfg['ShowAll']":[13,0,1,"cfg_ShowAll"],"$cfg['DefaultQueryDatabase']":[13,0,1,"cfg_DefaultQueryDatabase"],"$cfg['TextareaCols']":[13,0,1,"cfg_TextareaCols"],"$cfg['Border']":[13,0,1,"cfg_Border"],"$cfg['UserprefsDisallow']":[13,0,1,"cfg_UserprefsDisallow"],"$cfg['Servers'][$i]['pdf_pages']":[13,0,1,"cfg_Servers_pdf_pages"],"$cfg['HideStructureActions']":[13,0,1,"cfg_HideStructureActions"],"$cfg['RetainQueryBox']":[13,0,1,"cfg_RetainQueryBox"],"$cfg['Order']":[13,0,1,"cfg_Order"],"$cfg['GD2Available']":[13,0,1,"cfg_GD2Available"],"$cfg['PmaAbsoluteUri']":[13,0,1,"cfg_PmaAbsoluteUri"],"$cfg['LimitChars']":[13,0,1,"cfg_LimitChars"],"$cfg['ShowFieldTypesInDataEditView']":[13,0,1,"cfg_ShowFieldTypesInDataEditView"],"$cfg['Servers'][$i]['controluser']":[13,0,1,"cfg_Servers_controluser"],"$cfg['NavigationTreeTableLevel']":[13,0,1,"cfg_NavigationTreeTableLevel"],"$cfg['Servers'][$i]['relation']":[13,0,1,"cfg_Servers_relation"],"$cfg['ActionLinksMode']":[13,0,1,"cfg_ActionLinksMode"],"$cfg['Servers'][$i]['MaxTableUiprefs']":[13,0,1,"cfg_Servers_MaxTableUiprefs"],"$cfg['RememberSorting']":[13,0,1,"cfg_RememberSorting"],"$cfg['UserprefsDeveloperTab']":[13,0,1,"cfg_UserprefsDeveloperTab"],"$cfg['McryptDisableWarning']":[13,0,1,"cfg_McryptDisableWarning"],"$cfg['ShowDbStructureLastUpdate']":[13,0,1,"cfg_ShowDbStructureLastUpdate"],"$cfg['SendErrorReports']":[13,0,1,"cfg_SendErrorReports"],"$cfg['GZipDump']":[13,0,1,"cfg_GZipDump"],"$cfg['Servers'][$i]['connect_type']":[13,0,1,"cfg_Servers_connect_type"],"$cfg['CaptchaLoginPublicKey']":[13,0,1,"cfg_CaptchaLoginPublicKey"],"$cfg['MemoryLimit']":[13,0,1,"cfg_MemoryLimit"],"$cfg['TextareaAutoSelect']":[13,0,1,"cfg_TextareaAutoSelect"],"$cfg['Servers'][$i]['auth_swekey_config']":[13,0,1,"cfg_Servers_auth_swekey_config"],"$cfg['BZipDump']":[13,0,1,"cfg_BZipDump"],"$cfg['BrowseMarkerEnable']":[13,0,1,"cfg_BrowseMarkerEnable"],"$cfg['ShowStats']":[13,0,1,"cfg_ShowStats"],"$cfg['ThemeDefault']":[13,0,1,"cfg_ThemeDefault"],"$cfg['NaturalOrder']":[13,0,1,"cfg_NaturalOrder"],"$cfg['TitleServer']":[13,0,1,"cfg_TitleServer"],"$cfg['ThColor']":[13,0,1,"cfg_ThColor"],"$cfg['BrowsePointerColor']":[13,0,1,"cfg_BrowsePointerColor"],"$cfg['DefaultConnectionCollation']":[13,0,1,"cfg_DefaultConnectionCollation"],"$cfg['Servers'][$i]['verbose']":[13,0,1,"cfg_Servers_verbose"],"$cfg['AllowThirdPartyFraming']":[13,0,1,"cfg_AllowThirdPartyFraming"],"$cfg['Servers'][$i]['bookmarktable']":[13,0,1,"cfg_Servers_bookmarktable"],"$cfg['NavigationDisplayLogo']":[13,0,1,"cfg_NavigationDisplayLogo"],"$cfg['Servers'][$i]['ssl_ca']":[13,0,1,"cfg_Servers_ssl_ca"],"$cfg['Servers'][$i]['nopassword']":[13,0,1,"cfg_Servers_nopassword"],"$cfg['NavigationTreeDefaultTabTable']":[13,0,1,"cfg_NavigationTreeDefaultTabTable"],"$cfg['NavigationLogoLinkWindow']":[13,0,1,"cfg_NavigationLogoLinkWindow"],"$cfg['FilterLanguages']":[13,0,1,"cfg_FilterLanguages"],"$cfg['ShowSQL']":[13,0,1,"cfg_ShowSQL"],"$cfg['InitialSlidersState']":[13,0,1,"cfg_InitialSlidersState"],"$cfg['Servers'][$i]['userconfig']":[13,0,1,"cfg_Servers_userconfig"],"$cfg['blowfish_secret']":[13,0,1,"cfg_blowfish_secret"],"$cfg['DefaultTabTable']":[13,0,1,"cfg_DefaultTabTable"],"$cfg['ShowServerInfo']":[13,0,1,"cfg_ShowServerInfo"],"$cfg['ShowChgPassword']":[13,0,1,"cfg_ShowChgPassword"],"$cfg['Servers'][$i]['ssl']":[13,0,1,"cfg_Servers_ssl"],"$cfg['Servers'][$i]['hide_db']":[13,0,1,"cfg_Servers_hide_db"],"$cfg['MaxCharactersInDisplayedSQL']":[13,0,1,"cfg_MaxCharactersInDisplayedSQL"],"$cfg['LoginCookieValidity']":[13,0,1,"cfg_LoginCookieValidity"],"$cfg['Servers'][$i]['ssl_ciphers']":[13,0,1,"cfg_Servers_ssl_ciphers"],"$cfg['Servers'][$i]['controlport']":[13,0,1,"cfg_Servers_controlport"],"$cfg['ShowDbStructureLastCheck']":[13,0,1,"cfg_ShowDbStructureLastCheck"],"$cfg['DefaultTabServer']":[13,0,1,"cfg_DefaultTabServer"],"$cfg['NumRecentTables']":[13,0,1,"cfg_NumRecentTables"],"$cfg['Servers'][$i]['extension']":[13,0,1,"cfg_Servers_extension"],"$cfg['CharTextareaRows']":[13,0,1,"cfg_CharTextareaRows"],"$cfg['BgOne']":[13,0,1,"cfg_BgOne"],"$cfg['HeaderFlipType']":[13,0,1,"cfg_HeaderFlipType"],"$cfg['Servers'][$i]['ssl_cert']":[13,0,1,"cfg_Servers_ssl_cert"],"$cfg['ShowDbStructureCreation']":[13,0,1,"cfg_ShowDbStructureCreation"],"$cfg['QueryHistoryMax']":[13,0,1,"cfg_QueryHistoryMax"],"$cfg['BrowsePointerEnable']":[13,0,1,"cfg_BrowsePointerEnable"],"$cfg['LoginCookieStore']":[13,0,1,"cfg_LoginCookieStore"],"$cfg['Servers'][$i]['history']":[13,0,1,"cfg_Servers_history"],"$cfg['BgTwo']":[13,0,1,"cfg_BgTwo"],"$cfg['TitleDatabase']":[13,0,1,"cfg_TitleDatabase"],"$cfg['Servers'][$i]['auth_type']":[13,0,1,"cfg_Servers_auth_type"],"$cfg['RowActionLinks']":[13,0,1,"cfg_RowActionLinks"],"$cfg['Servers'][$i]['StatusCacheDatabases']":[13,0,1,"cfg_Servers_StatusCacheDatabases"],"$cfg['ProxyPass']":[13,0,1,"cfg_ProxyPass"],"$cfg['Servers'][$i]['column_info']":[13,0,1,"cfg_Servers_column_info"],"$cfg['TitleDefault']":[13,0,1,"cfg_TitleDefault"],"$cfg['DefaultFunctions']":[13,0,1,"cfg_DefaultFunctions"],"$cfg['GridEditing']":[13,0,1,"cfg_GridEditing"],"$cfg['QueryHistoryDB']":[13,0,1,"cfg_QueryHistoryDB"],"$cfg['SQLQuery']['ShowAsPHP']":[13,0,1,"cfg_SQLQuery_ShowAsPHP"],"$cfg['SaveDir']":[13,0,1,"cfg_SaveDir"],"$cfg['TempDir']":[13,0,1,"cfg_TempDir"],"$cfg['NavigationTreeDisplayDbFilterMinimum']":[13,0,1,"cfg_NavigationTreeDisplayDbFilterMinimum"],"$cfg['NavigationTreeTableSeparator']":[13,0,1,"cfg_NavigationTreeTableSeparator"],"$cfg['TranslationWarningThreshold']":[13,0,1,"cfg_TranslationWarningThreshold"],"$cfg['Servers'][$i]['usergroups']":[13,0,1,"cfg_Servers_usergroups"],"$cfg['Servers'][$i]['tracking_add_drop_database']":[13,0,1,"cfg_Servers_tracking_add_drop_database"],"$cfg['Servers'][$i]['controlpass']":[13,0,1,"cfg_Servers_controlpass"],"$cfg['Servers'][$i]['tracking']":[13,0,1,"cfg_Servers_tracking"],"$cfg['ShowHint']":[13,0,1,"cfg_ShowHint"],"$cfg['MainBackground']":[13,0,1,"cfg_MainBackground"],"$cfg['Export']":[13,0,1,"cfg_Export"],"$cfg['Servers'][$i]['auth_http_realm']":[13,0,1,"cfg_Servers_auth_http_realm"],"$cfg['DisplayBinaryAsHex']":[13,0,1,"cfg_DisplayBinaryAsHex"],"$cfg['UseDbSearch']":[13,0,1,"cfg_UseDbSearch"],"$cfg['IconvExtraParams']":[13,0,1,"cfg_IconvExtraParams"],"$cfg['DisableMultiTableMaintenance']":[13,0,1,"cfg_DisableMultiTableMaintenance"],"$cfg['LoginCookieRecall']":[13,0,1,"cfg_LoginCookieRecall"],"$cfg['TabsMode']":[13,0,1,"cfg_TabsMode"],"$cfg['Servers'][$i]['ssl_key']":[13,0,1,"cfg_Servers_ssl_key"],"$cfg['Servers'][$i]['tracking_add_drop_table']":[13,0,1,"cfg_Servers_tracking_add_drop_table"],"$cfg['DefaultTabDatabase']":[13,0,1,"cfg_DefaultTabDatabase"],"$cfg['LongtextDoubleTextarea']":[13,0,1,"cfg_LongtextDoubleTextarea"],"$cfg['NaviWidth']":[13,0,1,"cfg_NaviWidth"],"$cfg['MaxTableList']":[13,0,1,"cfg_MaxTableList"],"$cfg['RepeatCells']":[13,0,1,"cfg_RepeatCells"],"$cfg['TitleTable']":[13,0,1,"cfg_TitleTable"],"$cfg['AllowArbitraryServer']":[13,0,1,"cfg_AllowArbitraryServer"],"$cfg['RecodingEngine']":[13,0,1,"cfg_RecodingEngine"],"$cfg['PDFPageSizes']":[13,0,1,"cfg_PDFPageSizes"],"$cfg['DBG']['demo']":[13,0,1,"cfg_DBG_demo"],"$cfg['NaviBackground']":[13,0,1,"cfg_NaviBackground"],"$cfg['VersionCheck']":[13,0,1,"cfg_VersionCheck"],"$cfg['SuhosinDisableWarning']":[13,0,1,"cfg_SuhosinDisableWarning"],"$cfg['BrowsePointerBackground']":[13,0,1,"cfg_BrowsePointerBackground"],"$cfg['IgnoreMultiSubmitErrors']":[13,0,1,"cfg_IgnoreMultiSubmitErrors"],"$cfg['BrowseMIME']":[13,0,1,"cfg_BrowseMIME"],"$cfg['Servers'][$i]['designer_coords']":[13,0,1,"cfg_Servers_designer_coords"],"$cfg['Servers'][$i]['controlhost']":[13,0,1,"cfg_Servers_controlhost"],"$cfg['ZipDump']":[13,0,1,"cfg_ZipDump"],"$cfg['CodemirrorEnable']":[13,0,1,"cfg_CodemirrorEnable"],"$cfg['ForeignKeyMaxLimit']":[13,0,1,"cfg_ForeignKeyMaxLimit"],"$cfg['ForeignKeyDropdownOrder']":[13,0,1,"cfg_ForeignKeyDropdownOrder"],"$cfg['Servers'][$i]['host']":[13,0,1,"cfg_Servers_host"],"$cfg['QueryWindowDefTab']":[13,0,1,"cfg_QueryWindowDefTab"],"$cfg['Servers'][$i]['StatusCacheLifetime']":[13,0,1,"cfg_Servers_StatusCacheLifetime"],"$cfg['TextareaRows']":[13,0,1,"cfg_TextareaRows"],"$cfg['Servers'][$i]['tracking_default_statements']":[13,0,1,"cfg_Servers_tracking_default_statements"],"$cfg['TableNavigationLinksMode']":[13,0,1,"cfg_TableNavigationLinksMode"],"$cfg['ServerDefault']":[13,0,1,"cfg_ServerDefault"],"$cfg['ShowDisplayDirection']":[13,0,1,"cfg_ShowDisplayDirection"],"$cfg['ProxyUrl']":[13,0,1,"cfg_ProxyUrl"],"$cfg['SessionSavePath']":[13,0,1,"cfg_SessionSavePath"],"$cfg['ShowCreateDb']":[13,0,1,"cfg_ShowCreateDb"],"$cfg['InsertRows']":[13,0,1,"cfg_InsertRows"],"$cfg['LoginCookieDeleteAll']":[13,0,1,"cfg_LoginCookieDeleteAll"],"$cfg['CaptchaLoginPrivateKey']":[13,0,1,"cfg_CaptchaLoginPrivateKey"],"$cfg['Servers'][$i]['ssl_ca_path']":[13,0,1,"cfg_Servers_ssl_ca_path"],"$cfg['PersistentConnections']":[13,0,1,"cfg_PersistentConnections"],"$cfg['ServerLibraryDifference_DisableWarning']":[13,0,1,"cfg_ServerLibraryDifference_DisableWarning"],"$cfg['Servers'][$i]['only_db']":[13,0,1,"cfg_Servers_only_db"],"$cfg['QueryWindowHeight']":[13,0,1,"cfg_QueryWindowHeight"],"$cfg['SQLValidator']['use']":[13,0,1,"cfg_SQLValidator_use"],"$cfg['CharTextareaCols']":[13,0,1,"cfg_CharTextareaCols"],"$cfg['NavigationTreePointerEnable']":[13,0,1,"cfg_NavigationTreePointerEnable"],"$cfg['PDFDefaultPageSize']":[13,0,1,"cfg_PDFDefaultPageSize"],"$cfg['SQLQuery']['Edit']":[13,0,1,"cfg_SQLQuery_Edit"],"$cfg['Servers'][$i]['SignonSession']":[13,0,1,"cfg_Servers_SignonSession"],"$cfg['NavigationTreeDbSeparator']":[13,0,1,"cfg_NavigationTreeDbSeparator"],"$cfg['Servers'][$i]['LogoutURL']":[13,0,1,"cfg_Servers_LogoutURL"],"$cfg['ThBackground']":[13,0,1,"cfg_ThBackground"],"$cfg['CSPAllow']":[13,0,1,"cfg_CSPAllow"],"$cfg['ShowFunctionFields']":[13,0,1,"cfg_ShowFunctionFields"],"$cfg['SQLValidator']['password']":[13,0,1,"cfg_SQLValidator_password"],"$cfg['SQLQuery']['Validate']":[13,0,1,"cfg_SQLQuery_Validate"],"$cfg['AllowUserDropDatabase']":[13,0,1,"cfg_AllowUserDropDatabase"],"$cfg['MaxExactCountViews']":[13,0,1,"cfg_MaxExactCountViews"],"$cfg['Servers'][$i]['table_coords']":[13,0,1,"cfg_Servers_table_coords"],"$cfg['Import']":[13,0,1,"cfg_Import"],"$cfg['DBG']":[13,0,1,"cfg_DBG"],"$cfg['AvailableCharsets']":[13,0,1,"cfg_AvailableCharsets"],"$cfg['MaxSizeForInputField']":[13,0,1,"cfg_MaxSizeForInputField"],"$cfg['Servers'][$i]['SignonScript']":[13,0,1,"cfg_Servers_SignonScript"],"$cfg['NaviPointerColor']":[13,0,1,"cfg_NaviPointerColor"],"$cfg['CharEditing']":[13,0,1,"cfg_CharEditing"],"$cfg['Servers'][$i]['table_info']":[13,0,1,"cfg_Servers_table_info"],"$cfg['MaxExactCount']":[13,0,1,"cfg_MaxExactCount"],"$cfg['PmaNoRelation_DisableWarning']":[13,0,1,"cfg_PmaNoRelation_DisableWarning"],"$cfg['MaxNavigationItems']":[13,0,1,"cfg_MaxNavigationItems"],"$cfg['Servers'][$i]['tracking_add_drop_view']":[13,0,1,"cfg_Servers_tracking_add_drop_view"],"$cfg['BrowseMarkerColor']":[13,0,1,"cfg_BrowseMarkerColor"],"$cfg['NavigationDisplayServers']":[13,0,1,"cfg_NavigationDisplayServers"],"$cfg['Error_Handler']['display']":[13,0,1,"cfg_Error_Handler_display"],"$cfg['PropertiesNumColumns']":[13,0,1,"cfg_PropertiesNumColumns"],"$cfg['ThemePerServer']":[13,0,1,"cfg_ThemePerServer"],"$cfg['MinSizeForInputField']":[13,0,1,"cfg_MinSizeForInputField"],"$cfg['FontFamily']":[13,0,1,"cfg_FontFamily"],"$cfg['Servers'][$i]['users']":[13,0,1,"cfg_Servers_users"],"$cfg['Servers'][$i]['AllowDeny']['rules']":[13,0,1,"cfg_Servers_AllowDeny_rules"],"$cfg['Servers'][$i]['pmadb']":[13,0,1,"cfg_Servers_pmadb"],"$cfg['ProxyUser']":[13,0,1,"cfg_ProxyUser"],"$cfg['TrustedProxies']":[13,0,1,"cfg_TrustedProxies"]}},terms:{represent:8,varfilt:5,uploadprogress:5,prefix:13,forget:[5,13],whose:[4,5],miner:5,tobia:[8,2],usepackag:5,lori:8,under:[4,5,13,14,2],hermann:8,textareaautoselect:13,merchant:2,versioncheck:13,witten:8,everi:[4,5,13],risk:[5,13],dutch:8,max_value_length:5,alberty_at_neptunlab:8,affect:[5,13],opendocu:[3,10],look:[1,3,4,5,10,13],upload:[0,4,5,13,6],cma:8,getmimesubtyp:1,multipurpos:3,zlib:[3,5,10],hord:8,direct:[4,5,13,1],nair:8,consequ:13,second:[5,13,1],chee:8,even:[2,4,5,10,13,14],dialogu:5,hide:[4,13],followsymlink:5,veeven:8,"new":[1,3,4,5,8,11,13,14],net:[2,3,4,5,8,13],ever:5,super_priv:4,told:8,abov:[5,13],readman:8,never:[5,13],here:[4,5,13,1],beck:8,path:[4,5,13,9],interpret:5,michal:[8,4,2],forum:[8,5],robin:[8,2],datetim:13,transformation_opt:[13,1],permit:[14,13],mysqld:5,portabl:3,siramizu_at_gmail:8,phpseclib:8,heritrix:5,unix:[4,5],mike_at_graftonhal:8,mysqldump:5,tbl_select:[8,13],txt:[4,5],unit:8,plot:5,dhima:8,upgrade_tables_mysql_4_1_2:4,describ:[3,13,1],would:[4,5,13,1],mysqladmin:5,kettler:8,call:[13,4,5,10,1],recommend:[3,4,5,13],memoranda:3,type:[3,8,5,13,1],until:[8,4,13],rink_at_initfour:8,relat:[3,8,4,5,13],email_at_c:8,yahoo:5,u4663530_at_anu:8,warn:[4,5,13],mysql_connect:5,exce:13,hole:13,hold:[5,13],unpack:[4,5],addon:5,kuppelwies:8,join:[8,5,13],restor:5,setup:[0,1,4,5,8,9,13],work:[8,5,13,1],memorylimit:13,itself:[4,5,13],root:[4,5,13,14],overrid:4,give:[4,5,9],autodetect:13,delislma_at_collegesherbrook:8,indic:0,pandithawatta:8,captcha:4,unavail:13,want:[4,5,13,1,9],moham:8,unsign:1,horizonta:13,end:[4,5,13,1],chanaka:8,quot:5,travel:4,zzzz:13,march:8,how:[4,5,13,1],func_numb:13,disappear:[5,13],pikto:5,maxnavigationitem:13,config:[4,5,13,9],updat:[8,4,5,13],process_priv:4,chines:8,after:[4,5,13],lump:5,diagram:5,befor:[4,5,13],wrong:[5,13],star_at_origin:8,router:4,allowuserdropdatabas:13,averag:5,autoconnect:13,attempt:[5,13],third:[4,5,13,7],grant:[4,5,14],credenti:[4,13],ssl_ca:13,matiasbellone_at_gmail:8,maintain:[8,4],environ:[4,5,13],enter:[4,5,13,1],nikto:5,order:[0,3,4,5,8,13],oper:[3,5,13,1],feedback:8,softwar:[3,9,5,2],diagnos:5,over:[3,4,5,13,14],becaus:[8,4,5,13,1],jpeg:[3,6,1],supun:8,navigationtreedisplayitemfilterminimum:13,privileg:[4,5,8,10,11,13,14],jordi:8,digest:5,textbox:14,directli:[13,5,10],fit:[8,5,13,2],fix:[8,5],better:5,offic:3,persist:13,auth_swekey_config:[4,13],hidden:13,mydb:[5,13],rachim:8,split:[5,13,1],them:[1,3,4,5,9,13],thei:[1,4,5,8,9,13,14],fragment:5,safe:[4,5,13],"break":5,kirillov:8,choic:[4,5,13],alex:8,changelog:3,telekom:5,arrow:5,rowactionlink:13,side:[3,4,13],mean:[4,5,13,1],cybot_tm_at_us:[8,2],navi:13,allowarbitraryserv:[4,13],neomo:5,arg_separ:5,phpmy:5,forgot:5,logo:[8,13],extract:5,network:[3,5],file_format:3,goe:5,zarubin:8,newli:4,content:[0,1,3,4,5,8,13],rewrit:[3,5],daniel:8,showfunctionfield:13,got:5,ware:8,userprefsdisallow:13,forth:1,"98se":5,http_request:5,navig:[0,5,13,8],situat:5,free:[3,4,5,1,2],standard:[3,8,6,5,13],small:[5,13],kaushalya:8,hand:[4,5],func_spati:13,silent:[5,13],workaround:5,server_address:13,loup:3,isp:[3,0,4,5,13],filter:[5,13],iso:[3,10],unabl:5,martijn:8,kingdom:8,onto:5,user:[0,1,3,4,5,6,8,10,11,13,14],rang:[3,5,13],signonsess:[4,13],independ:[3,8,5],xitami:5,restrict:[4,5,13],instruct:5,alreadi:[4,5],grantor:[4,13],hanut_at_php:8,unmark:13,agre:13,primari:[3,8,5],chathuranga:8,top:[4,5,13],sometim:5,amalesh:8,master:[7,13],too:[5,13,12],pma__designer_coord:13,danish:8,tool:[8,5,13,12],"17a":5,showbrowsecom:13,past:13,max_link:5,provid:[1,3,4,5,9,13],tree:[8,13],project:[3,0,5,8],serverlibrarydifference_disablewarn:13,thu:[4,5],checkconfigurationpermiss:13,fashion:13,php_mysql:5,raj:8,mine:5,seed:13,manner:5,increment:13,seen:13,seem:[4,5,13],incompat:5,minu:5,userprefsdevelopertab:13,querywindowheight:13,realm:13,recreat:5,latter:[13,5,10],sakamoto:8,pma__us:13,derek:8,thoma:[3,8],indrajith:8,hypertext_transfer_protocol:3,davidson:8,simplifi:8,thi:[1,2,4,5,8,9,13],plenti:5,though:13,usernam:[13,4,5,10,14],w3c_valid:5,marin:8,regular:[3,8,13],defaultlang:13,letter:[5,13],jean:3,lithuanian:8,titledefault:13,tradit:8,persistentconnect:13,don:[4,5,13,14],telugu:8,dom:8,doc:[3,5],lose:[5,13],doe:[1,4,5,10,13,6,14],omniexplorer_bot:5,declar:[5,1],wildcard:[5,13],neg:5,winningham:8,mrbendig_at_mrbendig:8,dot:[5,13],ldi_:8,xampp:4,feedfetch:5,synoobot:5,opposit:13,random:[8,13],syntax:[5,13],radio:5,protocol:[3,4,5,13],placella:8,absolut:13,layout:[13,5,10],firstnam:5,alvar:8,menu:[5,13],explain:[4,5,13],configur:[0,1,3,4,5,8,10,13,14],apach:[3,4,5,13,6],burak:8,theme:[0,5,13],busi:3,lubo:8,folder:[4,5],schneier:3,field_:3,tbl_structur:[13,1],likewis:5,stop:[5,13],sqlvalid:13,report:[8,5,13],symmetr:3,"k\u0119stuti":8,volkov:8,bar:[6,5,13],excel:5,signonurl:[4,13],method:[3,4,5,13,1],reload:5,bad:5,ban:5,taceloski:8,mysql:[0,3,4,5,8,9,10,7,13,6,14],forcessl:13,gridedit:13,result:[13,4,5,10],auto_incr:5,corrupt:13,themselv:13,best:[4,5],subject:[5,13],pete:8,awar:[4,5],said:5,hopefulli:1,databas:[0,3,4,5,8,10,11,13,6,14],wikipedia:[3,4],tracking_version_auto_cr:13,bgone:13,wiltave_at_gmail:8,atul:8,yahooseek:5,adnan:8,pma__navigationhid:13,approach:13,n8falke_at_us:8,accord:13,extend:[3,5,1],srnka:8,extens:[3,4,5,8,10,13,6],cut:13,preprocessor:3,wtf:5,subfold:4,protect:[4,5,13],accident:13,shapefil:[5,13],met:5,emerson4br_at_gmail:8,howev:[4,5,13,1],ayush:8,kronsbein:8,against:[4,5],brad:5,ivanlanin_at_us:8,countri:5,fauveau_at_globali:8,browser:[0,1,3,4,5,13,6],com:[1,2,3,5,8,13],"16m":13,clshttp:5,queryhistorydb:13,loader:5,pdf_page:[5,13],column_com:13,trust:13,assum:[4,5],gc_maxlifetim:13,duplic:5,question:[3,0,5],saedi:8,three:[5,13,1],been:[4,5,13,12],trigger:[3,8,10,13],interest:5,basic:[0,1,4,5,9,13],rather:[14,5,13],suppress:13,xxx:[5,13,1],telnet:5,argument:5,multithread:3,dave:8,"kl\u00e4ger":8,http_post_var:5,dash:[5,13],gnu:[3,2],servic:[3,4,5,13],properti:[8,5,13,1],sourceforg:[8,5,2],rouslan:8,pmanorelation_disablewarn:13,contributor:8,need:[4,5,9,10,13,6,14],libxml:6,myadmin:8,conf:[4,5],vendor:13,sever:[9,5,13,1],piotr:8,navigationtreedefaulttabt:13,perform:[14,5,13,6],suggest:[8,4,5,6],make:[4,5,13,1,12],ammar:8,complex:[5,10],descend:13,roszatycki:8,complet:[8,5,13],http_x_forwarded_for:13,"_uri_schem":3,evil:[4,5],kit:[4,5],norwegian:8,nix:13,ownership:5,tune:4,kept:[13,1],scenario:5,execute_priv:4,swekei:[4,13],printview:[8,13],bugzilla:5,client:[3,0,4,5,13],maxtablelist:13,gzip:[3,8,5,10,13],everyth:5,maxexactcount:[5,13],left:[8,5,13],seekbot:5,table_priv:4,bellow:13,identifi:[3,4,5,13],just:[8,4,5,13],bellon:8,textareacol:13,languag:[0,3,4,5,8,10,13],jose:5,easi:[5,13,1],interfer:5,had:[4,5],logformat:5,els:[8,4,5,13],save:[0,4,5,13],hat:4,jan_at_nrw:8,applic:[3,4,5,13],mayb:5,recaptcha:13,credit:[0,2,8],editinwindow:13,file_priv:4,arab:8,rfc1867:5,corazza:8,background:13,sitesearch:5,apart:5,measur:[3,4],specif:[1,3,4,5,11,13,14],arbitrari:[4,13],sublevel:13,controlport:13,manual:[13,4,5,10,1],zoom:[8,5],soap:[3,5,13],create_priv:4,sebastian:[8,2],underli:5,sqlqueri:13,www:[1,2,3,5,8,13],right:[4,5,13,1,14],old:[4,5,13],deal:3,czech:[8,13],"_db":13,foreignkeymaxlimit:[5,13],maxim:8,getmimetyp:1,intern:[3,5,13,1],sure:[4,5,13,1],savecellsatonc:13,borg:8,inact:1,wkito:5,bora:8,transmiss:3,bottom:[14,5,13],net_dim:5,normal:[4,5,13,1],track:[8,4,10,13],tracker:[5,13],t10:13,setoutputfilt:5,iccrawl:5,condit:5,foo:5,localhost:[4,5,13],core:3,plu:[8,5],titleserv:13,connect_typ:13,stefan:8,confer:8,ivan:8,ankit:8,post:[5,13],"super":10,"stanis\u0142aw":8,plug:[4,1],alexand:[8,2],chronolog:[0,8],surround:5,algi:8,produc:[5,13],ppa:4,tbl_dump:5,kissu:8,curiou:5,profession:3,bound:1,repl_client_priv:4,down:[14,5,13,1,9],slurp:5,xavier:8,netscap:5,contrib:4,storag:[3,0,4,13],maxsizeforinputfield:13,accordingli:[5,1],suffici:5,support:[0,4,5,8,10,13,6],pma_usernam:5,transform:[0,1,4,5,8,10,11,13],why:[5,13],avail:[3,9,5,13,1],width:13,request_method:5,editor:[8,4,13],legner:5,form:[3,8,5,13],offer:[3,13],forc:[5,13],tickbox:5,papazogl:8,sensi:5,savedir:13,renam:[13,5,10],cidr:13,"true":[4,13],limitchar:13,textarea:13,bugfix:8,maximum:[5,13],tell:5,toggl:[5,13],absenc:5,opensus:4,webmaster_at_trafficg:8,legenhausen:8,featur:[0,3,4,5,8,10,12,13],classic:[5,13],request:[3,4,5,13],"abstract":[8,1],decrypt:5,zend:5,mysql_fetch_field:1,seoma:5,showdisplaydirect:13,exist:[4,5,8,11,13,14],ship:[3,4,9],browsepointeren:13,db_search:13,interf:5,password:[13,4,5,10,14],encrypt:[4,5,13],showdbstructurelastcheck:13,refactor:8,vserver:[5,13],test:[8,9,5,13],propertiesnumcolumn:13,intend:[9,5],yasitha:8,walton:8,consid:[4,5],sql:[0,3,4,5,8,10,13],receiv:[3,5,1,2],longer:13,furthermor:13,tinyint:5,ignor:[5,13],time:[3,4,5,13],backward:5,inc:[4,5,13,9],concept:[8,10],table_coord:[5,13],skip:[9,13],rob:5,global:[4,5,10,1,14],ba17c1ec07d65003:4,signific:8,horizontalflip:13,delete_priv:4,pma_combin:5,row:[3,8,5,13],hierarch:8,decid:5,middl:13,depend:[4,5],pem:13,crawleradmin:5,decim:5,readabl:5,markt:5,mehbooob:8,must:[13,4,5,10,14],keck:[8,2],sourc:[0,3,5,8,7,11,12,13],string:[8,5,13,1],fando:5,initialslidersst:13,maxcharactersindisplayedsql:13,insertrow:13,word:[13,0,5,10],brows:[13,0,5,10,8],seealso:3,tracking_default_stat:13,administr:[8,4,5,13,14],level:[3,4,5,13],did:5,win2k:5,"gesch\u00e9":8,item:[3,5,13],team:[4,13],cooki:[0,3,4,5,8,13,6],dir:[5,1],prevent:[4,5,13],slower:6,obrador:8,bravo:8,applytransform:1,everytim:13,cost:4,showfieldtypesindataeditview:13,turnitinbot:5,port:[3,5,13],appear:[5,13],session_save_path:13,abdullah:8,uniform:3,current:[3,4,5,8,9,10,13],portugues:8,axel:8,navigationtreepointeren:13,chartextarearow:13,portnumb:13,deriv:4,dropdown:5,gener:[0,1,2,3,4,5,8,9,13,14],french:8,slow:[5,13],address:[3,5,13],along:[4,5,2],madhura:8,box:[0,5,13],invit:12,shift:5,rsedwardian_at_gmail:8,bot:5,bbedit:4,behav:5,seward:3,commonli:3,macintosh:3,fpdf:[3,8],stduser:13,extra:4,circumv:5,tweak:4,modul:[3,5],prefer:[8,4,5,13],get_login_credenti:13,fake:13,marker:13,instal:[0,1,4,5,13,6],bookmarkt:13,market:3,httpd:5,memori:[5,13],sake:5,visit:4,perl:[3,5],handler:3,everywher:5,criteria:5,scope:4,translit:13,maxime_at_fre:8,chapter:5,club:8,peopl:[8,9,5,10,12],claus:[5,13],ctype:6,enhanc:8,visual:[8,13],olivi:[8,2],accept:[3,5,13],examin:5,your_theme_nam:5,easiest:[4,5],fly:13,graphic:[3,4,10],ibm:5,dhtml:8,tokyo:5,prepar:[3,13],focu:13,minimum:13,mjane:8,can:[1,2,3,4,5,7,9,10,12,13,14],lc_messag:13,umlaut:5,purpos:[3,13,2],"c\u00e9dric":8,problemat:5,heart:5,querywindowdeftab:13,stream:5,backslash:5,agent:5,"lo\u00efc":8,heard:5,abort:13,spl:6,mediapartn:5,articl:[5,7],occur:5,swedish:8,alwai:[4,5,13,1],differenti:5,web_brows:3,multipl:[13,8,5,10],hungarian:8,sailboat:8,charset:[8,13,1],nyu:8,write:[13,4,5,10],navigationlogolink:13,navipointerbackground:13,anyon:4,tild:5,protectbinari:13,securer:8,allownopassword:13,product:4,mat:8,"m\u00fcller":[8,2],max:5,sql_mode:5,usabl:5,gailli:3,funck_at_googlemail:8,mac:[3,4,5,13],mai:[13,4,5,10,1],underscor:5,data:[1,3,4,5,10,13],grow:1,practic:13,johnson:[8,2],divid:3,explicit:13,inform:[0,1,3,4,5,10,11,12,13,7],"switch":[3,4,5],combin:[5,13],block:[3,5,13],anoth:[3,4,5,13],ordinari:4,simoncini:5,anticip:3,navigationdisplayserv:13,michal_at_cihar:[8,2],db1:13,still:[4,13],pointer:13,dynam:[3,8,5],"p\u00e9ter":8,group:[3,5,13],thank:[8,5],func_uuid:13,polici:13,jim:8,create_tmp_table_priv:4,platform:[3,4,5,13],window:[0,1,3,4,5,8,13],mail:[3,5],main:[0,1,4,5,8,13,14],non:[5,13],recal:13,encod:[8,5,13],initi:[4,5,13],answer:3,first_timestamp:13,safari:5,now:[4,5,13],thilina:8,discuss:5,nor:5,introduct:[0,10,1,11],term:2,glund_at_silversoft:8,name:[1,3,4,5,8,13,14],exectimelimit:[5,13],drop:[1,14,5,8,10,13],separ:[3,8,5,13],gergo314_at_gmail:8,compressonfli:[5,13],compil:5,domain:[5,13],replac:[4,5,13,9],individu:14,continu:13,wrap:13,redistribut:[9,2],sponsor:5,happen:[4,5],bgtwo:13,foreign_kei:3,canada:5,maxrow:13,shown:[5,13],accomplish:10,jackson:8,madlen:8,space:[5,13],internet:[3,4,5,13],ufpdf:[3,8],correct:[5,13],integr:[13,4,5,10],iusr_machin:5,dbc334_at_gmail:8,state:13,migrat:5,xhtml1:8,recodingengin:13,phpmyadmin_x:4,ajax:8,mime:[3,8,5,13,1],superus:[4,14],ruleant_at_us:8,mysqli:[3,8,5,10,13],"byte":13,care:[5,1],recod:13,thbackground:13,wai:[8,4,5,13],unwil:5,emerson4br:8,synchron:[0,5,8],refus:5,domen:8,thing:[5,13],place:[4,5,13],titledatabas:13,wiegger:8,view:[3,14,5,8,10,13],imposs:13,frequent:[3,0,5,13],first:[4,5,13,1,14],origin:[0,6,13,1,8],info:[8,5,13,2],redhat:5,onc:[4,5,13,14],arrai:[5,13,1],reload_priv:4,yourself:4,submit:[5,13],rink:8,spanish:8,open:[3,4,5,12,13,6],predefin:10,country_cod:5,size:[5,13],given:[14,5,13],ian:8,navigationtreeenablegroup:13,convent:1,bookmark:[13,8,4,5,10],maxexactcountview:13,conveni:4,ysajeepan_at_l:8,especi:[4,5,13],copi:[2,4,5,10,13,14],specifi:[8,4,5,13,1],mod_proxi:5,thai:8,than:[13,8,14,5,10],png:5,themenam:13,serv:3,wide:3,przybylski:8,transformationsplugin:1,tecnick:8,balanc:13,were:[8,5,13],posit:[3,5],seri:[3,5],pre:[5,13,1],sai:[5,1],zipdump:13,san:13,bailout_on_error:5,displayserverslist:13,ani:[1,2,3,4,5,8,10,13,14],subroutin:3,userconfig:13,doctyp:5,suhosin:[5,13],saw:5,chrisj_at_ctel:8,engin:[3,5],advic:9,greek:8,tcpdf:[3,8,9,5],note:[4,5,13,1,9],harald:5,take:[5,13,1],advis:13,noth:5,clickjack:13,begin:[5,13],printer:8,ukrainian:8,buffer:[5,13,1],compress:[3,13,5,10],os_x:3,pr1:5,pair:[4,13],homepag:[5,1],icon:[8,14,5,13,1],latex:[3,5,10],path_to_your_phpmyadmin_directori:13,contacto_at_joaodia:8,later:[5,13],serif:13,typeset:3,meanwhil:5,pmapass:4,pattern:13,axi:5,pma_db:4,john2db:5,event:[3,8,10,13],show:[5,13],german:[8,5],tkl:5,russian:8,concurr:13,permiss:[4,5,13,14],threshold:13,foreign_db:13,help:[8,4,5,13,12],xml:[3,8,6,5,10],onli:[1,4,5,8,10,13,14],explicitli:[4,13],ratio:6,romanian:8,activ:[4,5,13],behind:[4,13],internet_information_servic:3,analyz:[5,13],analys:8,offici:[7,4,5,1],reset:[4,5],nearli:13,variou:[0,3,5,8,9,10,13],get:[7,4,5,13,1],ssl:[3,5,13],kiko:8,cannot:[4,5,13,1],martin_at_whistl:8,wasser:5,sascha:8,requir:[0,4,5,10,13,6],truli:4,home_pag:5,output_compress:5,borrow:8,yield:5,email:[8,5],controlpass:[4,5,13],where:[3,4,5,13],wiki:[3,5,7],parse_url:5,numrecentt:13,proce:5,pma__histori:13,korakot:8,hierarchi:[5,13],yacybot:5,progress:[6,5],server_vari:13,logincookievalid:13,blobstream:8,detect:[8,5,13],innov:3,review:4,chapeaux:8,enumer:5,hide_db:13,label:[3,5],enough:4,between:[5,13],"import":[0,3,4,5,8,10,13,6],across:[3,13],parent:5,lsml_at_liv:8,screen:[4,5],cedric:8,retainquerybox:13,come:[4,5,13],img:5,contol:3,allowroot:13,tutori:[7,5,1,11],kanitchet:8,open_basedir:[5,13],mani:[3,4,5,8,10,12,13],fauveau:8,rel_person:5,among:13,googlebot:5,mmcrawler:5,color:13,overview:[5,1],nicola:8,ultim:5,chaovavanich:8,marc:[8,5,7,2],allowdeni:[4,5,13],hardli:4,mark:[3,8,13],barri:8,filterlanguag:13,table_uipref:13,emphas:13,"50x50":5,phpmysqlformgen:8,andrea:8,tamil:8,marconcini:8,tabbrows:5,"case":[4,5,13,14],blowfish:[3,8,4,13],mount:13,references_priv:4,wigginton:8,advantag:5,ctrl:5,marcel:8,kasun:8,cluster:5,zahra:8,setup_dir_writ:9,duke3d_at_ukr:8,ascii:[5,13,1],insert_priv:4,garvin:[8,2],develop:[0,3,5,8,12,13],author:[8,5,13],media:5,statuscachelifetim:13,check:[1,2,14,5,8,9,10,12,13],binari:13,html:[3,8,5,13,1],pma__table_uipref:13,pai:4,update_priv:4,document:[0,3,4,5,8,9,13,6],pan:5,webserv:[3,4,5,13],screenshot:5,nest:[8,5,13],driven:4,capabl:3,set_magic_quotes_runtim:4,http_host:[5,13],improv:[3,8,5,10,13],extern:[0,9,13],tradition:4,om_at_omni:[8,2],appropri:[4,5,10],moder:8,port_:3,edlund:8,without:[5,13,1,2],dimension:3,summer:8,execut:[3,13,5,10],phpmyadmin:[0,1,4,5,7,8,9,10,12,13,6,14],tip:[5,13],aspect:[6,9],polish:8,passphras:13,speed:[4,5,13],defaulttabserv:13,gigabot:5,hint:[5,13],except:[4,5,13],adsbot:5,typo3_at_dirk:8,blob:[13,5,10],save_path:5,vulner:[4,5],table_nam:4,gd2:[3,6],hover:13,around:[4,5,13],yuval:8,read:[13,4,5,10],grid:13,dbase:5,world:[3,4,13],mod:5,setup_config_fil:9,whitespac:5,rel_town:5,integ:13,server:[0,3,4,5,8,9,10,13,6,14],benefit:[5,13],either:[5,13],output:[8,5,13,1],intenet:13,inter:[3,13],grant_priv:4,manag:[0,3,4,5,7,10,11,13,14],yyyi:13,node:[3,8],maxtableuipref:13,turck:5,longtextdoubletextarea:13,availablecharset:13,ascend:13,ashraf:8,charedit:13,showserverinfo:13,authent:[0,4,5,8,13,6],strickroth:8,column_priv:4,jakub:8,martyna:8,confirm:[5,13],gd2avail:13,piankov:8,definit:[5,13,7],rewriteengin:5,legal:13,nokeepal:5,complic:13,tabsmod:13,column_info:[13,1],schaefer:8,timeout:[5,13],olof:8,each:[1,3,4,5,13,14],xzvf:4,broken:5,stdpass:13,found:[4,5,13],navigationtreedbsepar:13,xvnavarro_at_gmail:8,acl:[3,13],precedessor:3,degre:13,mjaning_at_gmail:8,lucen:5,addtyp:5,backup:5,routin:[8,13],chartextareacol:13,effici:[5,13],logouturl:13,usergroup:13,yyi:13,your:[0,1,4,5,10,13,6,14],lolo_at_phpheaven:8,opengi:8,log:[3,13,4,5,10],her:5,area:[4,5,13],hex:[5,13],ysajeepan:8,overwrit:13,start:[8,4,5,13],compliant:8,interfac:[3,8,6,5,13],low:[4,5,13],mbstring:[6,13],ipv6:[3,13],submiss:13,proxyus:13,machin:[3,4,5,13,6],hindi:8,hard:13,tupl:3,bundl:5,regard:[10,1],upload_max_files:5,cryptograph:3,realli:[4,5,13],adler:3,pull:13,largest:5,possibl:[4,5,13,1,12],"default":[0,1,3,4,5,13,6],textarearow:13,embed:13,expect:5,gone:5,scanner:5,creat:[3,4,5,8,10,11,13,14],certain:[3,13,1],certail:5,mike:8,strongli:[6,5,13],plathei:8,localnetc:13,file:[1,3,4,5,8,9,10,11,13,6],"mickevi\u010diu":8,encompass:3,fill:[4,5,13],incorrect:5,again:[4,5],showdbstructurelastupd:13,googl:[8,4,5,13],commiss:3,corazza_at_wanadoo:8,tbl_row_delet:5,field:[0,1,3,4,5,13],valid:[0,4,5,8,10,13],writabl:[4,13,9],you:[1,2,4,5,7,8,9,10,12,13,6,14],architectur:5,openid:13,resolut:3,sequenc:3,symbol:5,pear:[3,8,5],allowoverrid:5,ansi:5,tables_priv:[4,13],viliu:8,lineup:13,gzencod:5,directori:[0,1,3,4,5,9,13],descript:[5,13,1],papaz_p_at_yahoo:8,chown:[5,13],adam:8,potenti:13,escap:13,unset:5,file_upload:5,all:[1,3,4,5,9,10,12,13],consider:4,gupta:8,browsemarkeren:13,code:[3,8,4,5,13],yavuz:8,follow:[8,4,5,13],disk:4,minsizeforinputfield:13,scp:5,net_url:5,iconv:13,rewrot:8,intext:5,former:[8,13],alberti:8,program:[3,13,2],those:[4,5,13,1,14],introduc:[8,5,13],liter:[5,13],fals:[9,5,13],faq:[3,0,5],suhosindisablewarn:[5,13],util:[3,5,13],leiding:8,ichiro:5,verb:5,mechan:[8,4,5,13],veri:[5,13],longtext:13,list:[3,9,5,13,7],resav:4,adjust:[5,13],plain:[4,5,13,1],pbm:8,tbl_creat:8,enterpris:[4,5],homonym:5,internetwork:3,template_abstract:1,path_to_phpmyadmin:5,sync:8,controlhost:13,tex:[3,5],zero:13,design:[0,3,4,5,8,13],pass:[13,14,5,10,1],further:[8,13],ajaxifi:8,hick:[8,2],cursor:[5,13],what:[1,4,5,10,13,14],sub:5,request_for_com:3,me_at_derrabu:[8,2],sun:8,section:[4,5,13,1,12],abl:[8,4,5,13],u4663530:8,delet:[4,5,13,14,11],version:[0,2,3,4,5,8,9,10,13,6],"public":[4,5,13,2],full:[4,5,13,14],hash:5,berkelei:13,behaviour:5,shouldn:4,modifi:[5,13,2],valu:[3,4,5,13,1],ignoremultisubmiterror:13,d3xter_at_us:8,search:[13,0,5,10,8],thememanag:[5,13],yukihiro:8,amount:[5,13,1],pick:5,bussier:8,showcreatedb:13,lock_tables_priv:4,via:[4,5,13,14],janni:8,put:[4,5,13,1],voyag:5,armel:8,famili:13,select:[1,4,5,8,13,14],esri:[5,13],hexadecim:13,khan:8,ga244_at_is8:8,distinct:[5,13],msnbot:5,two:[3,4,5,13],coverag:5,pmahomm:[5,13],taken:5,remembersort:13,ntf:13,minor:[8,5],more:[3,4,5,13,2],reachabl:13,bulgarian:8,desir:10,kristof:8,hundr:5,mozilla:5,oleg:8,particular:[3,4,14,2],known:[3,0,9,5,13],destin:3,"bokm\u00e5l":8,cach:[5,13],town:5,none:13,der:8,dev:[3,4,5],histori:[8,4,13],remain:[5,13],paragraph:5,rel_countri:5,kosit:8,abram:8,renato:8,omit:13,prompt:[4,13],scan:5,share:4,templat:1,max_totalname_length:5,chimera:5,explor:[4,5,13],tablesepar:5,action:[14,5,13],computer_socket:3,uncheck:[5,13],huge:[5,13],cours:[4,5,13],xxxx:13,newlin:13,secur:[0,1,3,4,5,13],yuichiro_at_pop07:8,hidestructureact:13,spreadsheet:[6,10],reject:13,csv:[3,5,10],simpl:[3,4,5],css:[5,13],resourc:3,unprivileg:13,reflect:3,sven:8,okai:4,mendel:[8,2],mariadb:[6,5],associ:4,pma__rec:13,svec:8,tablenavigationlinksmod:13,mous:[5,13],"short":3,john1db:5,footer:13,themepath:[5,13],caus:[6,5,13],parti:[4,5,7],checkbox:[14,5,13],rotat:13,hypertext:3,soon:5,soom:8,paper:[5,13],through:[3,13,5,10,1],same:[4,5,13,14],urdu:8,ipmask:13,"montr\u00e9al":5,paramet:[5,13,1],style:[4,5,13],arial:13,db_structur:[5,13],ip_address:3,me_at_supergarv:[8,2],ricardo:8,mcryptdisablewarn:13,bypass:[5,13],might:[4,5,13,9],alter:[13,5,10],good:[4,5,13,1],"return":[5,13,1],pma__usergroup:13,timestamp:[4,13],disable_funct:13,defaulttabt:13,libwww:5,rewriterul:5,ukrain:8,framework:9,botelho:8,rwx:[5,13],bigger:5,troubleshoot:5,userid:5,unlik:4,refresh:[5,13],easili:[4,5,13],achiev:13,tamsjadi:8,innodb:[13,5,10],fulli:5,unicod:3,truncat:13,neil:8,wasn:8,idea:[8,4,5,13,1],procedur:[3,5,10],slowdown:5,connect:[0,3,14,5,10,13],http:[2,3,4,5,8,13],beyond:4,orient:[3,5],ftp:[4,5,13],marcin:8,robert:8,publish:[13,2],research:3,footnot:10,print:[7,13,11],occurr:5,msie:5,benjamin:8,difficulti:10,proxi:[4,5,13],advanc:[4,13],browsepointerbackground:13,differ:[1,3,4,5,8,10,13],asc:13,quick:[3,0,4,5,13],reason:[5,13],base:[3,6,5,8,9,13],ask:[3,0,5,13],ash:8,english:[8,4,13],repl_slave_priv:4,bakondi:8,perhap:4,pma__rel:5,vainauska:8,lifetim:13,assign:[14,5,13,11],feed:5,major:5,upper:5,feel:4,exchang:3,lastnam:5,number:[3,5,13],placehold:5,alexandr:8,done:[5,13],least:[4,5,13],blank:[5,13,1],stabl:5,miss:[5,13,1],ssl_ca_path:13,collat:13,mail_mim:5,interact:3,construct:5,http_cooki:3,station:5,adriaenssen:8,statement:[13,4,5,10],cfg:[4,5,13],enclos:5,ton:13,store:[1,3,4,5,8,10,13],schema:[8,5,13],option:[0,4,5,13,1],relationship:5,girish:8,villanueva:8,feryanto:8,part:[3,13,5,10],pars:[5,13,1],naviwidth:13,webadmin:8,exposur:4,kind:[3,5,13],sta:8,whenev:[5,13],remot:3,remov:[8,4,5,13,14],rsedwardian:8,horizont:[3,5,13],jqueri:9,darlow:8,kindli:5,acko:[3,8],pma:4,comput:3,well:[13,8,4,5,10],wysiwyg:8,packag:[0,4,5,9],translationwarningthreshold:13,mod_rewrit:5,"null":[5,13],wilson:8,unintend:13,bz2:13,equival:13,self:[4,13],also:[1,3,4,5,8,9,10,13,6,14],build:[4,5,13,1],kraai:8,http_user_ag:5,upload_tmp_dir:5,distribut:[0,2,4,5,8,9,13],func_dat:13,previou:[4,5,13],reach:1,chart:[8,5],most:[1,3,4,5,8,13,6],plai:4,myisam:[5,10],alpha:5,max_var:5,kempf:8,charg:13,filesystem:13,clear:[4,5],qbe:[8,10],usual:[3,4,5,13,1],microsoft:[3,5,10],visibl:[5,13],paul:5,think:5,mimer:[5,13],carefulli:13,consult:1,column_:3,session:[4,5,13,6],marc_at_infomarc:[8,2],font:[5,13],fine:5,find:[4,5,13],impact:[4,5,13],access:[3,4,5,8,13,6],beck_at_web:8,pretti:8,scooter:5,solut:[5,13],clipboard:[5,13],iec:[3,10],first__second__third:13,monospac:13,tyron:8,max_array_index_length:5,express:[3,5,13],setenvif:5,gandon_at_isia:8,nativ:5,mainten:[8,10,13],generator_main_class:1,him:8,restart:5,target:5,browsepointercolor:13,ie6:13,rfc:[3,5,10],pundalik:8,defaulttabdatabas:13,common:[3,5,13],nowher:13,kleemann:8,certif:13,set:[0,1,3,4,5,8,9,10,13],dump:[13,8,5,10],creator:8,psbot0:5,see:[1,2,3,4,5,8,10,13,6],seo:5,reserv:13,browsemarkercolor:13,alexukf:8,lee:8,someth:[4,5,13],won:[5,13],gd_graphics_librari:3,opera7:5,opera6:5,ssl_cipher:13,navigationtreetablesepar:[5,13],altern:[4,5,13],numer:[5,13],serverdefault:13,javascript:[8,6,5,13],navigationhid:13,disallow:[4,13],lowercas:[4,5],solv:5,wiltav:8,both:[4,5,13],cryptic:5,last:[5,13,1],mod_gzip_item_includ:5,foreign:[3,13,5,10],context:5,pdf:[0,3,4,5,8,10,13],whole:[13,4,5,10],load:[13,4,5,10,6],simpli:[4,5,13,14],point:[3,5,13],utf8_general_ci:13,joaotmdia:8,documentclass:5,shutdown:5,suppli:[4,13],desktop:5,shanyan:8,java:5,sessionsavepath:13,navigationlogolinkwindow:13,devic:3,due:[5,13],empti:[5,13],secret:13,senderrorreport:13,memory_limit:5,org:[3,8,5,13,2],repeatcel:13,mind:4,imag:[1,3,6,5,10,13],great:[8,12],coordin:[5,13],understand:[4,5,10],paulei:8,mkkeck_at_us:[8,2],remote_us:5,setfacl:13,batch:10,"while":[5,13,1],match:[5,13],behavior:[9,5,13],error:[8,4,5,13],anonym:[5,13],everyon:8,pack:5,real:[5,13],mac_os_x:3,readi:4,jpg:3,asuni:8,defaultconnectioncol:13,cento:4,alter_priv:4,attach:[3,13],ignacio:8,fedora:4,minim:[4,5],shorten:5,shorter:5,conflict:5,higher:5,signon:[4,13],veeven_at_gmail:8,proxypassreversecookiepath:5,optim:[8,5,13],ssl_kei:13,alert:5,"tom\u00e1\u0161":8,temporari:[4,5,13],winhttp:5,maxdblist:13,winnt4:5,recent:[3,4,5,13],lower:[5,13],drop_priv:4,lib:[4,5,1,9],older:[0,4,5,13],kelli:8,entri:[4,13],searchabl:4,person:[3,5,13],userstatu:5,mandriva:4,vazquez:8,lin:8,propos:[5,10],explan:[4,5],from:[0,1,3,4,5,8,10,13,14],table_:3,administ:10,rutkowski:8,snappi:5,getinfo:1,shortcut:13,mydatabas:13,input:[4,5,13],useless:5,bin:[8,5],checklink:5,thilanka:8,varchar:[5,13],format:[1,3,4,5,8,10,13],big:[5,13],catalan:8,tabl:[0,1,3,4,5,8,10,13,14],lanin:8,backquot:5,insert:[8,4,5,13],bit:[6,13],oleg_at_gmail:8,lost:[5,13],table_info:13,resolv:5,collect:3,"boolean":13,proxypassrevers:5,popular:3,engstrom:8,tbl_sql:13,vendor_config:9,often:[5,13],creation:[8,13],some:[1,3,4,5,8,9,13],back:[3,4,5,14],scratchboard:[8,5],proxyurl:13,sampl:[4,5,13],pmadb:[5,13],mirror:5,scale:5,pratap:8,bruce:3,larg:[5,13],slash:13,reproduc:5,cgi:[3,4,5],object:[3,1],run:[3,4,5,13],zzz:13,ummer:5,weis:8,cochran:8,step:[4,5],bruguera:8,impos:13,blowfish_:3,mmcach:5,delisl:[8,7,2],captchaloginpublickei:[4,13],func_char:13,mcrypt:[3,4,5,13,6],italian:8,gamma:5,allowthirdpartyfram:13,person_nam:5,displaybinaryashex:13,within:[14,5,13],row_:3,slovak:8,klokner:8,steven:8,ensur:[4,5,13],chang:[1,3,4,5,8,9,10,13,14],pcre:[3,5,13],server_:3,cj_at_gmail:8,sock:5,fast:5,custom:[0,1,5,8,9,13],includ:[1,3,4,5,8,9,13],suit:[3,5],forward:[5,13],stoyanst:8,properli:[4,5,10],electrotechn:3,usedbsearch:13,chaudhari:8,link:[1,4,5,8,10,13,14],translat:[0,5,13,8],newer:[4,5,13,6],upright:5,line:[3,4,5,13,1],torsten:8,trustedproxi:13,utf:3,consist:5,mrbendig:8,hamann:8,reorder:5,mj12bot:5,highlight:13,similar:[4,5,13],enlarg:5,parser:8,chao:8,doesn:[5,13,1],repres:[3,5,13],"char":[5,13],thomsen:8,incomplet:13,tar_:3,overcom:5,guarante:13,curl:5,rewritecond:5,titl:[0,13],invalid:[5,13],town_cod:5,nick:5,urltrend:5,tempdir:[5,13],proxypass:[5,13],navipointercolor:13,show_db_priv:4,heis:5,drag:5,captchaloginprivatekei:[4,13],clue:5,lang:[5,13],titlet:13,algorithm:[3,4,13],mimetyp:[5,13,1],rewritebas:5,sherbrook:5,depth:5,foreignkeydropdownord:13,errorcod:5,scroll:5,albiol:8,partial:13,queri:[0,3,4,5,8,10,13],steve:8,broader:3,edu:8,funck:8,privat:[5,13],bzipdump:13,turkish:8,sensit:13,only_db:[4,13],wizard:4,send:[5,13],headerfliptyp:13,becam:13,sens:1,sent:[3,8,5,13],deactiv:[5,13],unzip:4,logincookiedeleteal:13,zigmanta:8,master_db:13,implicitli:3,portable_document_format:3,relev:13,net_socket:5,tri:[4,5,13],ajaxif:8,button:[4,5,13],michael:[8,2],stuffit:4,fewer:13,"try":[4,5,13],mathia:8,alia:8,queryhistorymax:13,refer:[3,5,13],pleas:[4,5,13,1,9],impli:2,smaller:[8,5,13],visualis:5,natur:13,wors:5,noblob:13,uniqu:[3,5],jump:13,defaultdisplai:13,gmbh:5,user_prefer:13,odn:8,tobias_at_ratschil:[8,2],download:[4,10],ratschil:[8,2],click:[14,5,13,1],append:[13,1],victor:8,compat:[3,4,5,8,9,6],index:[0,3,4,5,8,10,13],ia_archiv:5,computer_sci:3,cell:[3,5,13],experiment:13,isapi:[3,4,5],typo3:8,gheni:8,chose:[4,5],tracking_add_drop_databas:13,vinai:8,internet_protocol:3,firewal:[4,5,13],logout:13,ubuntu:[4,13],vertic:[3,8,13],sinc:[8,4,5,13,6],pma_dbi:8,convert:5,didn:13,copyright:[0,2],themedefault:[5,13],baishui:8,larger:[5,13],technolog:[3,5],delorm:8,cert:13,typim:8,auth_kei:4,typic:[3,5],forkik_at_gmail:8,control:[3,4,5,8,13,14],bzip2:[3,5,13],firefox:5,haa:8,appli:[4,5,13,1],approxim:[5,13],foundat:2,gatewai:3,api:[3,5],seosearch:5,apc:[5,13],pma__track:13,zerofil:1,usb:4,zip:[3,6,5,8,10,13],commun:[3,10],doubl:[5,13],upgrad:[0,4,5],intitl:5,next:[4,5,13],websit:[3,8,5,12],few:[4,5,13],lesli:8,webcrawl:5,ninad:8,sort:[3,5,13],pencil:14,client_:3,browsemarkerbackground:13,newsblog:5,pdfpages:13,trail:13,defaultqueryt:13,central:[4,5,13],harvest:5,abtract:1,account:[10,13],john_db:5,retriev:13,gabriel:8,ne0x_at_us:8,when:[4,5,8,10,13,6],showal:13,opensource_at_jth:8,obvious:4,"j\u00f8rgen":8,scatter:5,employe:5,user_bas:4,weaker:13,tar:[3,4],process:[3,14,5],lock:[5,13],codemirroren:13,high:[5,13],auth_http_realm:13,tag:5,jeev:5,tab:[0,5,13],opensourc:8,onlin:5,delai:5,andersen:8,siu:8,slovenian:8,subdirectori:[4,5,13],instead:[4,5,13],chri:8,stock:4,pink:5,klau:5,gentoo:4,attent:4,mod_ssl:5,nordenberg:8,alloc:13,ssl_cert:13,walton_at_nordicdm:8,light:13,astarita:8,correspond:[5,13,1],element:[3,5,1],issu:[5,13],encyclopedia:3,allow:[3,4,5,8,10,13,14],subtyp:1,fallback:13,cbb74bc:4,include_path:5,me_at_mynetx:8,move:[4,5,13],iconvextraparam:13,pruett:8,comma:3,korakot_at_inam:8,themeperserv:13,bunch:5,fontfamili:13,edlund_at_upright:8,till:[4,5],chosen:5,wget:5,fujifilm:8,clickabl:[5,13],ukf_at_gmail:8,dorning:5,therefor:13,pixel:13,crash:5,handl:[14,5,13,1],auto:[5,13],dan:8,auth:[4,5,13],repositori:[3,4],mention:[4,5],geert:8,krukowski:8,somewher:5,anyth:4,edit:[0,4,5,10,11,13,14],mode:[0,4,5,8,13,6],beneath:5,register_glob:5,showphpinfo:13,subset:10,strip:[9,5,13],consum:3,drizzl:[8,6,5,13],httrack:5,our:[1,5,8,7,12,13],navigationtreetablelevel:13,patch:[8,13],tracking_add_drop_view:13,special:[3,4,5,13],out:[3,4,5,13,12],variabl:[5,13,1],gandon:8,showstat:13,acunetix:5,naeem:8,index_:3,rel:5,hardwar:13,sp2:5,red:4,statist:[8,5,13],insid:[4,5,13,1,9],manipul:[3,10,13],querywindowwidth:13,transliter:13,releas:[8,5,13],mysql_pconnect:13,designer_coord:13,could:[4,5,13],david:8,navigationdisplaylogo:13,length:[5,13],enforc:13,organis:3,db_sql:13,outsid:[4,13,1],transfer:[3,4,5,13],geometri:5,manuzhai:8,endors:7,baiduspid:5,suffix:13,christoph:8,brute:5,exact:13,date:[5,13],muhammad:8,buggi:[4,5],netcologn:5,owner:[4,13],showchgpassword:13,suffic:4,alioglu:8,"long":[3,5,13,1],strict:13,rouslan_at_placella:8,unknown:5,licens:2,mkdir:[4,5],system:[3,4,5,8,9,13],messag:[4,5,13],ssloption:5,fontfamilyfix:13,attack:[4,5,13],appl:3,lower_case_table_nam:5,pavel:8,rfc2616_header:5,lacina:8,ipv4:3,shell:5,lot:[5,13],methodolog:3,slider:13,obgzip:[5,13],textfield:1,haven:5,gzipdump:13,photograph:3,structur:[0,1,3,5,10,11,13],charact:[3,4,5,13,1],htaccess:[3,4,5],seriou:5,stoyanster_at_gmail:8,upload_progress:5,julian:3,respons:3,robot:[4,5],sysadmin:[5,13],miquel:8,have:[1,2,4,5,8,10,12,13,14],ari:8,close:[5,13],turn:[5,13],border:13,afraid:4,rout:13,browsemim:13,which:[1,3,4,5,10,13,6,14],singh:8,exabot:5,singl:[3,13,4,5,10],"5b4":5,brazil:8,untar:4,unless:[4,5],transmit:5,who:[1,4,5,8,9,10,13],discov:4,cipher:[3,13],buddika:8,nutchcv:5,stdenvvar:5,herman:8,placement:5,secure_sockets_lay:3,url:[3,5,13],uploaddir:[5,13],uro:8,showhint:13,face:5,pipe:13,deni:[8,4,5,13],snapshot:13,determin:[14,5,13],built:[8,5],index_priv:4,fact:[5,13],dbm:3,abeyrathna:8,text:[0,1,3,4,5,8,10,13],verbos:[5,13],dbg:13,dbf:5,bring:[4,5],turek:[8,2],"mat\u00eda":8,controlus:[4,5,13],redirect:[5,13],textual:5,locat:[3,4,5],auth_typ:[4,5,13],should:[2,4,5,8,9,13],manufactur:3,bernard:8,tape:3,local:[4,5,13],"lu\u00ed":8,hope:2,contribut:[8,5,12],autom:[8,4],recode_str:13,drawn:1,increas:[5,13],db2:13,awai:5,takahashi:8,shp:5,enabl:[1,3,4,5,13,6],organ:3,showasphp:13,navarro:8,stuff:8,she:5,contain:[4,5,13,1],grab:5,mynam:5,statuscachedatabas:13,kawada:8,conform:3,win98:5,frame:[8,5,13],mod_gzip:5,packet:3,malfunct:5,dialog:[4,5],alessandro:8,temporarili:5,tracking_add_drop_t:13,statu:[8,5,13],convers:[8,13],pdfdefaultpages:13,correctli:[5,13],mainli:3,nopassword:13,dll:5,written:[5,13,12],default_socket:5,boutel:3,navigationtreedisplaydbfilterminimum:13,longtabl:5,neither:[5,13],thumbnail:6,classless:13,kei:[3,4,5,8,10,13],smart:13,job:4,entir:[4,5,6],joe:[8,5],webapp:4,server_privileg:13,addit:[3,8,4,5,13],plugin:[8,5,1],wisenutbot:5,libiconv:13,etc:[4,5,13,1],instanc:13,admir:8,tschopp:8,strftime:5,comment:[3,8,4,5,13],hyphen:5,chmod:[4,5,13],defaultquerydatabas:13,respect:5,gheni_at_yahoo:8,withdrawn:[8,5],unclean:5,quit:[8,5,13],disablemultitablemainten:13,"10_at_windowsl":8,addition:13,compos:13,signonscript:[4,13],json:[6,5],slashdot:13,treat:5,logincookiestor:13,infrastructur:4,filippo:5,adob:3,reservedworddisablewarn:13,moreov:5,togeth:[4,5,13],present:[5,13],hitowerdigit_at_hotmail:8,replic:8,multi:[0,3,4,5,8,13],tbl_chang:[8,13],showdbstructurecr:13,"\u010diha\u0159":[8,4,2],align:5,yuichiro:8,harden:5,defin:[3,14,5,13,1],wilk:8,glossari:[3,0],server_databas:13,ini:[13,5,10],layer:3,purchas:4,dieter:8,almost:13,demo:13,site:[4,5,13,7],skiplockedt:13,archiv:[3,5],incom:4,revis:[3,5],pmaabsoluteuri:[5,13],let:[5,13],welcom:[0,4,5],japanes:8,stored_procedur:3,referenti:[10,13],cross:[3,4,13],python:5,pma_password:5,select_priv:4,abravo_at_hq:8,linklengthlimit:13,probabl:[4,5,9],difficult:5,proxypassreversecookiedomain:5,stankruk_at_neostrada:8,mousewheel:5,hostnam:[3,5,13],expans:5,effect:[7,5,13,1],naturalord:13,thcolor:13,php:[0,1,3,4,5,8,9,10,13,6],codemirror:13,login:[4,5,13],expand:5,keep:[4,5,13],real_us:4,off:[5,13],center:[4,5],nevertheless:4,builder:8,jayaratn:8,real_password:4,exampl:[4,5,8,9,10,13],command:[4,5,13],choos:[4,5,13,1],undefin:5,fail:[5,13],metagerbot:5,yasir:8,latest:[3,5,13],mehboobbugti_at_gmail:8,newest:13,cspallow:13,less:[4,5,13],obtain:13,tcp:[3,5,13],gettext:9,skill:5,robert_readman_at_hotmail:8,web:[0,3,4,5,8,9,13,6],mainbackground:13,smith:5,script:[8,4,5,13,9],add:[4,5,13,14],other:[0,1,3,4,5,7,9,10,11,12,13,14],uighur:8,showsql:13,pma__column_com:13,kick:5,css2:8,bigdump:5,rememb:[5,13],max_request_vari:5,setinputfilt:5,pma__table_info:[5,13],know:[5,1],redesign:8,tick:13,desc:13,konqueror:5,like:[1,4,5,8,10,13],success:5,header:[5,13],pma__column_info:13,necessari:[5,1],navibackground:13,martin:8,separated_valu:3,resiz:5,page:[0,1,3,4,5,6,8,7,13,14],crawler:5,revers:[5,13],prepend:1,convei:3,jan:8,"kozio\u0142":8,linux:[0,4,13,9],"landh\u00e4u\u00df":8,"export":[13,0,5,10,8],unstuff:4,proper:[13,4,5,10,1],home:14,fileinfo:5,peter:8,laurent:8,librari:[0,1,3,4,5,8,9,13,6],tmp:[5,13],win32:[4,5],guid:[0,7,11],my_db:13,lead:5,avoid:[5,13],phpinfo:[5,13],octet:5,tooltip:5,leav:[5,13,1],lord_dark_at_wp:8,backend:5,kiddi:5,getnam:1,"enum":[8,1],usag:[1,4,5,11,13,14],host:[1,3,4,5,8,13],although:[8,5],"7euser":5,panel:[0,4,5,13],about:[0,1,4,5,10,13],misbehav:5,actual:[5,1],socket:[3,5,13],kawada_at_den:8,column:[1,3,4,5,8,10,13],andersen_at_gmail:8,zip_:3,localnetb:13,localneta:13,disabl:[4,5,13],not_nul:1,own:[13,4,5,10,1],sarna:8,actionlinksmod:13,transformation_overview:1,automat:[3,4,5,8,10,13],create_t:4,warranti:2,lund:8,robbat2_at_us:[8,2],generator_plugin:1,sander:8,w3c:[3,5],van:8,panagioti:8,much:1,downgrad:5,kang:8,"var":[9,5],favorit:[4,5],"function":[1,3,5,8,10,13],unexpect:5,alexi:8,lossi:3,soulard:8,eas:1,inlin:6,bug:[8,5,13],piller:8,count:[5,13],made:[3,8,5,13],database_trigg:3,whether:[14,13,9],wish:[4,13,14],defaultfunct:13,displai:[0,1,3,4,5,8,10,13,6],troubl:[5,13],record:[3,14],below:[4,5,13,1],meta:[13,1],limit:[0,4,5,13],shutdown_priv:4,otherwis:[5,13],problem:[3,4,5,13],significantli:6,epel:4,"int":5,ilnytskyi:8,dure:[5,13],filenam:[5,1],implement:[3,13,1],erik:[8,5],sinhala:8,error_handl:13,stefan_at_inkopsforum:8,nakandala:8,detail:[4,5,13,2],logincookierecal:13,book:[7,11],futur:[5,13],branch:[4,5],php4:[8,5],blowfish_secret:[4,13],php3:8,repeat:[5,13],star:8,mysql_upgrad:5,"class":[5,1],june:8,kanichet_at_hotmail:8,server_statu:13,showpropertycom:13,debian:[4,13],gergo314:8,markup:3,outsourc:8,fund:4,reliabl:5,kanji:8,rule:[4,5,13,1],post_max_s:5,portion:13,emerg:4,rajandran:8,decemb:8,phpwizard:[8,5]},objtypes:{"0":"config:option"},titles:["Welcome to phpMyAdmin’s documentation!","Transformations","Copyright","Glossary","Installation","FAQ - Frequently Asked Questions","Requirements","Other sources of information","Credits","Distributing and packaging phpMyAdmin","Introduction","User Guide","Developers Information","Configuration","User management"],objnames:{"0":["config","option","Config config option"]},filenames:["index","transformations","copyright","glossary","setup","faq","require","other","credits","vendors","intro","user","developers","config","privileges"]}) \ No newline at end of file diff --git a/phpMyAdmin/doc/html/setup.html b/phpMyAdmin/doc/html/setup.html new file mode 100644 index 0000000..8699a00 --- /dev/null +++ b/phpMyAdmin/doc/html/setup.html @@ -0,0 +1,549 @@ + + + + + + + + + + Installation — phpMyAdmin 4.1.7 documentation + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Installation¶

+

phpMyAdmin does not apply any special security methods to the MySQL +database server. It is still the system administrator’s job to grant +permissions on the MySQL databases properly. phpMyAdmin’s Users +page can be used for this.

+
+

Warning

+

Mac users should note that if you are on a version before +Mac OS X, StuffIt unstuffs with Mac formats. So you’ll have +to resave as in BBEdit to Unix style ALL phpMyAdmin scripts before +uploading them to your server, as PHP seems not to like Mac-style +end of lines character (“\r”).

+
+
+

Linux distributions¶

+

phpMyAdmin is included in most Linux distributions. It is recommended to use +distribution packages when possible - they usually provide integration to your +distribution and you will automatically get security updates from your distribution.

+
+

Debian¶

+

Debian’s package repositories include a phpMyAdmin package, but be aware that +the configuration file is maintained in /etc/phpmyadmin and may differ in +some ways from the official phpMyAdmin documentation.

+
+
+

OpenSUSE¶

+

OpenSUSE already comes with phpMyAdmin package, just install packages from +the openSUSE Build Service.

+
+
+

Ubuntu¶

+

Ubuntu ships phpMyAdmin package, however if you want to use recent version, you +can use packages from +PPA for Michal ÄŒihaÅ™.

+
+
+

Gentoo¶

+

Gentoo ships the phpMyAdmin package, both in a near stock configuration as well +as in a webapp-config configuration. Use emerge dev-db/phpmyadmin to +install.

+
+
+

Mandriva¶

+

Mandriva ships the phpMyAdmin package in their contrib branch and can be +installed via the usual Control Center.

+
+
+

Fedora¶

+

Fedora ships the phpMyAdmin package, but be aware that the configuration file +is maintained in /etc/phpMyAdmin/ and may differ in some ways from the +official phpMyAdmin documentation.

+
+
+

Red Hat Enterprise Linux¶

+

Red Hat Enterprise Linux itself and thus derivatives like CentOS don’t +ship phpMyAdmin, but the Fedora-driven repository +Extra Packages for Enterprise Linux (EPEL) +is doing so, if it’s +enabled. +But be aware that the configuration file is maintained in +/etc/phpMyAdmin/ and may differ in some ways from the +official phpMyAdmin documentation.

+
+
+
+

Installing on Windows¶

+

The easiest way to get phpMyAdmin on Windows is using third party products +which include phpMyAdmin together with a database and web server such as +XAMPP.

+

You can find more of such options at Wikipedia.

+
+
+

Quick Install¶

+
    +
  1. Choose an appropriate distribution kit from the phpmyadmin.net +Downloads page. Some kits contain only the English messages, others +contain all languages. We’ll assume you chose a kit whose name +looks like phpMyAdmin-x.x.x -all-languages.tar.gz.
  2. +
  3. Untar or unzip the distribution (be sure to unzip the subdirectories): +tar -xzvf phpMyAdmin_x.x.x-all-languages.tar.gz in your +webserver’s document root. If you don’t have direct access to your +document root, put the files in a directory on your local machine, +and, after step 4, transfer the directory on your web server using, +for example, ftp.
  4. +
  5. Ensure that all the scripts have the appropriate owner (if PHP is +running in safe mode, having some scripts with an owner different from +the owner of other scripts will be a problem). See 4.2 What’s the preferred way of making phpMyAdmin secure against evil access? and +1.26 I just installed phpMyAdmin in my document root of IIS but I get the error “No input file specified” when trying to run phpMyAdmin. for suggestions.
  6. +
  7. Now you must configure your installation. There are two methods that +can be used. Traditionally, users have hand-edited a copy of +config.inc.php, but now a wizard-style setup script is provided +for those who prefer a graphical installation. Creating a +config.inc.php is still a quick way to get started and needed for +some advanced features.
  8. +
+
+

Manually creating the file¶

+

To manually create the file, simply use your text editor to create the +file config.inc.php (you can copy config.sample.inc.php to get +minimal configuration file) in the main (top-level) phpMyAdmin +directory (the one that contains index.php). phpMyAdmin first +loads libraries/config.default.php and then overrides those values +with anything found in config.inc.php. If the default value is +okay for a particular setting, there is no need to include it in +config.inc.php. You’ll need a few directives to get going, a +simple configuration may look like this:

+
<?php
+$cfg['blowfish_secret'] = 'ba17c1ec07d65003';  // use here a value of your choice
+
+$i=0;
+$i++;
+$cfg['Servers'][$i]['auth_type']     = 'cookie';
+?>
+
+
+

Or, if you prefer to not be prompted every time you log in:

+
<?php
+
+$i=0;
+$i++;
+$cfg['Servers'][$i]['user']          = 'root';
+$cfg['Servers'][$i]['password']      = 'cbb74bc'; // use here your password
+$cfg['Servers'][$i]['auth_type']     = 'config';
+?>
+
+
+

For a full explanation of possible configuration values, see the +Configuration of this document.

+
+
+

Using Setup script¶

+

Instead of manually editing config.inc.php, you can use the Setup +Script. First you must manually create a folder config +in the phpMyAdmin directory. This is a security measure. On a +Linux/Unix system you can use the following commands:

+
cd phpMyAdmin
+mkdir config                        # create directory for saving
+chmod o+rw config                   # give it world writable permissions
+
+
+

And to edit an existing configuration, copy it over first:

+
cp config.inc.php config/           # copy current configuration for editing
+chmod o+w config/config.inc.php     # give it world writable permissions
+
+
+

On other platforms, simply create the folder and ensure that your web +server has read and write access to it. 1.26 I just installed phpMyAdmin in my document root of IIS but I get the error “No input file specified” when trying to run phpMyAdmin. can help with +this.

+

Next, open setup/ in your browser. If you have an existing configuration, +use the Load button to bring its content inside the setup panel. +Note that changes are not saved to disk until explicitly choose ``Save`` +from the Configuration area of the screen. Normally the script saves the new +config.inc.php to the config/ directory, but if the webserver does +not have the proper permissions you may see the error “Cannot load or +save configuration.” Ensure that the config/ directory exists and +has the proper permissions - or use the Download link to save the +config file locally and upload it (via FTP or some similar means) to the +proper location.

+

Once the file has been saved, it must be moved out of the config/ +directory and the permissions must be reset, again as a security +measure:

+
mv config/config.inc.php .         # move file to current directory
+chmod o-rw config.inc.php          # remove world read and write permissions
+rm -rf config                      # remove not needed directory
+
+
+

Now the file is ready to be used. You can choose to review or edit the +file with your favorite editor, if you prefer to set some advanced +options which the setup script does not provide.

+
    +
  1. If you are using the auth_type “config”, it is suggested that you +protect the phpMyAdmin installation directory because using config +does not require a user to enter a password to access the phpMyAdmin +installation. Use of an alternate authentication method is +recommended, for example with HTTP–AUTH in a .htaccess file or switch to using +auth_type cookie or http. See the ISPs, multi-user installations +for additional information, especially 4.4 phpMyAdmin always gives “Access denied” when using HTTP authentication..
  2. +
  3. Open the main phpMyAdmin directory in your browser. +phpMyAdmin should now display a welcome screen and your databases, or +a login dialog if using HTTP or +cookie authentication mode.
  4. +
  5. You should deny access to the ./libraries and ./setup/lib +subfolders in your webserver configuration. For Apache you can use +supplied .htaccess file in that folder, for other webservers, you should +configure this yourself. Such configuration prevents from possible +path exposure and cross side scripting vulnerabilities that might +happen to be found in that code.
  6. +
  7. It is generally good idea to protect public phpMyAdmin installation +against access by robots as they usually can not do anything good +there. You can do this using robots.txt file in root of your +webserver or limit access by web server configuration, see +1.42 How can I prevent robots from accessing phpMyAdmin?.
  8. +
+
+
+
+

phpMyAdmin configuration storage¶

+

For a whole set of new features (bookmarks, comments, SQL-history, +tracking mechanism, PDF-generation, column contents transformation, +etc.) you need to create a set of special tables. Those tables can be located +in your own database, or in a central database for a multi-user installation +(this database would then be accessed by the controluser, so no other user +should have rights to it).

+

Please look at your ./examples/ directory, where you should find a +file called create_tables.sql. (If you are using a Windows server, +pay special attention to 1.23 I’m running MySQL on a Win32 machine. Each time I create a new table the table and column names are changed to lowercase!).

+

If you already had this infrastructure and upgraded to MySQL 4.1.2 or +newer, please use examples/upgrade_tables_mysql_4_1_2+.sql +and then create new tables by importing +examples/create_tables.sql.

+

You can use your phpMyAdmin to create the tables for you. Please be +aware that you may need special (administrator) privileges to create +the database and tables, and that the script may need some tuning, +depending on the database name.

+

After having imported the examples/create_tables.sql file, you +should specify the table names in your config.inc.php file. The +directives used for that can be found in the Configuration. You will also need to +have a controluser with the proper rights to those tables (see section +Using authentication modes below).

+
+
+

Upgrading from an older version¶

+

Simply copy config.inc.php from your previous installation into +the newly unpacked one. Configuration files from old versions may +require some tweaking as some options have been changed or removed. +For compatibility with PHP 6, remove a +set_magic_quotes_runtime(0); statement that you might find near +the end of your configuration file.

+

You should not copy libraries/config.default.php over +config.inc.php because the default configuration file is version- +specific.

+

If you have upgraded your MySQL server from a version previous to 4.1.2 to +version 5.x or newer and if you use the phpMyAdmin configuration storage, you +should run the SQL script found in +examples/upgrade_tables_mysql_4_1_2+.sql.

+
+
+

Using authentication modes¶

+

HTTP and cookie authentication modes are recommended in a multi-user +environment where you want to give users access to their own database and +don’t want them to play around with others. Nevertheless be aware that MS +Internet Explorer seems to be really buggy about cookies, at least till version +6. Even in a single-user environment, you might prefer to use HTTP +or cookie mode so that your user/password pair are not in clear in the +configuration file.

+

HTTP and cookie authentication +modes are more secure: the MySQL login information does not need to be +set in the phpMyAdmin configuration file (except possibly for the +$cfg['Servers'][$i]['controluser']). +However, keep in mind that the password travels in plain text, unless +you are using the HTTPS protocol. In cookie mode, the password is +stored, encrypted with the blowfish algorithm, in a temporary cookie.

+

For ‘HTTP‘ and ‘cookie’ modes, phpMyAdmin needs a controluser that has +only the SELECT privilege on the `mysql`.`user` (all columns except +`Password`), `mysql`.`db` (all columns), `mysql`.`host` (all columns) and +`mysql`.`tables_priv` (all columns except `Grantor` and `Timestamp`) tables. +You must specify the details for the controluser in the config.inc.php +file under the $cfg['Servers'][$i]['controluser'] and +$cfg['Servers'][$i]['controlpass'] settings. The following +example assumes you want to use pma as the controluser and pmapass as +the controlpass, but this is only an example: use something else in your +file! Input these statements from the phpMyAdmin SQL Query window or +mysql command–line client. Of course you have to replace localhost with the +webserver’s host if it’s not the same as the MySQL server’s one.

+
GRANT USAGE ON mysql.* TO 'pma'@'localhost' IDENTIFIED BY 'pmapass';
+GRANT SELECT (
+Host, User, Select_priv, Insert_priv, Update_priv, Delete_priv,
+Create_priv, Drop_priv, Reload_priv, Shutdown_priv, Process_priv,
+File_priv, Grant_priv, References_priv, Index_priv, Alter_priv,
+Show_db_priv, Super_priv, Create_tmp_table_priv, Lock_tables_priv,
+Execute_priv, Repl_slave_priv, Repl_client_priv
+) ON mysql.user TO 'pma'@'localhost';
+GRANT SELECT ON mysql.db TO 'pma'@'localhost';
+GRANT SELECT ON mysql.host TO 'pma'@'localhost';
+GRANT SELECT (Host, Db, User, Table_name, Table_priv, Column_priv)
+ON mysql.tables_priv TO 'pma'@'localhost';
+
+
+

If you want to use the many new relation and bookmark features:

+
GRANT SELECT, INSERT, UPDATE, DELETE ON <pma_db>.* TO 'pma'@'localhost';
+
+
+

(this of course requires that your phpMyAdmin configuration storage be set up).

+

Then each of the true users should be granted a set of privileges +on a set of particular databases. Normally you shouldn’t give global +privileges to an ordinary user, unless you understand the impact of those +privileges (for example, you are creating a superuser). +For example, to grant the user real_user with all privileges on +the database user_base:

+
GRANT ALL PRIVILEGES ON user_base.* TO 'real_user'@localhost IDENTIFIED BY 'real_password';
+
+
+

What the user may now do is controlled entirely by the MySQL user management +system. With HTTP or cookie authentication mode, you don’t need to fill the +user/password fields inside the $cfg['Servers'].

+
+

HTTP authentication mode¶

+ +
+ +
+

Signon authentication mode¶

+
    +
  • This mode is a convenient way of using credentials from another +application to authenticate to phpMyAdmin.
  • +
  • The other application has to store login information into session +data.
  • +
+ +
+
+

Config authentication mode¶

+
    +
  • This mode is the less secure one because it requires you to fill the +$cfg['Servers'][$i]['user'] and +$cfg['Servers'][$i]['password'] +fields (and as a result, anyone who can read your config.inc.php +can discover your username and password). But you don’t need to setup +a “controluser” here: using the $cfg['Servers'][$i]['only_db'] might be enough.
  • +
  • In the ISPs, multi-user installations section, there is an entry explaining how +to protect your configuration file.
  • +
  • For additional security in this mode, you may wish to consider the +Host authentication $cfg['Servers'][$i]['AllowDeny']['order'] +and $cfg['Servers'][$i]['AllowDeny']['rules'] configuration directives.
  • +
  • Unlike cookie and http, does not require a user to log in when first +loading the phpMyAdmin site. This is by design but could allow any +user to access your installation. Use of some restriction method is +suggested, perhaps a .htaccess file with the HTTP-AUTH directive or disallowing +incoming HTTP requests at one’s router or firewall will suffice (both +of which are beyond the scope of this manual but easily searchable +with Google).
  • +
+
+
+

Swekey authentication mode¶

+

The Swekey is a low cost authentication USB key that can be used in +web applications. When Swekey authentication is activated, phpMyAdmin +requires the users’s Swekey to be plugged before entering the login +page (currently supported for cookie authentication mode only). Swekey +Authentication is disabled by default. To enable it, add the following +line to config.inc.php:

+
$cfg['Servers'][$i]['auth_swekey_config'] = '/etc/swekey.conf';
+
+
+

You then have to create the swekey.conf file that will associate +each user with their Swekey Id. It is important to place this file +outside of your web server’s document root (in the example, it is +located in /etc). A self documented sample file is provided in the +examples directory. Feel free to use it with your own users’ +information. If you want to purchase a Swekey please visit +http://phpmyadmin.net/auth_key +since this link provides funding for phpMyAdmin.

+ +
+
+
+

Securing your phpMyAdmin installation¶

+

The phpMyAdmin team tries hardly to make the application secure, however there +are always ways to make your installation more secure:

+ +
+
+ + +
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/phpMyAdmin/doc/html/transformations.html b/phpMyAdmin/doc/html/transformations.html new file mode 100644 index 0000000..8562e14 --- /dev/null +++ b/phpMyAdmin/doc/html/transformations.html @@ -0,0 +1,240 @@ + + + + + + + + + + Transformations — phpMyAdmin 4.1.7 documentation + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Transformations¶

+
+

Introduction¶

+

To enable transformations, you have to setup the column_info +table and the proper directives. Please see the Configuration on how to do so.

+

You can apply different transformations to the contents of each +column. The transformation will take the content of each column and +transform it with certain rules defined in the selected +transformation.

+

Say you have a column ‘filename’ which contains a filename. Normally +you would see in phpMyAdmin only this filename. Using transformations +you can transform that filename into a HTML link, so you can click +inside of the phpMyAdmin structure on the column’s link and will see +the file displayed in a new browser window. Using transformation +options you can also specify strings to append/prepend to a string or +the format you want the output stored in.

+

For a general overview of all available transformations and their +options, you can consult your <www.your-host.com>/<your-install- +dir>/transformation_overview.php installation.

+

For a tutorial on how to effectively use transformations, see our +Link section on the +official phpMyAdmin homepage.

+
+
+

Usage¶

+

Go to your tbl_structure.php page (i.e. reached through clicking on +the ‘Structure’ link for a table). There click on “Change” (or change +icon) and there you will see three new fields at the end of the line. +They are called ‘MIME-type’, ‘Browser transformation’ and +‘Transformation options’.

+
    +
  • The field ‘MIME-type’ is a drop-down field. Select the MIME-type that +corresponds to the column’s contents. Please note that transformations +are inactive as long as no MIME-type is selected.
  • +
  • The field ‘Browser transformation’ is a drop-down field. You can +choose from a hopefully growing amount of pre-defined transformations. +See below for information on how to build your own transformation. +There are global transformations and mimetype-bound transformations. +Global transformations can be used for any mimetype. They will take +the mimetype, if necessary, into regard. Mimetype-bound +transformations usually only operate on a certain mimetype. There are +transformations which operate on the main mimetype (like ‘image’), +which will most likely take the subtype into regard, and those who +only operate on a specific subtype (like ‘image/jpeg’). You can use +transformations on mimetypes for which the function was not defined +for. There is no security check for you selected the right +transformation, so take care of what the output will be like.
  • +
  • The field ‘Transformation options’ is a free-type textfield. You have +to enter transform-function specific options here. Usually the +transforms can operate with default options, but it is generally a +good idea to look up the overview to see which options are necessary. +Much like the ENUM/SET-Fields, you have to split up several options +using the format ‘a’,’b’,’c’,...(NOTE THE MISSING BLANKS). This is +because internally the options will be parsed as an array, leaving the +first value the first element in the array, and so forth. If you want +to specify a MIME character set you can define it in the +transformation_options. You have to put that outside of the pre- +defined options of the specific mime-transform, as the last value of +the set. Use the format “’; charset=XXX’”. If you use a transform, for +which you can specify 2 options and you want to append a character +set, enter “‘first parameter’,’second parameter’,’charset=us-ascii’”. +You can, however use the defaults for the parameters: “’‘,’‘,’charset +=us-ascii’”.
  • +
+
+
+

File structure¶

+

All specific transformations for mimetypes are defined through class +files in the directory ‘libraries/plugins/transformations/’. Each of +them extends a certain transformation abstract class declared in +libraries/plugins/transformations/abstract.

+

They are stored in files to ease up customization and easy adding of +new transformations.

+

Because the user cannot enter own mimetypes, it is kept sure that +transformations always work. It makes no sense to apply a +transformation to a mimetype the transform-function doesn’t know to +handle.

+

There is a file called ‘transformations.lib.php‘ that provides some +basic functions which can be included by any other transform function.

+

The file name convention is [Mimetype]_[Subtype]_[Transformation +Name].class.php, while the abtract class that it extends has the +name [Transformation Name]TransformationsPlugin. All of the +methods that have to be implemented by a transformations plug-in are:

+
    +
  1. getMIMEType() and getMIMESubtype() in the main class;
  2. +
  3. getName(), getInfo() and applyTransformation() in the abstract class +it extends.
  4. +
+

The getMIMEType(), getMIMESubtype() and getName() methods return the +name of the MIME type, MIME Subtype and transformation accordingly. +getInfo() returns the transformation’s description and possible +options it may receive and applyTransformation() is the method that +does the actual work of the transformation plug-in.

+

Please see the libraries/plugins/transformations/TEMPLATE and +libraries/plugins/transformations/TEMPLATE_ABSTRACT files for adding +your own transformation plug-in. You can also generate a new +transformation plug-in (with or without the abstract transformation +class), by using +libraries/plugins/transformations/generator_plugin.sh or +libraries/plugins/transformations/generator_main_class.sh.

+

The applyTransformation() method always gets passed three variables:

+
    +
  1. $buffer - Contains the text inside of the column. This is the +text, you want to transform.
  2. +
  3. $options - Contains any user-passed options to a transform +function as an array.
  4. +
  5. $meta - Contains an object with information about your column. The +data is drawn from the output of the mysql_fetch_field() function. This means, all +object properties described on the manual page are available in this +variable and can be used to transform a column accordingly to +unsigned/zerofill/not_null/... properties. The $meta->mimetype +variable contains the original MIME-type of the column (i.e. +‘text/plain’, ‘image/jpeg’ etc.)
  6. +
+
+
+ + +
+
+
+
+
+

Table Of Contents

+ + +

Previous topic

+

User Guide

+

Next topic

+

User management

+

This Page

+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/phpMyAdmin/doc/html/user.html b/phpMyAdmin/doc/html/user.html new file mode 100644 index 0000000..36ffc59 --- /dev/null +++ b/phpMyAdmin/doc/html/user.html @@ -0,0 +1,135 @@ + + + + + + + + + + User Guide — phpMyAdmin 4.1.7 documentation + + + + + + + + + + + + + + + + +
+ +
+
+

Previous topic

+

Configuration

+

Next topic

+

Transformations

+

This Page

+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/phpMyAdmin/doc/html/vendors.html b/phpMyAdmin/doc/html/vendors.html new file mode 100644 index 0000000..d1716ae --- /dev/null +++ b/phpMyAdmin/doc/html/vendors.html @@ -0,0 +1,147 @@ + + + + + + + + + + Distributing and packaging phpMyAdmin — phpMyAdmin 4.1.7 documentation + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Distributing and packaging phpMyAdmin¶

+

This document is intended to give advices to people who want to +redistribute phpMyAdmin inside other software package such as Linux +distribution or some all in one package including web server and MySQL +server.

+

Generally you can customize some basic aspects (paths to some files and +behavior) in libraries/vendor_config.php.

+

For example if you want setup script to generate config file in var, change +SETUP_CONFIG_FILE to /var/lib/phpmyadmin/config.inc.php and you +will also probably want to skip directory writable check, so set +SETUP_DIR_WRITABLE to false.

+
+

External libraries¶

+

phpMyAdmin includes several external libraries, you might want to +replace them with system ones if they are available, but please note +that you should test whether version you provide is compatible with the +one we ship.

+

Currently known list of external libraries:

+
+
js/jquery
+
jQuery js framework and various jQuery based libraries.
+
libraries/php-gettext
+
php-gettext library
+
libraries/tcpdf
+
tcpdf library, stripped down of not needed files
+
+
+
+ + +
+
+
+
+
+

Table Of Contents

+ + +

Previous topic

+

Developers Information

+

Next topic

+

Copyright

+

This Page

+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/phpMyAdmin/doc/index.rst b/phpMyAdmin/doc/index.rst new file mode 100644 index 0000000..917ddf8 --- /dev/null +++ b/phpMyAdmin/doc/index.rst @@ -0,0 +1,32 @@ +.. phpMyAdmin documentation master file, created by + sphinx-quickstart on Wed Sep 26 14:04:48 2012. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to phpMyAdmin's documentation! +====================================== + +Contents: + +.. toctree:: + :maxdepth: 2 + + intro + require + setup + config + user + faq + developers + vendors + copyright + credits + glossary + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`search` +* :ref:`glossary` diff --git a/phpMyAdmin/doc/intro.rst b/phpMyAdmin/doc/intro.rst new file mode 100644 index 0000000..9576814 --- /dev/null +++ b/phpMyAdmin/doc/intro.rst @@ -0,0 +1,68 @@ +.. _intro: + +Introduction +============ + +phpMyAdmin can manage a whole MySQL server (needs a super-user) as +well as a single database. To accomplish the latter you'll need a +properly set up MySQL user who can read/write only the desired +database. It's up to you to look up the appropriate part in the MySQL +manual. + + +Supported features +------------------ + +Currently phpMyAdmin can: + +* browse and drop databases, tables, views, columns and indexes +* display multiple results sets through stored procedures or queries +* create, copy, drop, rename and alter databases, tables, columns and + indexes +* maintenance server, databases and tables, with proposals on server + configuration +* execute, edit and bookmark any :term:`SQL`-statement, even batch-queries +* load text files into tables +* create [#f1]_ and read dumps of tables +* export [#f1]_ data to various formats: :term:`CSV`, :term:`XML`, :term:`PDF`, + :term:`ISO`/:term:`IEC` 26300 - :term:`OpenDocument` Text and Spreadsheet, Microsoft + Word 2000, and LATEX formats +* import data and :term:`MySQL` structures from :term:`OpenDocument` spreadsheets, as + well as :term:`XML`, :term:`CSV`, and :term:`SQL` files +* administer multiple servers +* manage MySQL users and privileges +* check referential integrity in MyISAM tables +* using Query-by-example (QBE), create complex queries automatically + connecting required tables +* create :term:`PDF` graphics of your + database layout +* search globally in a database or a subset of it +* transform stored data into any format using a set of predefined + functions, like displaying BLOB-data as image or download-link +* track changes on databases, tables and views +* support InnoDB tables and foreign keys see :ref:`faq3_6` +* support mysqli, the improved MySQL extension see :ref:`faq1_17` +* create, edit, call, export and drop stored procedures and functions +* create, edit, export and drop events and triggers +* communicate in `62 different languages + `_ + + +A word about users +------------------ + +Many people have difficulty understanding the concept of user +management with regards to phpMyAdmin. When a user logs in to +phpMyAdmin, that username and password are passed directly to MySQL. +phpMyAdmin does no account management on its own (other than allowing +one to manipulate the MySQL user account information); all users must +be valid MySQL users. + +.. rubric:: Footnotes + +.. [#f1] + + phpMyAdmin can compress (:term:`Zip`, :term:`GZip` or :term:`RFC 1952` + formats) dumps and :term:`CSV` exports if you use PHP with + :term:`Zlib` support (``--with-zlib``). + Proper support may also need changes in :file:`php.ini`. diff --git a/phpMyAdmin/doc/make.bat b/phpMyAdmin/doc/make.bat new file mode 100644 index 0000000..19b6090 --- /dev/null +++ b/phpMyAdmin/doc/make.bat @@ -0,0 +1,190 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +set I18NSPHINXOPTS=%SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\phpMyAdmin.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\phpMyAdmin.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +:end diff --git a/phpMyAdmin/doc/other.rst b/phpMyAdmin/doc/other.rst new file mode 100644 index 0000000..aa95451 --- /dev/null +++ b/phpMyAdmin/doc/other.rst @@ -0,0 +1,18 @@ +Other sources of information +============================ + +Printed Book +------------ + +The definitive guide to using phpMyAdmin is the book Mastering phpMyAdmin for +Effective MySQL Management by Marc Delisle. You can get information on that +book and other officially endorsed `books at the phpMyAdmin site`_. + +.. _books at the phpMyAdmin site: http://www.phpmyadmin.net/home_page/docs.php?books + +Tutorials +--------- + +Third party tutorials and articles are listed on our `wiki page`_. + +.. _wiki page: http://wiki.phpmyadmin.net/pma/Articles diff --git a/phpMyAdmin/doc/privileges.rst b/phpMyAdmin/doc/privileges.rst new file mode 100644 index 0000000..0c12932 --- /dev/null +++ b/phpMyAdmin/doc/privileges.rst @@ -0,0 +1,50 @@ +User management +=============== + +User management is the process of controlling which users are allowed to +connect to the MySQL server and what permissions they have on each database. +phpMyAdmin does not handle user management, rather it passes the username and +password on to MySQL, which then determines whether a user is permitted to +perform a particular action. Within phpMyAdmin, administrators have full +control over creating users, viewing and editing privileges for existing users, +and removing users. + +Within phpMyAdmin, user management is controlled via the :guilabel:`Users` link +from the main page. Users can be created, edited, and removed. + +Creating a new user +------------------- + +To create a new user, click the :guilabel:`Add a new user` link near the bottom +of the :guilabel:`Users` page (you must be a "superuser", e.g., user "root"). +Use the textboxes and drop-downs to configure the user to your particular +needs. You can then select whether to create a database for that user and grant +specific global privileges. Once you've created the user (by clicking Go), you +can define that user's permissions on a specific database (don't grant global +privileges in that case). In general, users do not need any global privileges +(other than USAGE), only permissions for their specific database. + +Editing an existing user +------------------------ + +To edit an existing user, simply click the pencil icon to the right of that +user in the :guilabel:`Users` page. You can then edit their global- and +database-specific privileges, change their password, or even copy those +privileges to a new user. + +Deleting a user +--------------- + +From the :guilabel:`Users` page, check the checkbox for the user you wish to +remove, select whether or not to also remove any databases of the same name (if +they exist), and click Go. + +Assigning privileges to user for a specific database +---------------------------------------------------- + +Users are assigned to databases by editing the user record (from the +:guilabel:`Users` link on the home page) not from within the :guilabel:`Users` +link under the table. If you are creating a user specifically for a given table +you will have to create the user first (with no global privileges) and then go +back and edit that user to add the table and privileges for the individual +table. diff --git a/phpMyAdmin/doc/require.rst b/phpMyAdmin/doc/require.rst new file mode 100644 index 0000000..4582d72 --- /dev/null +++ b/phpMyAdmin/doc/require.rst @@ -0,0 +1,53 @@ +.. _require: + +Requirements +============ + +Web server +---------- + +Since, phpMyAdmin's interface is based entirely in your browser, you'll need a +web server (such as Apache, :term:`IIS`) to install phpMyAdmin's files into. + +PHP +--- + +* You need PHP 5.3.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. + +* You need GD2 support in PHP to display inline thumbnails of JPEGs + ("image/jpeg: inline") with their original aspect ratio. + +* When using the cookie authentication (the default), the `mcrypt + `_ extension is strongly suggested for most + users and is **required** for 64–bit machines. Not using mcrypt will + cause phpMyAdmin to load pages significantly slower. + +* To support upload progress bars, see :ref:`faq2_9`. + +* To support XML and Open Document Spreadsheet importing, you need the + `libxml `_ extension. + +* Performance suggestion: install the ``ctype`` extension. + +.. seealso:: :ref:`faq1_31`, :ref:`authentication_modes` + +Database +-------- + +phpMyAdmin supports MySQL-compatible databases. + +* MySQL 5.5 or newer +* MariaDB 5.5 or newer +* Drizzle + +.. seealso:: :ref:`faq1_17` + +Web browser +----------- + +To access phpMyAdmin you need a web browser with cookies and javascript +enabled. + diff --git a/phpMyAdmin/doc/setup.rst b/phpMyAdmin/doc/setup.rst new file mode 100644 index 0000000..783cffd --- /dev/null +++ b/phpMyAdmin/doc/setup.rst @@ -0,0 +1,493 @@ +.. _setup: + +Installation +============ + +phpMyAdmin does not apply any special security methods to the MySQL +database server. It is still the system administrator's job to grant +permissions on the MySQL databases properly. phpMyAdmin's :guilabel:`Users` +page can be used for this. + +.. warning:: + + :term:`Mac` users should note that if you are on a version before + :term:`Mac OS X`, StuffIt unstuffs with :term:`Mac` formats. So you'll have + to resave as in BBEdit to Unix style ALL phpMyAdmin scripts before + uploading them to your server, as PHP seems not to like :term:`Mac`-style + end of lines character ("``\r``"). + +Linux distributions ++++++++++++++++++++ + +phpMyAdmin is included in most Linux distributions. It is recommended to use +distribution packages when possible - they usually provide integration to your +distribution and you will automatically get security updates from your distribution. + + +Debian +------ + +Debian's package repositories include a phpMyAdmin package, but be aware that +the configuration file is maintained in ``/etc/phpmyadmin`` and may differ in +some ways from the official phpMyAdmin documentation. + +OpenSUSE +-------- + +OpenSUSE already comes with phpMyAdmin package, just install packages from +the `openSUSE Build Service `_. + +Ubuntu +------ + +Ubuntu ships phpMyAdmin package, however if you want to use recent version, you +can use packages from +`PPA for Michal Čihař `_. + +Gentoo +------ + +Gentoo ships the phpMyAdmin package, both in a near stock configuration as well +as in a ``webapp-config`` configuration. Use ``emerge dev-db/phpmyadmin`` to +install. + +Mandriva +-------- + +Mandriva ships the phpMyAdmin package in their ``contrib`` branch and can be +installed via the usual Control Center. + +Fedora +------ + +Fedora ships the phpMyAdmin package, but be aware that the configuration file +is maintained in ``/etc/phpMyAdmin/`` and may differ in some ways from the +official phpMyAdmin documentation. + +Red Hat Enterprise Linux +------------------------ + +Red Hat Enterprise Linux itself and thus derivatives like CentOS don't +ship phpMyAdmin, but the Fedora-driven repository +`Extra Packages for Enterprise Linux (EPEL) `_ +is doing so, if it's +`enabled `_. +But be aware that the configuration file is maintained in +``/etc/phpMyAdmin/`` and may differ in some ways from the +official phpMyAdmin documentation. + + +Installing on Windows ++++++++++++++++++++++ + +The easiest way to get phpMyAdmin on Windows is using third party products +which include phpMyAdmin together with a database and web server such as +`XAMPP `_. + +You can find more of such options at `Wikipedia `_. + + +.. _quick_install: + +Quick Install ++++++++++++++ + +#. Choose an appropriate distribution kit from the phpmyadmin.net + Downloads page. Some kits contain only the English messages, others + contain all languages. We'll assume you chose a kit whose name + looks like ``phpMyAdmin-x.x.x -all-languages.tar.gz``. +#. Untar or unzip the distribution (be sure to unzip the subdirectories): + ``tar -xzvf phpMyAdmin_x.x.x-all-languages.tar.gz`` in your + webserver's document root. If you don't have direct access to your + document root, put the files in a directory on your local machine, + and, after step 4, transfer the directory on your web server using, + for example, ftp. +#. Ensure that all the scripts have the appropriate owner (if PHP is + running in safe mode, having some scripts with an owner different from + the owner of other scripts will be a problem). See :ref:`faq4_2` and + :ref:`faq1_26` for suggestions. +#. Now you must configure your installation. There are two methods that + can be used. Traditionally, users have hand-edited a copy of + :file:`config.inc.php`, but now a wizard-style setup script is provided + for those who prefer a graphical installation. Creating a + :file:`config.inc.php` is still a quick way to get started and needed for + some advanced features. + + +Manually creating the file +-------------------------- + +To manually create the file, simply use your text editor to create the +file :file:`config.inc.php` (you can copy :file:`config.sample.inc.php` to get +minimal configuration file) in the main (top-level) phpMyAdmin +directory (the one that contains :file:`index.php`). phpMyAdmin first +loads :file:`libraries/config.default.php` and then overrides those values +with anything found in :file:`config.inc.php`. If the default value is +okay for a particular setting, there is no need to include it in +:file:`config.inc.php`. You'll need a few directives to get going, a +simple configuration may look like this: + +.. code-block:: xml+php + + + + +Or, if you prefer to not be prompted every time you log in: + +.. code-block:: xml+php + + + + +For a full explanation of possible configuration values, see the +:ref:`config` of this document. + +.. index:: Setup script + +.. _setup_script: + +Using Setup script +------------------ + +Instead of manually editing :file:`config.inc.php`, you can use the `Setup +Script `_. First you must manually create a folder ``config`` +in the phpMyAdmin directory. This is a security measure. On a +Linux/Unix system you can use the following commands: + +.. code-block:: sh + + + cd phpMyAdmin + mkdir config # create directory for saving + chmod o+rw config # give it world writable permissions + +And to edit an existing configuration, copy it over first: + +.. code-block:: sh + + + cp config.inc.php config/ # copy current configuration for editing + chmod o+w config/config.inc.php # give it world writable permissions + +On other platforms, simply create the folder and ensure that your web +server has read and write access to it. :ref:`faq1_26` can help with +this. + +Next, open ``setup/`` in your browser. If you have an existing configuration, +use the ``Load`` button to bring its content inside the setup panel. +Note that **changes are not saved to disk until explicitly choose ``Save``** +from the *Configuration* area of the screen. Normally the script saves the new +:file:`config.inc.php` to the ``config/`` directory, but if the webserver does +not have the proper permissions you may see the error "Cannot load or +save configuration." Ensure that the ``config/`` directory exists and +has the proper permissions - or use the ``Download`` link to save the +config file locally and upload it (via FTP or some similar means) to the +proper location. + +Once the file has been saved, it must be moved out of the ``config/`` +directory and the permissions must be reset, again as a security +measure: + +.. code-block:: sh + + + mv config/config.inc.php . # move file to current directory + chmod o-rw config.inc.php # remove world read and write permissions + rm -rf config # remove not needed directory + +Now the file is ready to be used. You can choose to review or edit the +file with your favorite editor, if you prefer to set some advanced +options which the setup script does not provide. + +#. If you are using the ``auth_type`` "config", it is suggested that you + protect the phpMyAdmin installation directory because using config + does not require a user to enter a password to access the phpMyAdmin + installation. Use of an alternate authentication method is + recommended, for example with HTTP–AUTH in a :term:`.htaccess` file or switch to using + ``auth_type`` cookie or http. See the :ref:`faqmultiuser` + for additional information, especially :ref:`faq4_4`. +#. Open the `main phpMyAdmin directory `_ in your browser. + phpMyAdmin should now display a welcome screen and your databases, or + a login dialog if using :term:`HTTP` or + cookie authentication mode. +#. You should deny access to the ``./libraries`` and ``./setup/lib`` + subfolders in your webserver configuration. For Apache you can use + supplied :term:`.htaccess` file in that folder, for other webservers, you should + configure this yourself. Such configuration prevents from possible + path exposure and cross side scripting vulnerabilities that might + happen to be found in that code. +#. It is generally good idea to protect public phpMyAdmin installation + against access by robots as they usually can not do anything good + there. You can do this using ``robots.txt`` file in root of your + webserver or limit access by web server configuration, see + :ref:`faq1_42`. + +.. index:: + single: Configuration storage + single: phpMyAdmin configuration storage + single: pmadb + +.. _linked-tables: + +phpMyAdmin configuration storage +++++++++++++++++++++++++++++++++ + +For a whole set of new features (bookmarks, comments, :term:`SQL`-history, +tracking mechanism, :term:`PDF`-generation, column contents transformation, +etc.) you need to create a set of special tables. Those tables can be located +in your own database, or in a central database for a multi-user installation +(this database would then be accessed by the controluser, so no other user +should have rights to it). + +Please look at your ``./examples/`` directory, where you should find a +file called *create\_tables.sql*. (If you are using a Windows server, +pay special attention to :ref:`faq1_23`). + +If you already had this infrastructure and upgraded to MySQL 4.1.2 or +newer, please use :file:`examples/upgrade_tables_mysql_4_1_2+.sql` +and then create new tables by importing +:file:`examples/create_tables.sql`. + +You can use your phpMyAdmin to create the tables for you. Please be +aware that you may need special (administrator) privileges to create +the database and tables, and that the script may need some tuning, +depending on the database name. + +After having imported the :file:`examples/create_tables.sql` file, you +should specify the table names in your :file:`config.inc.php` file. The +directives used for that can be found in the :ref:`config`. You will also need to +have a controluser with the proper rights to those tables (see section +:ref:`authentication_modes` below). + +.. _upgrading: + +Upgrading from an older version ++++++++++++++++++++++++++++++++ + +Simply copy :file:`config.inc.php` from your previous installation into +the newly unpacked one. Configuration files from old versions may +require some tweaking as some options have been changed or removed. +For compatibility with PHP 6, remove a +``set_magic_quotes_runtime(0);`` statement that you might find near +the end of your configuration file. + +You should **not** copy :file:`libraries/config.default.php` over +:file:`config.inc.php` because the default configuration file is version- +specific. + +If you have upgraded your MySQL server from a version previous to 4.1.2 to +version 5.x or newer and if you use the phpMyAdmin configuration storage, you +should run the :term:`SQL` script found in +:file:`examples/upgrade_tables_mysql_4_1_2+.sql`. + +.. index:: Authentication mode + +.. _authentication_modes: + +Using authentication modes +++++++++++++++++++++++++++ + +:term:`HTTP` and cookie authentication modes are recommended in a **multi-user +environment** where you want to give users access to their own database and +don't want them to play around with others. Nevertheless be aware that MS +Internet Explorer seems to be really buggy about cookies, at least till version +6. Even in a **single-user environment**, you might prefer to use :term:`HTTP` +or cookie mode so that your user/password pair are not in clear in the +configuration file. + +:term:`HTTP` and cookie authentication +modes are more secure: the MySQL login information does not need to be +set in the phpMyAdmin configuration file (except possibly for the +:config:option:`$cfg['Servers'][$i]['controluser']`). +However, keep in mind that the password travels in plain text, unless +you are using the HTTPS protocol. In cookie mode, the password is +stored, encrypted with the blowfish algorithm, in a temporary cookie. + +.. note: + + This section is only applicable if your MySQL server is running + with ``--skip-show-database``. + +For ':term:`HTTP`' and 'cookie' modes, phpMyAdmin needs a controluser that has +**only** the ``SELECT`` privilege on the *`mysql`.`user` (all columns except +`Password`)*, *`mysql`.`db` (all columns)*, *`mysql`.`host` (all columns)* and +*`mysql`.`tables\_priv` (all columns except `Grantor` and `Timestamp`)* tables. +You must specify the details for the controluser in the :file:`config.inc.php` +file under the :config:option:`$cfg['Servers'][$i]['controluser']` and +:config:option:`$cfg['Servers'][$i]['controlpass']` settings. The following +example assumes you want to use ``pma`` as the controluser and ``pmapass`` as +the controlpass, but **this is only an example: use something else in your +file!** Input these statements from the phpMyAdmin :term:`SQL` Query window or +mysql command–line client. Of course you have to replace ``localhost`` with the +webserver's host if it's not the same as the MySQL server's one. + +.. code-block:: mysql + + GRANT USAGE ON mysql.* TO 'pma'@'localhost' IDENTIFIED BY 'pmapass'; + GRANT SELECT ( + Host, User, Select_priv, Insert_priv, Update_priv, Delete_priv, + Create_priv, Drop_priv, Reload_priv, Shutdown_priv, Process_priv, + File_priv, Grant_priv, References_priv, Index_priv, Alter_priv, + Show_db_priv, Super_priv, Create_tmp_table_priv, Lock_tables_priv, + Execute_priv, Repl_slave_priv, Repl_client_priv + ) ON mysql.user TO 'pma'@'localhost'; + GRANT SELECT ON mysql.db TO 'pma'@'localhost'; + GRANT SELECT ON mysql.host TO 'pma'@'localhost'; + GRANT SELECT (Host, Db, User, Table_name, Table_priv, Column_priv) + ON mysql.tables_priv TO 'pma'@'localhost'; + +If you want to use the many new relation and bookmark features: + +.. code-block:: mysql + + GRANT SELECT, INSERT, UPDATE, DELETE ON .* TO 'pma'@'localhost'; + +(this of course requires that your :ref:`linked-tables` be set up). + +Then each of the *true* users should be granted a set of privileges +on a set of particular databases. Normally you shouldn't give global +privileges to an ordinary user, unless you understand the impact of those +privileges (for example, you are creating a superuser). +For example, to grant the user *real_user* with all privileges on +the database *user_base*: + +.. code-block:: mysql + + GRANT ALL PRIVILEGES ON user_base.* TO 'real_user'@localhost IDENTIFIED BY 'real_password'; + + +What the user may now do is controlled entirely by the MySQL user management +system. With HTTP or cookie authentication mode, you don't need to fill the +user/password fields inside the :config:option:`$cfg['Servers']`. + +.. index:: pair: HTTP; Authentication mode + +HTTP authentication mode +------------------------ + +* Uses :term:`HTTP` Basic authentication + method and allows you to log in as any valid MySQL user. +* Is supported with most PHP configurations. For :term:`IIS` (:term:`ISAPI`) + support using :term:`CGI` PHP see :ref:`faq1_32`, for using with Apache + :term:`CGI` see :ref:`faq1_35`. +* See also :ref:`faq4_4` about not using the :term:`.htaccess` mechanism along with + ':term:`HTTP`' authentication mode. + +.. index:: pair: Cookie; Authentication mode + +.. _cookie: + +Cookie authentication mode +-------------------------- + +* You can use this method as a replacement for the :term:`HTTP` authentication + (for example, if you're running :term:`IIS`). +* Obviously, the user must enable cookies in the browser, but this is + now a requirement for all authentication modes. +* With this mode, the user can truly log out of phpMyAdmin and log in + back with the same username. +* If you want to log in to arbitrary server see :config:option:`$cfg['AllowArbitraryServer']` directive. +* As mentioned in the :ref:`require` section, having the ``mcrypt`` extension will + speed up access considerably, but is not required. + +.. index:: pair: Signon; Authentication mode + +Signon authentication mode +-------------------------- + +* This mode is a convenient way of using credentials from another + application to authenticate to phpMyAdmin. +* The other application has to store login information into session + data. + +.. seealso:: + :config:option:`$cfg['Servers'][$i]['auth_type']`, + :config:option:`$cfg['Servers'][$i]['SignonSession']`, + :config:option:`$cfg['Servers'][$i]['SignonScript']`, + :config:option:`$cfg['Servers'][$i]['SignonURL']` + + +.. index:: pair: Config; Authentication mode + +Config authentication mode +-------------------------- + +* This mode is the less secure one because it requires you to fill the + :config:option:`$cfg['Servers'][$i]['user']` and + :config:option:`$cfg['Servers'][$i]['password']` + fields (and as a result, anyone who can read your :file:`config.inc.php` + can discover your username and password). But you don't need to setup + a "controluser" here: using the :config:option:`$cfg['Servers'][$i]['only_db']` might be enough. +* In the :ref:`faqmultiuser` section, there is an entry explaining how + to protect your configuration file. +* For additional security in this mode, you may wish to consider the + Host authentication :config:option:`$cfg['Servers'][$i]['AllowDeny']['order']` + and :config:option:`$cfg['Servers'][$i]['AllowDeny']['rules']` configuration directives. +* Unlike cookie and http, does not require a user to log in when first + loading the phpMyAdmin site. This is by design but could allow any + user to access your installation. Use of some restriction method is + suggested, perhaps a :term:`.htaccess` file with the HTTP-AUTH directive or disallowing + incoming HTTP requests at one’s router or firewall will suffice (both + of which are beyond the scope of this manual but easily searchable + with Google). + +.. index:: pair: Swekey; Authentication mode + +.. _swekey: + +Swekey authentication mode +-------------------------- + +The Swekey is a low cost authentication USB key that can be used in +web applications. When Swekey authentication is activated, phpMyAdmin +requires the users's Swekey to be plugged before entering the login +page (currently supported for cookie authentication mode only). Swekey +Authentication is disabled by default. To enable it, add the following +line to :file:`config.inc.php`: + +.. code-block:: php + + $cfg['Servers'][$i]['auth_swekey_config'] = '/etc/swekey.conf'; + +You then have to create the ``swekey.conf`` file that will associate +each user with their Swekey Id. It is important to place this file +outside of your web server's document root (in the example, it is +located in ``/etc``). A self documented sample file is provided in the +``examples`` directory. Feel free to use it with your own users' +information. If you want to purchase a Swekey please visit +`http://phpmyadmin.net/auth\_key `_ +since this link provides funding for phpMyAdmin. + +.. seealso:: :config:option:`$cfg['Servers'][$i]['auth_swekey_config']` + + +Securing your phpMyAdmin installation ++++++++++++++++++++++++++++++++++++++ + +The phpMyAdmin team tries hardly to make the application secure, however there +are always ways to make your installation more secure: + +* remove ``setup`` directory from phpMyAdmin, you will probably not + use it after initial setup +* properly choose authentication method - :ref:`cookie` + is probably the best choice for shared hosting +* in case you don't want all MySQL users to be able to access + phpMyAdmin, you can use :config:option:`$cfg['Servers'][$i]['AllowDeny']['rules']` to limit them +* consider hiding phpMyAdmin behind authentication proxy, so that + MySQL credentials are not all users need to login +* if you are afraid of automated attacks, enabling Captcha by + :config:option:`$cfg['CaptchaLoginPublicKey']` and + :config:option:`$cfg['CaptchaLoginPrivateKey']` might be an option. diff --git a/phpMyAdmin/doc/transformations.rst b/phpMyAdmin/doc/transformations.rst new file mode 100644 index 0000000..4c3ce46 --- /dev/null +++ b/phpMyAdmin/doc/transformations.rst @@ -0,0 +1,138 @@ +.. _transformations: + +Transformations +=============== + +.. _transformationsintro: + +Introduction +++++++++++++ + +To enable transformations, you have to setup the ``column_info`` +table and the proper directives. Please see the :ref:`config` on how to do so. + +You can apply different transformations to the contents of each +column. The transformation will take the content of each column and +transform it with certain rules defined in the selected +transformation. + +Say you have a column 'filename' which contains a filename. Normally +you would see in phpMyAdmin only this filename. Using transformations +you can transform that filename into a HTML link, so you can click +inside of the phpMyAdmin structure on the column's link and will see +the file displayed in a new browser window. Using transformation +options you can also specify strings to append/prepend to a string or +the format you want the output stored in. + +For a general overview of all available transformations and their +options, you can consult your *//transformation\_overview.php* installation. + +For a tutorial on how to effectively use transformations, see our +`Link section `_ on the +official phpMyAdmin homepage. + +.. _transformationshowto: + +Usage ++++++ + +Go to your *tbl\_structure.php* page (i.e. reached through clicking on +the 'Structure' link for a table). There click on "Change" (or change +icon) and there you will see three new fields at the end of the line. +They are called 'MIME-type', 'Browser transformation' and +'Transformation options'. + +* The field 'MIME-type' is a drop-down field. Select the MIME-type that + corresponds to the column's contents. Please note that transformations + are inactive as long as no MIME-type is selected. +* The field 'Browser transformation' is a drop-down field. You can + choose from a hopefully growing amount of pre-defined transformations. + See below for information on how to build your own transformation. + There are global transformations and mimetype-bound transformations. + Global transformations can be used for any mimetype. They will take + the mimetype, if necessary, into regard. Mimetype-bound + transformations usually only operate on a certain mimetype. There are + transformations which operate on the main mimetype (like 'image'), + which will most likely take the subtype into regard, and those who + only operate on a specific subtype (like 'image/jpeg'). You can use + transformations on mimetypes for which the function was not defined + for. There is no security check for you selected the right + transformation, so take care of what the output will be like. +* The field 'Transformation options' is a free-type textfield. You have + to enter transform-function specific options here. Usually the + transforms can operate with default options, but it is generally a + good idea to look up the overview to see which options are necessary. + Much like the ENUM/SET-Fields, you have to split up several options + using the format 'a','b','c',...(NOTE THE MISSING BLANKS). This is + because internally the options will be parsed as an array, leaving the + first value the first element in the array, and so forth. If you want + to specify a MIME character set you can define it in the + transformation\_options. You have to put that outside of the pre- + defined options of the specific mime-transform, as the last value of + the set. Use the format "'; charset=XXX'". If you use a transform, for + which you can specify 2 options and you want to append a character + set, enter "'first parameter','second parameter','charset=us-ascii'". + You can, however use the defaults for the parameters: "'','','charset + =us-ascii'". + +.. _transformationsfiles: + +File structure +++++++++++++++ + +All specific transformations for mimetypes are defined through class +files in the directory 'libraries/plugins/transformations/'. Each of +them extends a certain transformation abstract class declared in +libraries/plugins/transformations/abstract. + +They are stored in files to ease up customization and easy adding of +new transformations. + +Because the user cannot enter own mimetypes, it is kept sure that +transformations always work. It makes no sense to apply a +transformation to a mimetype the transform-function doesn't know to +handle. + +There is a file called '*transformations.lib.php*' that provides some +basic functions which can be included by any other transform function. + +The file name convention is ``[Mimetype]_[Subtype]_[Transformation +Name].class.php``, while the abtract class that it extends has the +name ``[Transformation Name]TransformationsPlugin``. All of the +methods that have to be implemented by a transformations plug-in are: + +#. getMIMEType() and getMIMESubtype() in the main class; +#. getName(), getInfo() and applyTransformation() in the abstract class + it extends. + +The getMIMEType(), getMIMESubtype() and getName() methods return the +name of the MIME type, MIME Subtype and transformation accordingly. +getInfo() returns the transformation's description and possible +options it may receive and applyTransformation() is the method that +does the actual work of the transformation plug-in. + +Please see the libraries/plugins/transformations/TEMPLATE and +libraries/plugins/transformations/TEMPLATE\_ABSTRACT files for adding +your own transformation plug-in. You can also generate a new +transformation plug-in (with or without the abstract transformation +class), by using +:file:`libraries/plugins/transformations/generator_plugin.sh` or +:file:`libraries/plugins/transformations/generator_main_class.sh`. + +The applyTransformation() method always gets passed three variables: + +#. **$buffer** - Contains the text inside of the column. This is the + text, you want to transform. +#. **$options** - Contains any user-passed options to a transform + function as an array. +#. **$meta** - Contains an object with information about your column. The + data is drawn from the output of the `mysql\_fetch\_field() + `_ function. This means, all + object properties described on the `manual page + `_ are available in this + variable and can be used to transform a column accordingly to + unsigned/zerofill/not\_null/... properties. The $meta->mimetype + variable contains the original MIME-type of the column (i.e. + 'text/plain', 'image/jpeg' etc.) + diff --git a/phpMyAdmin/doc/user.rst b/phpMyAdmin/doc/user.rst new file mode 100644 index 0000000..ceaf723 --- /dev/null +++ b/phpMyAdmin/doc/user.rst @@ -0,0 +1,9 @@ +User Guide +========== + +.. toctree:: + :maxdepth: 2 + + transformations + privileges + other diff --git a/phpMyAdmin/doc/vendors.rst b/phpMyAdmin/doc/vendors.rst new file mode 100644 index 0000000..13d7e55 --- /dev/null +++ b/phpMyAdmin/doc/vendors.rst @@ -0,0 +1,34 @@ +Distributing and packaging phpMyAdmin +===================================== + +This document is intended to give advices to people who want to +redistribute phpMyAdmin inside other software package such as Linux +distribution or some all in one package including web server and MySQL +server. + +Generally you can customize some basic aspects (paths to some files and +behavior) in :file:`libraries/vendor_config.php`. + +For example if you want setup script to generate config file in var, change +``SETUP_CONFIG_FILE`` to :file:`/var/lib/phpmyadmin/config.inc.php` and you +will also probably want to skip directory writable check, so set +``SETUP_DIR_WRITABLE`` to false. + +External libraries +------------------ + +phpMyAdmin includes several external libraries, you might want to +replace them with system ones if they are available, but please note +that you should test whether version you provide is compatible with the +one we ship. + +Currently known list of external libraries: + +js/jquery + jQuery js framework and various jQuery based libraries. + +libraries/php-gettext + php-gettext library +libraries/tcpdf + tcpdf library, stripped down of not needed files + diff --git a/phpMyAdmin/error_report.php b/phpMyAdmin/error_report.php new file mode 100644 index 0000000..3ed045b --- /dev/null +++ b/phpMyAdmin/error_report.php @@ -0,0 +1,95 @@ +addJSON( + 'message', + PMA_Message::error( + __( + 'An error has been detected and an error report has been ' + .'automatically submitted based on your settings.' + ) + . '
' + . __('You may want to refresh the page.') + ) + ); + } else { + $response->addJSON( + 'message', + PMA_Message::error( + __( + 'An error has been detected and an error report has been ' + . 'generated but failed to be sent.' + ) + . ' ' + . __( + 'If you experience any ' + . 'problems please submit a bug report manually.' + ) + . '
' + . __('You may want to refresh the page.') + ) + ); + } + } else { + if ($success) { + $response->addJSON( + 'message', + PMA_Message::success( + __('Thank you for submitting this report.') + . '
' + . __('You may want to refresh the page.') + ) + ); + } else { + $response->addJSON( + 'message', + PMA_Message::error( + __('Thank you for submitting this report.') + . ' ' + . __('Unfortunately the submission failed.') + . ' ' + . __( + 'If you experience any ' + . 'problems please submit a bug report manually.' + ) + . '
' + . __('You may want to refresh the page.') + ) + ); + } + if (isset($_REQUEST['always_send']) + && $_REQUEST['always_send'] === "true" + ) { + PMA_persistOption("SendErrorReports", "always", "ask"); + } + } +} elseif (! empty($_REQUEST['get_settings'])) { + $response->addJSON('report_setting', $GLOBALS['cfg']['SendErrorReports']); +} else { + $response->addHTML(PMA_getErrorReportForm()); +} diff --git a/phpMyAdmin/examples/config.manyhosts.inc.php b/phpMyAdmin/examples/config.manyhosts.inc.php index d006cde..3ab6572 100644 --- a/phpMyAdmin/examples/config.manyhosts.inc.php +++ b/phpMyAdmin/examples/config.manyhosts.inc.php @@ -1,43 +1,51 @@ -' . "\n"; ?> - - - + + + + phpMyAdmin OpenID signon example - - -' . $_SESSION['PMA_single_signon_message'] . '

'; - unset($_SESSION['PMA_single_signon_message']); -} -echo $contents; -?> - - - + + ' . $_SESSION['PMA_single_signon_message'] . '

'; + unset($_SESSION['PMA_single_signon_message']); + } + echo $contents; + ?> + + + '; - show_page($content); + Show_page($content); exit; } @@ -109,7 +113,7 @@ function show_page($contents) $contents = "
\n"; $contents .= "
" . $e->getMessage() . "
\n"; $contents .= "
"; - show_page($contents); + Show_page($contents); exit; } @@ -121,7 +125,7 @@ function show_page($contents) $contents = "
\n"; $contents .= "
" . $e->getMessage() . "
\n"; $contents .= "
"; - show_page($contents); + Show_page($contents); exit; } @@ -150,7 +154,7 @@ function show_page($contents) /* Redirect to phpMyAdmin (should use absolute URL here!) */ header('Location: ../index.php'); } else { - show_page('

User not allowed!

'); + Show_page('

User not allowed!

'); exit; } } diff --git a/phpMyAdmin/examples/signon-script.php b/phpMyAdmin/examples/signon-script.php index 52777a0..e333f2e 100644 --- a/phpMyAdmin/examples/signon-script.php +++ b/phpMyAdmin/examples/signon-script.php @@ -7,7 +7,7 @@ * phpMyAdmin, it is not intended to be perfect code and look, only * shows how you can integrate this functionality in your application. * - * @package PhpMyAdmin + * @package PhpMyAdmin * @subpackage Example */ @@ -17,7 +17,8 @@ * * It can optionally use configured username as parameter. * - * @param string $user + * @param string $user User name + * * @return array */ function get_login_credentials($user) diff --git a/phpMyAdmin/examples/signon.php b/phpMyAdmin/examples/signon.php index 0dfd356..57e989d 100644 --- a/phpMyAdmin/examples/signon.php +++ b/phpMyAdmin/examples/signon.php @@ -7,7 +7,7 @@ * phpMyAdmin, it is not intended to be perfect code and look, only * shows how you can integrate this functionality in your application. * - * @package PhpMyAdmin + * @package PhpMyAdmin * @subpackage Example */ @@ -37,29 +37,33 @@ header('Content-Type: text/html; charset=utf-8'); echo '' . "\n"; ?> - - - + + + + phpMyAdmin single signon example - - -' . $_SESSION['PMA_single_signon_error_message'] . '

'; -} -?> -
-Username:
-Password:
-Host: (will use the one from config.inc.php by default)
-Port: (will use the one from config.inc.php by default)
- -
- - - + + '; + echo $_SESSION['PMA_single_signon_error_message']; + echo '

'; + } + ?> +
+ Username:
+ Password:
+ Host: (will use the one from config.inc.php by default) +
+ Port: (will use the one from config.inc.php by default) +
+ +
+ + + diff --git a/phpMyAdmin/examples/upgrade_tables_mysql_4_1_2+.sql b/phpMyAdmin/examples/upgrade_tables_mysql_4_1_2+.sql index 905bd68..df4046a 100644 --- a/phpMyAdmin/examples/upgrade_tables_mysql_4_1_2+.sql +++ b/phpMyAdmin/examples/upgrade_tables_mysql_4_1_2+.sql @@ -23,122 +23,122 @@ USE phpmyadmin; -- -------------------------------------------------------- -- --- Table structure for table `pma_bookmark` +-- Table structure for table `pma__bookmark` -- -ALTER TABLE `pma_bookmark` +ALTER TABLE `pma__bookmark` DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; -ALTER TABLE `pma_bookmark` +ALTER TABLE `pma__bookmark` CHANGE `dbase` `dbase` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; -ALTER TABLE `pma_bookmark` +ALTER TABLE `pma__bookmark` CHANGE `user` `user` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; -ALTER TABLE `pma_bookmark` +ALTER TABLE `pma__bookmark` CHANGE `label` `label` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ''; -ALTER TABLE `pma_bookmark` +ALTER TABLE `pma__bookmark` CHANGE `query` `query` TEXT CHARACTER SET utf8 COLLATE utf8_bin NOT NULL; -- -------------------------------------------------------- -- --- Table structure for table `pma_column_info` +-- Table structure for table `pma__column_info` -- -ALTER TABLE `pma_column_info` +ALTER TABLE `pma__column_info` DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; -ALTER TABLE `pma_column_info` +ALTER TABLE `pma__column_info` CHANGE `db_name` `db_name` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; -ALTER TABLE `pma_column_info` +ALTER TABLE `pma__column_info` CHANGE `table_name` `table_name` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; -ALTER TABLE `pma_column_info` +ALTER TABLE `pma__column_info` CHANGE `column_name` `column_name` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; -ALTER TABLE `pma_column_info` +ALTER TABLE `pma__column_info` CHANGE `comment` `comment` VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ''; -ALTER TABLE `pma_column_info` +ALTER TABLE `pma__column_info` CHANGE `mimetype` `mimetype` VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ''; -ALTER TABLE `pma_column_info` +ALTER TABLE `pma__column_info` CHANGE `transformation` `transformation` VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; -ALTER TABLE `pma_column_info` +ALTER TABLE `pma__column_info` CHANGE `transformation_options` `transformation_options` VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; -- -------------------------------------------------------- -- --- Table structure for table `pma_history` +-- Table structure for table `pma__history` -- -ALTER TABLE `pma_history` +ALTER TABLE `pma__history` DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; -ALTER TABLE `pma_history` +ALTER TABLE `pma__history` CHANGE `username` `username` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; -ALTER TABLE `pma_history` +ALTER TABLE `pma__history` CHANGE `db` `db` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; -ALTER TABLE `pma_history` +ALTER TABLE `pma__history` CHANGE `table` `table` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; -ALTER TABLE `pma_history` +ALTER TABLE `pma__history` CHANGE `sqlquery` `sqlquery` TEXT CHARACTER SET utf8 COLLATE utf8_bin NOT NULL; -- -------------------------------------------------------- -- --- Table structure for table `pma_pdf_pages` +-- Table structure for table `pma__pdf_pages` -- -ALTER TABLE `pma_pdf_pages` +ALTER TABLE `pma__pdf_pages` DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; -ALTER TABLE `pma_pdf_pages` +ALTER TABLE `pma__pdf_pages` CHANGE `db_name` `db_name` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; -ALTER TABLE `pma_pdf_pages` +ALTER TABLE `pma__pdf_pages` CHANGE `page_descr` `page_descr` VARCHAR(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL default ''; -- -------------------------------------------------------- -- --- Table structure for table `pma_relation` +-- Table structure for table `pma__relation` -- -ALTER TABLE `pma_relation` +ALTER TABLE `pma__relation` DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; -ALTER TABLE `pma_relation` +ALTER TABLE `pma__relation` CHANGE `master_db` `master_db` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; -ALTER TABLE `pma_relation` +ALTER TABLE `pma__relation` CHANGE `master_table` `master_table` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; -ALTER TABLE `pma_relation` +ALTER TABLE `pma__relation` CHANGE `master_field` `master_field` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; -ALTER TABLE `pma_relation` +ALTER TABLE `pma__relation` CHANGE `foreign_db` `foreign_db` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; -ALTER TABLE `pma_relation` +ALTER TABLE `pma__relation` CHANGE `foreign_table` `foreign_table` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; -ALTER TABLE `pma_relation` +ALTER TABLE `pma__relation` CHANGE `foreign_field` `foreign_field` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; -- -------------------------------------------------------- -- --- Table structure for table `pma_table_coords` +-- Table structure for table `pma__table_coords` -- -ALTER TABLE `pma_table_coords` +ALTER TABLE `pma__table_coords` DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; -ALTER TABLE `pma_table_coords` +ALTER TABLE `pma__table_coords` CHANGE `db_name` `db_name` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; -ALTER TABLE `pma_table_coords` +ALTER TABLE `pma__table_coords` CHANGE `table_name` `table_name` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; -- -------------------------------------------------------- -- --- Table structure for table `pma_table_info` +-- Table structure for table `pma__table_info` -- -ALTER TABLE `pma_table_info` +ALTER TABLE `pma__table_info` DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; -ALTER TABLE `pma_table_info` +ALTER TABLE `pma__table_info` CHANGE `db_name` `db_name` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; -ALTER TABLE `pma_table_info` +ALTER TABLE `pma__table_info` CHANGE `table_name` `table_name` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; -ALTER TABLE `pma_table_info` +ALTER TABLE `pma__table_info` CHANGE `display_field` `display_field` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT ''; diff --git a/phpMyAdmin/export.php b/phpMyAdmin/export.php index 7036af9..d874e9e 100644 --- a/phpMyAdmin/export.php +++ b/phpMyAdmin/export.php @@ -1,136 +1,331 @@ $export_type, - 'single_table' => isset($single_table))); + foreach ($post_params as $one_post_param) { + if (isset($_POST[$one_post_param])) { + $GLOBALS[$one_post_param] = $_POST[$one_post_param]; + } + } -// Backward compatbility -$type = $what; + // sanitize this parameter which will be used below in a file inclusion + $what = PMA_securePath($what); -// Check export type -if (! isset($export_list[$type])) { - die(__('Bad type!')); -} + PMA_Util::checkParameters(array('what', 'export_type')); -/** - * valid compression methods - */ -$compression_methods = array( - 'zip', - 'gzip', - 'bzip2', -); + // export class instance, not array of properties, as before + $export_plugin = PMA_getPlugin( + "export", + $what, + 'libraries/plugins/export/', + array( + 'export_type' => $export_type, + 'single_table' => isset($single_table) + ) + ); -/** - * init and variable checking - */ -$compression = false; -$onserver = false; -$save_on_server = false; -$buffer_needed = false; - -// Is it a quick or custom export? -if ($_REQUEST['quick_or_custom'] == 'quick') { - $quick_export = true; -} else { - $quick_export = false; -} + // Backward compatbility + $type = $what; + + // Check export type + if (! isset($export_plugin)) { + PMA_fatalError(__('Bad type!')); + } + + /** + * valid compression methods + */ + $compression_methods = array( + 'zip', + 'gzip' + ); + + /** + * init and variable checking + */ + $compression = false; + $onserver = false; + $save_on_server = false; + $buffer_needed = false; -if ($_REQUEST['output_format'] == 'astext') { - $asfile = false; -} else { - $asfile = true; - if (in_array($_REQUEST['compression'], $compression_methods)) { - $compression = $_REQUEST['compression']; - $buffer_needed = true; + // Is it a quick or custom export? + if ($_REQUEST['quick_or_custom'] == 'quick') { + $quick_export = true; + } else { + $quick_export = false; + } + + if ($_REQUEST['output_format'] == 'astext') { + $asfile = false; + } else { + $asfile = true; + if (in_array($_REQUEST['compression'], $compression_methods)) { + $compression = $_REQUEST['compression']; + $buffer_needed = true; + } + if (($quick_export && ! empty($_REQUEST['quick_export_onserver'])) + || (! $quick_export && ! empty($_REQUEST['onserver'])) + ) { + if ($quick_export) { + $onserver = $_REQUEST['quick_export_onserver']; + } else { + $onserver = $_REQUEST['onserver']; + } + // Will we save dump on server? + $save_on_server = ! empty($cfg['SaveDir']) && $onserver; + } } - if (($quick_export && !empty($_REQUEST['quick_export_onserver'])) || (!$quick_export && !empty($_REQUEST['onserver']))) { - if ($quick_export) { - $onserver = $_REQUEST['quick_export_onserver']; + + // Does export require to be into file? + if ($export_plugin->getProperties()->getForceFile() != null && ! $asfile) { + $message = PMA_Message::error( + __('Selected export type has to be saved in file!') + ); + if ($export_type == 'server') { + $active_page = 'server_export.php'; + include 'server_export.php'; + } elseif ($export_type == 'database') { + $active_page = 'db_export.php'; + include 'db_export.php'; } else { - $onserver = $_REQUEST['onserver']; + $active_page = 'tbl_export.php'; + include 'tbl_export.php'; } - // Will we save dump on server? - $save_on_server = ! empty($cfg['SaveDir']) && $onserver; + exit(); } -} -// Does export require to be into file? -if (isset($export_list[$type]['force_file']) && ! $asfile) { - $message = PMA_Message::error(__('Selected export type has to be saved in file!')); - include_once './libraries/header.inc.php'; + // Generate error url and check for needed variables if ($export_type == 'server') { - $active_page = 'server_export.php'; - include './server_export.php'; - } elseif ($export_type == 'database') { - $active_page = 'db_export.php'; - include './db_export.php'; + $err_url = 'server_export.php?' . PMA_URL_getCommon(); + } elseif ($export_type == 'database' && strlen($db)) { + $err_url = 'db_export.php?' . PMA_URL_getCommon($db); + // Check if we have something to export + if (isset($table_select)) { + $tables = $table_select; + } else { + $tables = array(); + } + } elseif ($export_type == 'table' && strlen($db) && strlen($table)) { + $err_url = 'tbl_export.php?' . PMA_URL_getCommon($db, $table); } else { - $active_page = 'tbl_export.php'; - include './tbl_export.php'; + PMA_fatalError(__('Bad parameters!')); } - exit(); -} -// Generate error url and check for needed variables -if ($export_type == 'server') { - $err_url = 'server_export.php?' . PMA_generate_common_url(); -} elseif ($export_type == 'database' && strlen($db)) { - $err_url = 'db_export.php?' . PMA_generate_common_url($db); - // Check if we have something to export - if (isset($table_select)) { - $tables = $table_select; - } else { - $tables = array(); + /** + * Increase time limit for script execution and initializes some variables + */ + @set_time_limit($cfg['ExecTimeLimit']); + if (! empty($cfg['MemoryLimit'])) { + @ini_set('memory_limit', $cfg['MemoryLimit']); } -} elseif ($export_type == 'table' && strlen($db) && strlen($table)) { - $err_url = 'tbl_export.php?' . PMA_generate_common_url($db, $table); -} else { - die(__('Bad parameters!')); -} + register_shutdown_function('PMA_shutdown'); + // Start with empty buffer + $dump_buffer = ''; + $dump_buffer_len = 0; -// Get the functions specific to the export type -require './libraries/export/' . PMA_securePath($type) . '.php'; + // We send fake headers to avoid browser timeout when buffering + $time_start = time(); +} /** - * Increase time limit for script execution and initializes some variables + * Sets a session variable upon a possible fatal error during export + * + * @return void + */ +function PMA_shutdown() +{ + $a = error_get_last(); + if ($a != null && strpos($a['message'], "execution time")) { + //write in partially downloaded file for future reference of user + print_r($a); + //set session variable to check if there was error while exporting + $_SESSION['pma_export_error'] = $a['message']; + } +} +/** + * Detect ob_gzhandler + * + * @return bool */ -@set_time_limit($cfg['ExecTimeLimit']); -if (!empty($cfg['MemoryLimit'])) { - @ini_set('memory_limit', $cfg['MemoryLimit']); +function PMA_isGzHandlerEnabled() +{ + return in_array('ob_gzhandler', ob_list_handlers()); } -// Start with empty buffer -$dump_buffer = ''; -$dump_buffer_len = 0; - -// We send fake headers to avoid browser timeout when buffering -$time_start = time(); - +/** + * Detect whether gzencode is needed; it might not be needed if + * the server is already compressing by itself + * + * @return bool Whether gzencode is needed + */ +function PMA_gzencodeNeeded() +{ + /* + * We should gzencode only if the function exists + * but we don't want to compress twice, therefore + * gzencode only if transparent compression is not enabled + * and gz compression was not asked via $cfg['OBGzip'] + * but transparent compression does not apply when saving to server + */ + if (@function_exists('gzencode') + && ((! @ini_get('zlib.output_compression') + && ! PMA_isGzHandlerEnabled()) + || $GLOBALS['save_on_server']) + ) { + return true; + } else { + return false; + } +} /** * Output handler for all exports, if needed buffering, it stores data into * $dump_buffer, otherwise it prints thems out. * - * @param string $line the insert statement - * @return bool Whether output succeeded + * @param string $line the insert statement + * + * @return bool Whether output succeeded */ function PMA_exportOutputHandler($line) { @@ -138,7 +333,11 @@ function PMA_exportOutputHandler($line) // Kanji encoding convert feature if ($GLOBALS['output_kanji_conversion']) { - $line = PMA_kanji_str_conv($line, $GLOBALS['knjenc'], isset($GLOBALS['xkana']) ? $GLOBALS['xkana'] : ''); + $line = PMA_Kanji_strConv( + $line, + $GLOBALS['knjenc'], + isset($GLOBALS['xkana']) ? $GLOBALS['xkana'] : '' + ); } // If we have to buffer data, we will perform everything at once at the end if ($GLOBALS['buffer_needed']) { @@ -150,20 +349,25 @@ function PMA_exportOutputHandler($line) if ($dump_buffer_len > $GLOBALS['memory_limit']) { if ($GLOBALS['output_charset_conversion']) { - $dump_buffer = PMA_convert_string('utf-8', $GLOBALS['charset_of_file'], $dump_buffer); + $dump_buffer = PMA_convertString( + 'utf-8', + $GLOBALS['charset_of_file'], + $dump_buffer + ); } - // as bzipped - if ($GLOBALS['compression'] == 'bzip2' && @function_exists('bzcompress')) { - $dump_buffer = bzcompress($dump_buffer); - } elseif ($GLOBALS['compression'] == 'gzip' && @function_exists('gzencode')) { + if ($GLOBALS['compression'] == 'gzip' + && PMA_gzencodeNeeded() + ) { // as a gzipped file - // without the optional parameter level because it bug + // without the optional parameter level because it bugs $dump_buffer = gzencode($dump_buffer); } if ($GLOBALS['save_on_server']) { $write_result = @fwrite($GLOBALS['file_handle'], $dump_buffer); - if (!$write_result || ($write_result != strlen($dump_buffer))) { - $GLOBALS['message'] = PMA_Message::error(__('Insufficient space to save the file %s.')); + if ($write_result != strlen($dump_buffer)) { + $GLOBALS['message'] = PMA_Message::error( + __('Insufficient space to save the file %s.') + ); $GLOBALS['message']->addParam($save_filename); return false; } @@ -183,12 +387,18 @@ function PMA_exportOutputHandler($line) } else { if ($GLOBALS['asfile']) { if ($GLOBALS['output_charset_conversion']) { - $line = PMA_convert_string('utf-8', $GLOBALS['charset_of_file'], $line); + $line = PMA_convertString( + 'utf-8', + $GLOBALS['charset_of_file'], + $line + ); } if ($GLOBALS['save_on_server'] && strlen($line) > 0) { $write_result = @fwrite($GLOBALS['file_handle'], $line); - if (!$write_result || ($write_result != strlen($line))) { - $GLOBALS['message'] = PMA_Message::error(__('Insufficient space to save the file %s.')); + if (! $write_result || ($write_result != strlen($line))) { + $GLOBALS['message'] = PMA_Message::error( + __('Insufficient space to save the file %s.') + ); $GLOBALS['message']->addParam($save_filename); return false; } @@ -209,508 +419,612 @@ function PMA_exportOutputHandler($line) return true; } // end of the 'PMA_exportOutputHandler()' function -// Defines the default format. For SQL always use \n as MySQL wants this on all platforms. -if ($what == 'sql') { - $crlf = "\n"; -} else { - $crlf = PMA_whichCrlf(); -} +// Defines the default format. +// For SQL always use \n as MySQL wants this on all platforms. +if (!defined('TESTSUITE')) { + if ($what == 'sql') { + $crlf = "\n"; + } else { + $crlf = PMA_Util::whichCrlf(); + } -$output_kanji_conversion = function_exists('PMA_kanji_str_conv') && $type != 'xls'; + $output_kanji_conversion = function_exists('PMA_Kanji_strConv') + && $type != 'xls'; -// Do we need to convert charset? -$output_charset_conversion = $asfile && $GLOBALS['PMA_recoding_engine'] != PMA_CHARSET_NONE - && isset($charset_of_file) && $charset_of_file != 'utf-8' - && $type != 'xls'; + // Do we need to convert charset? + $output_charset_conversion = $asfile + && $GLOBALS['PMA_recoding_engine'] != PMA_CHARSET_NONE + && isset($charset_of_file) && $charset_of_file != 'utf-8' + && $type != 'xls'; -// Use on the fly compression? -$onfly_compression = $GLOBALS['cfg']['CompressOnFly'] && ($compression == 'gzip' || $compression == 'bzip2'); -if ($onfly_compression) { - $memory_limit = trim(@ini_get('memory_limit')); - // 2 MB as default - if (empty($memory_limit)) { - $memory_limit = 2 * 1024 * 1024; - } + // Use on the fly compression? + $onfly_compression = $GLOBALS['cfg']['CompressOnFly'] + && $compression == 'gzip'; + if ($onfly_compression) { + $memory_limit = trim(@ini_get('memory_limit')); + $memory_limit_num = (int)substr($memory_limit, 0, -1); + // 2 MB as default + if (empty($memory_limit) || '-1' == $memory_limit) { + $memory_limit = 2 * 1024 * 1024; + } elseif (strtolower(substr($memory_limit, -1)) == 'm') { + $memory_limit = $memory_limit_num * 1024 * 1024; + } elseif (strtolower(substr($memory_limit, -1)) == 'k') { + $memory_limit = $memory_limit_num * 1024; + } elseif (strtolower(substr($memory_limit, -1)) == 'g') { + $memory_limit = $memory_limit_num * 1024 * 1024 * 1024; + } else { + $memory_limit = (int)$memory_limit; + } - if (strtolower(substr($memory_limit, -1)) == 'm') { - $memory_limit = (int)substr($memory_limit, 0, -1) * 1024 * 1024; - } elseif (strtolower(substr($memory_limit, -1)) == 'k') { - $memory_limit = (int)substr($memory_limit, 0, -1) * 1024; - } elseif (strtolower(substr($memory_limit, -1)) == 'g') { - $memory_limit = (int)substr($memory_limit, 0, -1) * 1024 * 1024 * 1024; - } else { - $memory_limit = (int)$memory_limit; - } + // Some of memory is needed for other things and as threshold. + // During export I had allocated (see memory_get_usage function) + // approx 1.2MB so this comes from that. + if ($memory_limit > 1500000) { + $memory_limit -= 1500000; + } - // Some of memory is needed for other thins and as treshold. - // Nijel: During export I had allocated (see memory_get_usage function) - // approx 1.2MB so this comes from that. - if ($memory_limit > 1500000) { - $memory_limit -= 1500000; + // Some memory is needed for compression, assume 1/3 + $memory_limit /= 8; } - // Some memory is needed for compression, assume 1/3 - $memory_limit /= 8; -} - -// Generate filename and mime type if needed -if ($asfile) { - $pma_uri_parts = parse_url($cfg['PmaAbsoluteUri']); - if ($export_type == 'server') { - if (isset($remember_template)) { - $GLOBALS['PMA_Config']->setUserValue('pma_server_filename_template', - 'Export/file_template_server', $filename_template); + // Generate filename and mime type if needed + if ($asfile) { + $pma_uri_parts = parse_url($cfg['PmaAbsoluteUri']); + if ($export_type == 'server') { + if (isset($remember_template)) { + $GLOBALS['PMA_Config']->setUserValue( + 'pma_server_filename_template', + 'Export/file_template_server', + $filename_template + ); + } + } elseif ($export_type == 'database') { + if (isset($remember_template)) { + $GLOBALS['PMA_Config']->setUserValue( + 'pma_db_filename_template', + 'Export/file_template_database', + $filename_template + ); + } + } else { + if (isset($remember_template)) { + $GLOBALS['PMA_Config']->setUserValue( + 'pma_table_filename_template', + 'Export/file_template_table', + $filename_template + ); + } } - } elseif ($export_type == 'database') { - if (isset($remember_template)) { - $GLOBALS['PMA_Config']->setUserValue('pma_db_filename_template', - 'Export/file_template_database', $filename_template); + $filename = PMA_Util::expandUserString($filename_template); + // remove dots in filename (coming from either the template or already + // part of the filename) to avoid a remote code execution vulnerability + $filename = PMA_sanitizeFilename($filename, $replaceDots = true); + + // Grab basic dump extension and mime type + // Check if the user already added extension; + // get the substring where the extension would be if it was included + $extension_start_pos = strlen($filename) - strlen( + $export_plugin->getProperties()->getExtension() + ) - 1; + $user_extension = substr($filename, $extension_start_pos, strlen($filename)); + $required_extension = "." . $export_plugin->getProperties()->getExtension(); + if (strtolower($user_extension) != $required_extension) { + $filename .= $required_extension; } - } else { - if (isset($remember_template)) { - $GLOBALS['PMA_Config']->setUserValue('pma_table_filename_template', - 'Export/file_template_table', $filename_template); + $mime_type = $export_plugin->getProperties()->getMimeType(); + + // If dump is going to be compressed, set correct mime_type and add + // compression to extension + if ($compression == 'gzip') { + $filename .= '.gz'; + $mime_type = 'application/x-gzip'; + } elseif ($compression == 'zip') { + $filename .= '.zip'; + $mime_type = 'application/zip'; } } - $filename = PMA_expandUserString($filename_template); - $filename = PMA_sanitize_filename($filename); - - // Grab basic dump extension and mime type - // Check if the user already added extension; get the substring where the extension would be if it was included - $extension_start_pos = strlen($filename) - strlen($export_list[$type]['extension']) - 1; - $user_extension = substr($filename, $extension_start_pos, strlen($filename)); - $required_extension = "." . $export_list[$type]['extension']; - if (strtolower($user_extension) != $required_extension) { - $filename .= $required_extension; - } - $mime_type = $export_list[$type]['mime_type']; - - // If dump is going to be compressed, set correct mime_type and add - // compression to extension - if ($compression == 'bzip2') { - $filename .= '.bz2'; - $mime_type = 'application/x-bzip2'; - } elseif ($compression == 'gzip') { - $filename .= '.gz'; - $mime_type = 'application/x-gzip'; - } elseif ($compression == 'zip') { - $filename .= '.zip'; - $mime_type = 'application/zip'; - } -} -// Open file on server if needed -if ($save_on_server) { - $save_filename = PMA_userDir($cfg['SaveDir']) . preg_replace('@[/\\\\]@', '_', $filename); - unset($message); - if (file_exists($save_filename) && ((!$quick_export && empty($onserverover)) || ($quick_export && $_REQUEST['quick_export_onserverover'] != 'saveitover'))) { - $message = PMA_Message::error(__('File %s already exists on server, change filename or check overwrite option.')); - $message->addParam($save_filename); - } else { - if (is_file($save_filename) && !is_writable($save_filename)) { - $message = PMA_Message::error(__('The web server does not have permission to save the file %s.')); + // Open file on server if needed + if ($save_on_server) { + $save_filename = PMA_Util::userDir($cfg['SaveDir']) + . preg_replace('@[/\\\\]@', '_', $filename); + unset($message); + if (file_exists($save_filename) + && ((! $quick_export && empty($_REQUEST['onserverover'])) + || ($quick_export + && $_REQUEST['quick_export_onserverover'] != 'saveitover')) + ) { + $message = PMA_Message::error( + __( + 'File %s already exists on server, ' + . 'change filename or check overwrite option.' + ) + ); $message->addParam($save_filename); } else { - if (!$file_handle = @fopen($save_filename, 'w')) { - $message = PMA_Message::error(__('The web server does not have permission to save the file %s.')); + if (is_file($save_filename) && ! is_writable($save_filename)) { + $message = PMA_Message::error( + __( + 'The web server does not have permission ' + . 'to save the file %s.' + ) + ); $message->addParam($save_filename); + } else { + if (! $file_handle = @fopen($save_filename, 'w')) { + $message = PMA_Message::error( + __( + 'The web server does not have permission ' + . 'to save the file %s.' + ) + ); + $message->addParam($save_filename); + } } } - } - if (isset($message)) { - include_once './libraries/header.inc.php'; - if ($export_type == 'server') { - $active_page = 'server_export.php'; - include './server_export.php'; - } elseif ($export_type == 'database') { - $active_page = 'db_export.php'; - include './db_export.php'; - } else { - $active_page = 'tbl_export.php'; - include './tbl_export.php'; - } - exit(); - } -} - -/** - * Send headers depending on whether the user chose to download a dump file - * or not - */ -if (!$save_on_server) { - if ($asfile) { - // Download - // (avoid rewriting data containing HTML with anchors and forms; - // this was reported to happen under Plesk) - @ini_set('url_rewriter.tags', ''); - $filename = PMA_sanitize_filename($filename); - - PMA_download_header($filename, $mime_type); - } else { - // HTML - if ($export_type == 'database') { - $num_tables = count($tables); - if ($num_tables == 0) { - $message = PMA_Message::error(__('No tables found in database.')); - include_once './libraries/header.inc.php'; + if (isset($message)) { + if ($export_type == 'server') { + $active_page = 'server_export.php'; + include 'server_export.php'; + } elseif ($export_type == 'database') { $active_page = 'db_export.php'; - include './db_export.php'; - exit(); + include 'db_export.php'; + } else { + $active_page = 'tbl_export.php'; + include 'tbl_export.php'; } + exit(); } - $backup_cfgServer = $cfg['Server']; - include_once './libraries/header.inc.php'; - $cfg['Server'] = $backup_cfgServer; - unset($backup_cfgServer); - echo "\n" . '
' . "\n"; - //echo '
' . "\n";
+    }
 
-        /**
-         * Displays a back button with all the $_REQUEST data in the URL (store in a variable to also display after the textarea)
-         */
-         $back_button = '

[ ' . "\n"; + //echo '

' . "\n";
 
-        foreach ($_REQUEST as $name => $value) {
-            $back_button .= '&' . urlencode($name) . '=' . urlencode($value);
-        }
-        $back_button .= '&repopulate=1">Back ]

'; + /** + * Displays a back button with all the $_REQUEST data in the URL + * (store in a variable to also display after the textarea) + */ + $back_button = '

[ ' . "\n" - // remove auto-select for now: there is no way to select - // only a part of the text; anyway, it should obey - // $cfg['TextareaAutoSelect'] - //. ' ' . "\n" - . ' ' . "\n"; - echo $back_button; + if (! empty($asfile)) { + // Convert the charset if required. + if ($output_charset_conversion) { + $dump_buffer = PMA_convertString( + 'utf-8', + $GLOBALS['charset_of_file'], + $dump_buffer + ); + } - echo "\n"; - echo '

' . "\n"; - echo "\n"; -?> - - 0 + && (! $write_result || ($write_result != strlen($dump_buffer))) + ) { + $message = new PMA_Message( + __('Insufficient space to save the file %s.'), + PMA_Message::ERROR, + $save_filename + ); + } else { + $message = new PMA_Message( + __('Dump has been saved to file %s.'), + PMA_Message::SUCCESS, + $save_filename + ); + } + + if ($export_type == 'server') { + $active_page = 'server_export.php'; + include_once 'server_export.php'; + } elseif ($export_type == 'database') { + $active_page = 'db_export.php'; + include_once 'db_export.php'; + } else { + $active_page = 'tbl_export.php'; + include_once 'tbl_export.php'; + } + exit(); + } else { + echo $dump_buffer; + } + } else { + /** + * Displays the dump... + * + * Close the html tags and add the footers if dump is displayed on screen + */ + echo '' . "\n" + . ' ' . "\n"; + echo $back_button; + + echo "\n"; + echo '
' . "\n"; + echo "\n"; + ?> + + diff --git a/phpMyAdmin/file_echo.php b/phpMyAdmin/file_echo.php index d3391fc..d910b74 100644 --- a/phpMyAdmin/file_echo.php +++ b/phpMyAdmin/file_echo.php @@ -7,7 +7,8 @@ * @package PhpMyAdmin */ -require_once './libraries/common.inc.php'; +define('PMA_MINIMUM_COMMON', true); +require_once 'libraries/common.inc.php'; /* For chart exporting */ if (isset($_REQUEST['filename']) && isset($_REQUEST['image'])) { @@ -18,7 +19,7 @@ /* Check whether MIME type is allowed */ if (! isset($allowed[$_REQUEST['type']])) { - die(__('Invalid export type')); + PMA_fatalError(__('Invalid export type')); } /* @@ -49,20 +50,22 @@ } /* Send download header */ - PMA_download_header($filename, $_REQUEST['type'], strlen($data)); + PMA_downloadHeader($filename, $_REQUEST['type'], strlen($data)); /* Send data */ echo $data; -/* For monitor chart config export */ } else if (isset($_REQUEST['monitorconfig'])) { - PMA_download_header('monitor.cfg', 'application/force-download'); + /* For monitor chart config export */ + PMA_downloadHeader('monitor.cfg', 'application/force-download'); echo urldecode($_REQUEST['monitorconfig']); -/* For monitor chart config import */ } else if (isset($_REQUEST['import'])) { + /* For monitor chart config import */ header('Content-type: text/plain'); - if(!file_exists($_FILES['file']['tmp_name'])) exit(); + if (!file_exists($_FILES['file']['tmp_name'])) { + exit(); + } echo file_get_contents($_FILES['file']['tmp_name']); } ?> diff --git a/phpMyAdmin/gis_data_editor.php b/phpMyAdmin/gis_data_editor.php index 6fb2436..621dbfa 100644 --- a/phpMyAdmin/gis_data_editor.php +++ b/phpMyAdmin/gis_data_editor.php @@ -1,11 +1,28 @@ generateParams($_REQUEST['value'])); + $gis_data = array_merge( + $gis_data, $gis_obj->generateParams($_REQUEST['value']) + ); } // Generate Well Known Text -$srid = (isset($gis_data['srid']) && $gis_data['srid'] != '') ? htmlspecialchars($gis_data['srid']) : 0; +$srid = (isset($gis_data['srid']) && $gis_data['srid'] != '') + ? htmlspecialchars($gis_data['srid']) : 0; $wkt = $gis_obj->generateWkt($gis_data, 0); $wkt_with_zero = $gis_obj->generateWkt($gis_data, 0, '0'); $result = "'" . $wkt . "'," . $srid; // Generate PNG or SVG based visualization -$format = (PMA_USR_BROWSER_AGENT == 'IE' && PMA_USR_BROWSER_VER <= 8) ? 'png' : 'svg'; -$visualizationSettings = array('width' => 450, 'height' => 300, 'spatialColumn' => 'wkt'); +$format = (PMA_USR_BROWSER_AGENT == 'IE' && PMA_USR_BROWSER_VER <= 8) + ? 'png' : 'svg'; +$visualizationSettings = array( + 'width' => 450, + 'height' => 300, + 'spatialColumn' => 'wkt' +); $data = array(array('wkt' => $wkt_with_zero, 'srid' => $srid)); -$visualization = PMA_GIS_visualizationResults($data, $visualizationSettings, $format); +$visualization = PMA_GIS_visualizationResults( + $data, $visualizationSettings, $format +); $open_layers = PMA_GIS_visualizationResults($data, $visualizationSettings, 'ol'); // If the call is to update the WKT and visualization make an AJAX response @@ -65,277 +96,323 @@ 'visualization' => $visualization, 'openLayers' => $open_layers, ); - PMA_ajaxResponse(null, true, $extra_data); + $response = PMA_Response::getInstance(); + $response->addJSON($extra_data); + exit; } -// If the call is to get the whole content, start buffering, skipping and tags -if (isset($_REQUEST['get_gis_editor']) && $_REQUEST['get_gis_editor'] == true) { - ob_start(); -} else { -?> - - -'; +echo ''; +echo '
'; + +echo '

'; +printf( + __('Value for the column "%s"'), + htmlspecialchars($_REQUEST['field']) +); +echo '

'; + +echo ''; +// The input field to which the final result should be added +// and corresponding null checkbox +if (isset($_REQUEST['input_name'])) { + echo ''; } -?> -
- -
-

- -'); - // The input field to which the final result should be added and corresponding null checkbox - if (isset($_REQUEST['input_name'])) { - echo(''); +echo PMA_URL_getHiddenInputs(); + +echo ''; +echo '
'; +echo $visualization; +echo '
'; + +echo '
'; +echo '
'; + +echo '
'; +echo ''; +echo ''; +echo '
'; + +echo ''; +echo ''; + + +echo ''; +echo '
'; +echo ''; +echo '    '; +/* l10n: Spatial Reference System Identifier */ +echo ''; +echo ''; +echo '
'; +echo ''; + +echo ''; +echo '
'; + +$geom_count = 1; +if ($geom_type == 'GEOMETRYCOLLECTION') { + $geom_count = (isset($gis_data[$geom_type]['geom_count'])) + ? $gis_data[$geom_type]['geom_count'] : 1; + if (isset($gis_data[$geom_type]['add_geom'])) { + $geom_count++; + } + echo ''; +} + +for ($a = 0; $a < $geom_count; $a++) { + + if ($geom_type == 'GEOMETRYCOLLECTION') { + echo '

'; + printf(__('Geometry %d:'), $a + 1); + echo '
'; + if (isset($gis_data[$a]['gis_type'])) { + $type = $gis_data[$a]['gis_type']; + } else { + $type = $gis_types[0]; } - echo PMA_generate_common_hidden_inputs(); -?> - -
-
-
-
-
- /> - -
- - - - -
- - " /> - - -
- - - -
-'; + foreach (array_slice($gis_types, 0, 6) as $gis_type) { + echo ''; } - for ($a = 0; $a < $geom_count; $a++) { - if ($geom_type == 'GEOMETRYCOLLECTION') { - echo('

'); echo __("Geometry"); echo($a + 1 . ':
'); - if (isset($gis_data[$a]['gis_type'])) { - $type = $gis_data[$a]['gis_type']; + echo ''; + } else { + $type = $geom_type; + } + + if ($type == 'POINT') { + echo '
'; + echo __('Point:'); + echo ''; + echo ''; + echo ''; + echo ''; + + } elseif ($type == 'MULTIPOINT' || $type == 'LINESTRING') { + $no_of_points = isset($gis_data[$a][$type]['no_of_points']) + ? $gis_data[$a][$type]['no_of_points'] : 1; + if ($type == 'LINESTRING' && $no_of_points < 2) { + $no_of_points = 2; + } + if ($type == 'MULTIPOINT' && $no_of_points < 1) { + $no_of_points = 1; + } + + if (isset($gis_data[$a][$type]['add_point'])) { + $no_of_points++; + } + echo ''; + + for ($i = 0; $i < $no_of_points; $i++) { + echo '
'; + printf(__('Point %d'), $i + 1); + echo ': '; + echo ''; + echo ''; + echo ''; + echo ''; + } + echo ''; + + } elseif ($type == 'MULTILINESTRING' || $type == 'POLYGON') { + $no_of_lines = isset($gis_data[$a][$type]['no_of_lines']) + ? $gis_data[$a][$type]['no_of_lines'] : 1; + if ($no_of_lines < 1) { + $no_of_lines = 1; + } + if (isset($gis_data[$a][$type]['add_line'])) { + $no_of_lines++; + } + echo ''; + + for ($i = 0; $i < $no_of_lines; $i++) { + echo '
'; + if ($type == 'MULTILINESTRING') { + printf(__('Linestring %d:'), $i + 1); + } else { + if ($i == 0) { + echo __('Outer ring:'); } else { - $type = $gis_types[0]; + printf(__('Inner ring %d:'), $i); } - echo(''); - echo(''); - } else { - $type = $geom_type; } - if ($type == 'POINT') { - echo('
'); echo __("Point"); echo(' :'); -?> - - - -'; - $no_of_points = isset($gis_data[$a][$type]['no_of_points']) ? $gis_data[$a][$type]['no_of_points'] : 1; - if ($type == 'LINESTRING' && $no_of_points < 2) { - $no_of_points = 2; - } - if ($type == 'MULTIPOINT' && $no_of_points < 1) { - $no_of_points = 1; - } + for ($j = 0; $j < $no_of_points; $j++) { + echo('
'); + printf(__('Point %d'), $j + 1); + echo ': '; + echo ''; + echo ''; + echo ''; + echo ''; + } + echo ''; + } + $caption = ($type == 'MULTILINESTRING') + ? __('Add a linestring') + : __('Add an inner ring'); + echo '
'; + echo ''; - if (isset($gis_data[$a][$type]['add_point'])) { - $no_of_points++; - } - echo(''); - - for ($i = 0; $i < $no_of_points; $i++) { - echo('
'); - printf(__('Point %d'), $i + 1); - echo ':'; -?> - - - - - "> -'; + + for ($k = 0; $k < $no_of_polygons; $k++) { + echo '
'; + printf(__('Polygon %d:'), $k + 1); + $no_of_lines = isset($gis_data[$a][$type][$k]['no_of_lines']) + ? $gis_data[$a][$type][$k]['no_of_lines'] : 1; + if ($no_of_lines < 1) { + $no_of_lines = 1; + } + if (isset($gis_data[$a][$type][$k]['add_line'])) { + $no_of_lines++; + } + echo ''; - $no_of_lines = isset($gis_data[$a][$type]['no_of_lines']) ? $gis_data[$a][$type]['no_of_lines'] : 1; - if ($no_of_lines < 1) { - $no_of_lines = 1; + for ($i = 0; $i < $no_of_lines; $i++) { + echo '

'; + if ($i == 0) { + echo __('Outer ring:'); + } else { + printf(__('Inner ring %d:'), $i); } - if (isset($gis_data[$a][$type]['add_line'])) { - $no_of_lines++; + + $no_of_points = isset($gis_data[$a][$type][$k][$i]['no_of_points']) + ? $gis_data[$a][$type][$k][$i]['no_of_points'] : 4; + if ($no_of_points < 4) { + $no_of_points = 4; } - echo(''); - - for ($i = 0; $i < $no_of_lines; $i++) { - echo('
'); - if ($type == 'MULTILINESTRING') { - echo __("Linestring"); echo($i + 1 . ':'); - } else { - if ($i == 0) { - echo __("Outer Ring") . ':'; - } else { - echo __("Inner Ring"); echo($i . ':'); - } - } - - $no_of_points = isset($gis_data[$a][$type][$i]['no_of_points']) ? $gis_data[$a][$type][$i]['no_of_points'] : 2; - if ($type == 'MULTILINESTRING' && $no_of_points < 2) { - $no_of_points = 2; - } - if ($type == 'POLYGON' && $no_of_points < 4) { - $no_of_points = 4; - } - if (isset($gis_data[$a][$type][$i]['add_point'])) { - $no_of_points++; - } - echo(''); - - for ($j = 0; $j < $no_of_points; $j++) { - echo('
'); - printf(__('Point %d'), $j + 1); - echo ':'; -?> - - - - "> -
-'; + + for ($j = 0; $j < $no_of_points; $j++) { + echo '
'; + printf(__('Point %d'), $j + 1); + echo ': '; + echo ''; + echo ''; + echo ''; + echo ''; } - echo(''); - - for ($k = 0; $k < $no_of_polygons; $k++) { - echo('
'); echo __("Polygon"); echo($k + 1 . ':'); - $no_of_lines = isset($gis_data[$a][$type][$k]['no_of_lines']) ? $gis_data[$a][$type][$k]['no_of_lines'] : 1; - if ($no_of_lines < 1) { - $no_of_lines = 1; - } - if (isset($gis_data[$a][$type][$k]['add_line'])) { - $no_of_lines++; - } - echo(''); - - for ($i = 0; $i < $no_of_lines; $i++) { - echo('

'); - if ($i == 0) { - echo __("Outer Ring") . ':'; - } else { - echo __("Inner Ring"); echo($i . ':'); - } - - $no_of_points = isset($gis_data[$a][$type][$k][$i]['no_of_points']) ? $gis_data[$a][$type][$k][$i]['no_of_points'] : 4; - if ($no_of_points < 4) { - $no_of_points = 4; - } - if (isset($gis_data[$a][$type][$k][$i]['add_point'])) { - $no_of_points++; - } - echo(''); - - for ($j = 0; $j < $no_of_points; $j++) { - echo('
'); - printf(__('Point %d'), $j + 1); - echo ':'; -?> - " value="" /> - - " value="" /> - " class="add addPoint" value=""> -
" class="add addLine" value="">
-
" class="add addPolygon" value=""> -'; + } + echo '
'; + echo ''; + echo '
'; } - if ($geom_type == 'GEOMETRYCOLLECTION') { -?>

" /> -
- - -
-
-

-

- -
-
- -'; + echo ''; + } } -?> - +if ($geom_type == 'GEOMETRYCOLLECTION') { + echo '

'; + echo ''; +} +echo '
'; +echo ''; -'; +echo ''; + +echo '
'; +echo '

' . __('Output') . '

'; +echo '

'; +echo __( + 'Choose "GeomFromText" from the "Function" column and paste the' + . ' string below into the "Value" field' +); +echo '

'; +echo ''; +echo '
'; + +echo '
'; +echo ''; +PMA_Response::getInstance()->addJSON('gis_editor', ob_get_contents()); +ob_end_clean(); ?> diff --git a/phpMyAdmin/import.php b/phpMyAdmin/import.php index af829d9..85a7814 100644 --- a/phpMyAdmin/import.php +++ b/phpMyAdmin/import.php @@ -9,8 +9,41 @@ /** * Get the variables sent or posted to this script and a core script */ -require_once './libraries/common.inc.php'; -//require_once './libraries/display_import_functions.lib.php'; +require_once 'libraries/common.inc.php'; +require_once 'libraries/sql.lib.php'; +require_once 'libraries/bookmark.lib.php'; +//require_once 'libraries/display_import_functions.lib.php'; + +if (isset($_REQUEST['show_as_php'])) { + $GLOBALS['show_as_php'] = $_REQUEST['show_as_php']; +} + +/** + * Sets globals from $_POST + */ +$post_params = array( + 'action_bookmark', + 'allow_interrupt', + 'bkm_label', + 'bookmark_variable', + 'charset_of_file', + 'format', + 'id_bookmark', + 'import_type', + 'is_js_confirmed', + 'MAX_FILE_SIZE', + 'message_to_show', + 'noplugin', + 'skip_queries', + 'local_import_file' +); + +// TODO: adapt full list of allowed parameters, as in export.php +foreach ($post_params as $one_post_param) { + if (isset($_POST[$one_post_param])) { + $GLOBALS[$one_post_param] = $_POST[$one_post_param]; + } +} // reset import messages for ajax request $_SESSION['Import_message']['message'] = null; @@ -18,32 +51,58 @@ // default values $GLOBALS['reload'] = false; -// Are we just executing plain query or sql file? (eg. non import, but query box/window run) -if (!empty($sql_query)) { +// Use to identify curren cycle is executing +// a multiquery statement or stored routine +if (!isset($_SESSION['is_multi_query'])) { + $_SESSION['is_multi_query'] = false; +} + +// Are we just executing plain query or sql file? +// (eg. non import, but query box/window run) +if (! empty($sql_query)) { // run SQL query $import_text = $sql_query; $import_type = 'query'; $format = 'sql'; - // refresh left frame on changes in table or db structure - if (preg_match('/^(CREATE|ALTER|DROP)\s+(VIEW|TABLE|DATABASE|SCHEMA)\s+/i', $sql_query)) { + // refresh navigation and main panels + if (preg_match('/^(DROP)\s+(VIEW|TABLE|DATABASE|SCHEMA)\s+/i', $sql_query)) { $GLOBALS['reload'] = true; } + // refresh navigation panel only + if (preg_match( + '/^(CREATE|ALTER)\s+(VIEW|TABLE|DATABASE|SCHEMA)\s+/i', + $sql_query + )) { + $ajax_reload['reload'] = true; + } + + // do a dynamic reload if table is RENAMED + // (by sending the instruction to the AJAX response handler) + if (preg_match( + '/^RENAME\s+TABLE\s+(.*?)\s+TO\s+(.*?)($|;|\s)/i', + $sql_query, + $rename_table_names + )) { + $ajax_reload['table_name'] = PMA_Util::unQuote($rename_table_names[2]); + $ajax_reload['reload'] = true; + } + $sql_query = ''; -} elseif (!empty($sql_localfile)) { +} elseif (! empty($sql_localfile)) { // run SQL file on server $local_import_file = $sql_localfile; $import_type = 'queryfile'; $format = 'sql'; unset($sql_localfile); -} elseif (!empty($sql_file)) { +} elseif (! empty($sql_file)) { // run uploaded SQL file $import_file = $sql_file; $import_type = 'queryfile'; $format = 'sql'; unset($sql_file); -} elseif (!empty($id_bookmark)) { +} elseif (! empty($id_bookmark)) { // run bookmark $import_type = 'query'; $format = 'sql'; @@ -53,39 +112,75 @@ // upload limit has been reached, let's assume the second possibility. ; if ($_POST == array() && $_GET == array()) { - include_once './libraries/header.inc.php'; - $message = PMA_Message::error(__('You probably tried to upload too large file. Please refer to %sdocumentation%s for ways to workaround this limit.')); - $message->addParam('[a@./Documentation.html#faq1_16@_blank]'); - $message->addParam('[/a]'); + $message = PMA_Message::error( + __('You probably tried to upload a file that is too large. Please refer to %sdocumentation%s for a workaround for this limit.') + ); + $message->addParam('[doc@faq1-16]'); + $message->addParam('[/doc]'); // so we can obtain the message $_SESSION['Import_message']['message'] = $message->getDisplay(); $_SESSION['Import_message']['go_back_url'] = $goto; $message->display(); - include './libraries/footer.inc.php'; + exit; // the footer is displayed automatically +} + +/** + * Sets globals from $_POST patterns, for import plugins + * We only need to load the selected plugin + */ + +if (! in_array( + $format, + array( + 'csv', + 'ldi', + 'mediawiki', + 'ods', + 'shp', + 'sql', + 'xml' + ) +) +) { + // this should not happen for a normal user + // but only during an attack + PMA_fatalError('Incorrect format parameter'); +} + +$post_patterns = array( + '/^force_file_/', + '/^'. $format . '_/' +); +foreach (array_keys($_POST) as $post_key) { + foreach ($post_patterns as $one_post_pattern) { + if (preg_match($one_post_pattern, $post_key)) { + $GLOBALS[$post_key] = $_POST[$post_key]; + } + } } // Check needed parameters -PMA_checkParameters(array('import_type', 'format')); +PMA_Util::checkParameters(array('import_type', 'format')); // We don't want anything special in format $format = PMA_securePath($format); // Import functions -require_once './libraries/import.lib.php'; +require_once 'libraries/import.lib.php'; // Create error and goto url if ($import_type == 'table') { - $err_url = 'tbl_import.php?' . PMA_generate_common_url($db, $table); + $err_url = 'tbl_import.php?' . PMA_URL_getCommon($db, $table); $_SESSION['Import_message']['go_back_url'] = $err_url; $goto = 'tbl_import.php'; } elseif ($import_type == 'database') { - $err_url = 'db_import.php?' . PMA_generate_common_url($db); + $err_url = 'db_import.php?' . PMA_URL_getCommon($db); $_SESSION['Import_message']['go_back_url'] = $err_url; $goto = 'db_import.php'; } elseif ($import_type == 'server') { - $err_url = 'server_import.php?' . PMA_generate_common_url(); + $err_url = 'server_import.php?' . PMA_URL_getCommon(); $_SESSION['Import_message']['go_back_url'] = $err_url; $goto = 'server_import.php'; } else { @@ -99,25 +194,26 @@ } } if (strlen($table) && strlen($db)) { - $common = PMA_generate_common_url($db, $table); + $common = PMA_URL_getCommon($db, $table); } elseif (strlen($db)) { - $common = PMA_generate_common_url($db); + $common = PMA_URL_getCommon($db); } else { - $common = PMA_generate_common_url(); + $common = PMA_URL_getCommon(); } - $err_url = $goto - . '?' . $common - . (preg_match('@^tbl_[a-z]*\.php$@', $goto) ? '&table=' . htmlspecialchars($table) : ''); + $err_url = $goto . '?' . $common + . (preg_match('@^tbl_[a-z]*\.php$@', $goto) + ? '&table=' . htmlspecialchars($table) + : ''); $_SESSION['Import_message']['go_back_url'] = $err_url; } if (strlen($db)) { - PMA_DBI_select_db($db); + $GLOBALS['dbi']->selectDb($db); } @set_time_limit($cfg['ExecTimeLimit']); -if (!empty($cfg['MemoryLimit'])) { +if (! empty($cfg['MemoryLimit'])) { @ini_set('memory_limit', $cfg['MemoryLimit']); } @@ -146,46 +242,72 @@ $bookmark_created = false; // Bookmark Support: get a query back from bookmark if required -if (!empty($id_bookmark)) { +if (! empty($id_bookmark)) { $id_bookmark = (int)$id_bookmark; - include_once './libraries/bookmark.lib.php'; + include_once 'libraries/bookmark.lib.php'; switch ($action_bookmark) { - case 0: // bookmarked query that have to be run - $import_text = PMA_Bookmark_get($db, $id_bookmark, 'id', isset($action_bookmark_all)); - if (isset($bookmark_variable) && !empty($bookmark_variable)) { - $import_text = preg_replace('|/\*(.*)\[VARIABLE\](.*)\*/|imsU', '${1}' . PMA_sqlAddSlashes($bookmark_variable) . '${2}', $import_text); - } + case 0: // bookmarked query that have to be run + $import_text = PMA_Bookmark_get( + $db, + $id_bookmark, + 'id', + isset($action_bookmark_all) + ); + if (isset($bookmark_variable) && ! empty($bookmark_variable)) { + $import_text = preg_replace( + '|/\*(.*)\[VARIABLE\](.*)\*/|imsU', + '${1}' . PMA_Util::sqlAddSlashes($bookmark_variable) . '${2}', + $import_text + ); + } - // refresh left frame on changes in table or db structure - if (preg_match('/^(CREATE|ALTER|DROP)\s+(VIEW|TABLE|DATABASE|SCHEMA)\s+/i', $import_text)) { - $GLOBALS['reload'] = true; - } + // refresh navigation and main panels + if (preg_match( + '/^(DROP)\s+(VIEW|TABLE|DATABASE|SCHEMA)\s+/i', + $import_text + )) { + $GLOBALS['reload'] = true; + } - break; - case 1: // bookmarked query that have to be displayed - $import_text = PMA_Bookmark_get($db, $id_bookmark); - if ($GLOBALS['is_ajax_request'] == true) { - $extra_data['sql_query'] = $import_text; - $extra_data['action_bookmark'] = $action_bookmark; - $message = PMA_Message::success(__('Showing bookmark')); - PMA_ajaxResponse($message, $message->isSuccess(), $extra_data); - } else { - $run_query = false; - } - break; - case 2: // bookmarked query that have to be deleted - $import_text = PMA_Bookmark_get($db, $id_bookmark); - PMA_Bookmark_delete($db, $id_bookmark); - if ($GLOBALS['is_ajax_request'] == true) { - $message = PMA_Message::success(__('The bookmark has been deleted.')); - $extra_data['action_bookmark'] = $action_bookmark; - $extra_data['id_bookmark'] = $id_bookmark; - PMA_ajaxResponse($message, $message->isSuccess(), $extra_data); - } else { - $run_query = false; - $error = true; // this is kind of hack to skip processing the query - } - break; + // refresh navigation panel only + if (preg_match( + '/^(CREATE|ALTER)\s+(VIEW|TABLE|DATABASE|SCHEMA)\s+/i', + $import_text + ) + ) { + $ajax_reload['reload'] = true; + } + break; + case 1: // bookmarked query that have to be displayed + $import_text = PMA_Bookmark_get($db, $id_bookmark); + if ($GLOBALS['is_ajax_request'] == true) { + $message = PMA_Message::success(__('Showing bookmark')); + $response = PMA_Response::getInstance(); + $response->isSuccess($message->isSuccess()); + $response->addJSON('message', $message); + $response->addJSON('sql_query', $import_text); + $response->addJSON('action_bookmark', $action_bookmark); + exit; + } else { + $run_query = false; + } + break; + case 2: // bookmarked query that have to be deleted + $import_text = PMA_Bookmark_get($db, $id_bookmark); + PMA_Bookmark_delete($db, $id_bookmark); + if ($GLOBALS['is_ajax_request'] == true) { + $message = PMA_Message::success(__('The bookmark has been deleted.')); + $response = PMA_Response::getInstance(); + $response->isSuccess($message->isSuccess()); + $response->addJSON('message', $message); + $response->addJSON('action_bookmark', $action_bookmark); + $response->addJSON('id_bookmark', $id_bookmark); + exit; + } else { + $run_query = false; + $error = true; // this is kind of hack to skip processing the query + } + break; } } // end bookmarks reading @@ -195,31 +317,6 @@ $go_sql = true; } -// Store the query as a bookmark before executing it if bookmarklabel was given -if (!empty($bkm_label) && !empty($import_text)) { - include_once './libraries/bookmark.lib.php'; - $bfields = array( - 'dbase' => $db, - 'user' => $cfg['Bookmark']['user'], - 'query' => urlencode($import_text), - 'label' => $bkm_label - ); - - // Should we replace bookmark? - if (isset($bkm_replace)) { - $bookmarks = PMA_Bookmark_getList($db); - foreach ($bookmarks as $key => $val) { - if ($val == $bkm_label) { - PMA_Bookmark_delete($db, $key); - } - } - } - - PMA_Bookmark_save($bfields, isset($bkm_all_users)); - - $bookmark_created = true; -} // end store bookmarks - // We can not read all at once, otherwise we can run out of memory $memory_limit = trim(@ini_get('memory_limit')); // 2 MB as default @@ -242,22 +339,28 @@ $memory_limit = (int)$memory_limit; } -$read_limit = $memory_limit / 8; // Just to be sure, there might be lot of memory needed for uncompression +// Just to be sure, there might be lot of memory needed for uncompression +$read_limit = $memory_limit / 8; // handle filenames -if (!empty($local_import_file) && !empty($cfg['UploadDir'])) { +if (isset($_FILES['import_file'])) { + $import_file = $_FILES['import_file']['tmp_name']; +} +if (! empty($local_import_file) && ! empty($cfg['UploadDir'])) { // sanitize $local_import_file as it comes from a POST $local_import_file = PMA_securePath($local_import_file); - $import_file = PMA_userDir($cfg['UploadDir']) . $local_import_file; -} elseif (empty($import_file) || !is_uploaded_file($import_file)) { + $import_file = PMA_Util::userDir($cfg['UploadDir']) + . $local_import_file; + +} elseif (empty($import_file) || ! is_uploaded_file($import_file)) { $import_file = 'none'; } // Do we have file to import? -if ($import_file != 'none' && !$error) { +if ($import_file != 'none' && ! $error) { // work around open_basedir and other limitations $open_basedir = @ini_get('open_basedir'); @@ -265,9 +368,9 @@ // before opening it. The doc explains how to create the "./tmp" // directory - if (!empty($open_basedir)) { + if (! empty($open_basedir)) { - $tmp_subdir = (PMA_IS_WINDOWS ? '.\\tmp\\' : './tmp/'); + $tmp_subdir = (PMA_IS_WINDOWS ? '.\\tmp\\' : 'tmp/'); if (is_writable($tmp_subdir)) { @@ -284,7 +387,7 @@ /** * Handle file compression - * @todo duplicate code exists in File.class.php + * @todo duplicate code exists in File.class.php */ $compression = PMA_detectCompression($import_file); if ($compression === false) { @@ -292,61 +395,71 @@ $error = true; } else { switch ($compression) { - case 'application/bzip2': - if ($cfg['BZipDump'] && @function_exists('bzopen')) { - $import_handle = @bzopen($import_file, 'r'); - } else { - $message = PMA_Message::error(__('You attempted to load file with unsupported compression (%s). Either support for it is not implemented or disabled by your configuration.')); - $message->addParam($compression); - $error = true; - } - break; - case 'application/gzip': - if ($cfg['GZipDump'] && @function_exists('gzopen')) { - $import_handle = @gzopen($import_file, 'r'); - } else { - $message = PMA_Message::error(__('You attempted to load file with unsupported compression (%s). Either support for it is not implemented or disabled by your configuration.')); - $message->addParam($compression); + case 'application/bzip2': + if ($cfg['BZipDump'] && @function_exists('bzopen')) { + $import_handle = @bzopen($import_file, 'r'); + } else { + $message = PMA_Message::error( + __('You attempted to load file with unsupported compression (%s). Either support for it is not implemented or disabled by your configuration.') + ); + $message->addParam($compression); + $error = true; + } + break; + case 'application/gzip': + if ($cfg['GZipDump'] && @function_exists('gzopen')) { + $import_handle = @gzopen($import_file, 'r'); + } else { + $message = PMA_Message::error( + __('You attempted to load file with unsupported compression (%s). Either support for it is not implemented or disabled by your configuration.') + ); + $message->addParam($compression); + $error = true; + } + break; + case 'application/zip': + if ($cfg['ZipDump'] && @function_exists('zip_open')) { + /** + * Load interface for zip extension. + */ + include_once 'libraries/zip_extension.lib.php'; + $result = PMA_getZipContents($import_file); + if (! empty($result['error'])) { + $message = PMA_Message::rawError($result['error']); $error = true; - } - break; - case 'application/zip': - if ($cfg['ZipDump'] && @function_exists('zip_open')) { - /** - * Load interface for zip extension. - */ - include_once './libraries/zip_extension.lib.php'; - $result = PMA_getZipContents($import_file); - if (! empty($result['error'])) { - $message = PMA_Message::rawError($result['error']); - $error = true; - } else { - $import_text = $result['data']; - } } else { - $message = PMA_Message::error(__('You attempted to load file with unsupported compression (%s). Either support for it is not implemented or disabled by your configuration.')); - $message->addParam($compression); - $error = true; + $import_text = $result['data']; } - break; - case 'none': - $import_handle = @fopen($import_file, 'r'); - break; - default: - $message = PMA_Message::error(__('You attempted to load file with unsupported compression (%s). Either support for it is not implemented or disabled by your configuration.')); + } else { + $message = PMA_Message::error( + __('You attempted to load file with unsupported compression (%s). Either support for it is not implemented or disabled by your configuration.') + ); $message->addParam($compression); $error = true; - break; + } + break; + case 'none': + $import_handle = @fopen($import_file, 'r'); + break; + default: + $message = PMA_Message::error( + __('You attempted to load file with unsupported compression (%s). Either support for it is not implemented or disabled by your configuration.') + ); + $message->addParam($compression); + $error = true; + break; } } // use isset() because zip compression type does not use a handle - if (!$error && isset($import_handle) && $import_handle === false) { + if (! $error && isset($import_handle) && $import_handle === false) { $message = PMA_Message::error(__('File could not be read')); $error = true; } -} elseif (!$error) { +} elseif (! $error) { if (! isset($import_text) || empty($import_text)) { - $message = PMA_Message::error(__('No data was received to import. Either no file name was submitted, or the file size exceeded the maximum size permitted by your PHP configuration. See [a@./Documentation.html#faq1_16@Documentation]FAQ 1.16[/a].')); + $message = PMA_Message::error( + __('No data was received to import. Either no file name was submitted, or the file size exceeded the maximum size permitted by your PHP configuration. See [doc@faq1-16]FAQ 1.16[/doc].') + ); $error = true; } } @@ -361,11 +474,14 @@ } } elseif (isset($charset_of_file) && $charset_of_file != 'utf8') { if (PMA_DRIZZLE) { - // Drizzle doesn't support other character sets, so we can't fallback to SET NAMES - throw an error + // Drizzle doesn't support other character sets, + // so we can't fallback to SET NAMES - throw an error $error = true; - $message = PMA_Message::error(__('Cannot convert file\'s character set without character set conversion library')); + $message = PMA_Message::error( + __('Cannot convert file\'s character set without character set conversion library') + ); } else { - PMA_DBI_query('SET NAMES \'' . $charset_of_file . '\''); + $GLOBALS['dbi']->query('SET NAMES \'' . $charset_of_file . '\''); // We can not show query in this case, it is in different charset $sql_query_disabled = true; $reset_charset = true; @@ -373,25 +489,38 @@ } // Something to skip? -if (!$error && isset($skip)) { +if (! $error && isset($skip)) { $original_skip = $skip; while ($skip > 0) { PMA_importGetNextChunk($skip < $read_limit ? $skip : $read_limit); - $read_multiply = 1; // Disable read progresivity, otherwise we eat all memory! + // Disable read progresivity, otherwise we eat all memory! + $read_multiply = 1; $skip -= $read_limit; } unset($skip); } -if (!$error) { +// This array contain the data like numberof valid sql queries in the statement +// and complete valid sql statement (which affected for rows) +$sql_data = array('valid_sql' => array(), 'valid_queries' => 0); + +if (! $error) { // Check for file existance - if (!file_exists('./libraries/import/' . $format . '.php')) { + include_once "libraries/plugin_interface.lib.php"; + $import_plugin = PMA_getPlugin( + "import", + $format, + 'libraries/plugins/import/', + $import_type + ); + if ($import_plugin == null) { $error = true; - $message = PMA_Message::error(__('Could not load import plugins, please check your installation!')); + $message = PMA_Message::error( + __('Could not load import plugins, please check your installation!') + ); } else { // Do the real import - $plugin_param = $import_type; - include './libraries/import/' . $format . '.php'; + $import_plugin->doImport($sql_data); } } @@ -406,79 +535,108 @@ // Reset charset back, if we did some changes if ($reset_charset) { - PMA_DBI_query('SET CHARACTER SET utf8'); - PMA_DBI_query('SET SESSION collation_connection =\'' . $collation_connection . '\''); + $GLOBALS['dbi']->query('SET CHARACTER SET utf8'); + $GLOBALS['dbi']->query( + 'SET SESSION collation_connection =\'' . $collation_connection . '\'' + ); } // Show correct message -if (!empty($id_bookmark) && $action_bookmark == 2) { +if (! empty($id_bookmark) && $action_bookmark == 2) { $message = PMA_Message::success(__('The bookmark has been deleted.')); $display_query = $import_text; $error = false; // unset error marker, it was used just to skip processing -} elseif (!empty($id_bookmark) && $action_bookmark == 1) { +} elseif (! empty($id_bookmark) && $action_bookmark == 1) { $message = PMA_Message::notice(__('Showing bookmark')); } elseif ($bookmark_created) { - $special_message = '[br]' . sprintf(__('Bookmark %s created'), htmlspecialchars($bkm_label)); -} elseif ($finished && !$error) { + $special_message = '[br]' . sprintf( + __('Bookmark %s created'), + htmlspecialchars($bkm_label) + ); +} elseif ($finished && ! $error) { if ($import_type == 'query') { $message = PMA_Message::success(); } else { - if ($import_notice) { - $message = PMA_Message::success(''.__('Import has been successfully finished, %d queries executed.').''); - $message->addParam($executed_queries); + $message = PMA_Message::success( + '' + . __('Import has been successfully finished, %d queries executed.') + . '' + ); + $message->addParam($executed_queries); + if ($import_notice) { $message->addString($import_notice); - $message->addString('(' . $_FILES['import_file']['name'] . ')'); + } + if (isset($local_import_file)) { + $message->addString('(' . htmlspecialchars($local_import_file) . ')'); } else { - $message = PMA_Message::success(__('Import has been successfully finished, %d queries executed.')); - $message->addParam($executed_queries); - $message->addString('(' . $_FILES['import_file']['name'] . ')'); + $message->addString('(' . htmlspecialchars($_FILES['import_file']['name']) . ')'); } } } // Did we hit timeout? Tell it user. if ($timeout_passed) { - $message = PMA_Message::error(__('Script timeout passed, if you want to finish import, please resubmit same file and import will resume.')); + $message = PMA_Message::error( + __('Script timeout passed, if you want to finish import, please resubmit same file and import will resume.') + ); if ($offset == 0 || (isset($original_skip) && $original_skip == $offset)) { - $message->addString(__('However on last run no data has been parsed, this usually means phpMyAdmin won\'t be able to finish this import unless you increase php time limits.')); + $message->addString( + __('However on last run no data has been parsed, this usually means phpMyAdmin won\'t be able to finish this import unless you increase php time limits.') + ); } } -// if there is any message, copy it into $_SESSION as well, so we can obtain it by AJAX call +// if there is any message, copy it into $_SESSION as well, +// so we can obtain it by AJAX call if (isset($message)) { $_SESSION['Import_message']['message'] = $message->getDisplay(); -// $_SESSION['Import_message']['go_back_url'] = $goto.'?'. PMA_generate_common_url(); } // Parse and analyze the query, for correct db and table name // in case of a query typed in the query window // (but if the query is too large, in case of an imported file, the parser // can choke on it so avoid parsing) if (strlen($sql_query) <= $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']) { - include_once './libraries/parse_analyze.lib.php'; + include_once 'libraries/parse_analyze.inc.php'; } // There was an error? if (isset($my_die)) { - foreach ($my_die AS $key => $die) { - PMA_mysqlDie($die['error'], $die['sql'], '', $err_url, $error); + foreach ($my_die as $key => $die) { + PMA_Util::mysqlDie( + $die['error'], $die['sql'], '', $err_url, $error + ); } } -// we want to see the results of the last query that returned at least a row -if (! empty($last_query_with_results)) { - // but we want to show intermediate results too - $disp_query = $sql_query; - $disp_message = __('Your SQL query has been executed successfully'); - $sql_query = $last_query_with_results; - $go_sql = true; -} - if ($go_sql) { - include './sql.php'; + // parse sql query + include_once 'libraries/parse_analyze.inc.php'; + + if (isset($ajax_reload) && $ajax_reload['reload'] === true) { + $response = PMA_Response::getInstance(); + $response->addJSON('ajax_reload', $ajax_reload); + } + PMA_executeQueryAndSendQueryResponse( + $analyzed_sql_results, false, $db, $table, null, $import_text, null, + $analyzed_sql_results['is_affected'], null, + null, null, null, $goto, $pmaThemeImage, null, null, null, $sql_query, + null, null + ); +} else if ($result) { + $response = PMA_Response::getInstance(); + $response->isSuccess(true); + $response->addJSON('message', PMA_Message::success($msg)); + $response->addJSON( + 'sql_query', + PMA_Util::getMessage($msg, $sql_query, 'success') + ); +} else if ($result == false) { + $response = PMA_Response::getInstance(); + $response->isSuccess(false); + $response->addJSON('message', PMA_Message::error($msg)); } else { $active_page = $goto; - include './' . $goto; + include '' . $goto; } -exit(); ?> diff --git a/phpMyAdmin/import_status.php b/phpMyAdmin/import_status.php index ebe3a97..f31e424 100644 --- a/phpMyAdmin/import_status.php +++ b/phpMyAdmin/import_status.php @@ -1,22 +1,79 @@ =') + && ini_get('session.upload_progress.enabled') +) { + + $sessionupload = array(); + define('UPLOAD_PREFIX', ini_get('session.upload_progress.prefix')); + + session_start(); + foreach ($_SESSION as $key => $value) { + // only copy session-prefixed data + if (substr($key, 0, strlen(UPLOAD_PREFIX)) == UPLOAD_PREFIX) { + $sessionupload[$key] = $value; + } + } + // PMA will kill all variables, so let's use a constant + define('SESSIONUPLOAD', serialize($sessionupload)); + session_write_close(); + + session_name('phpMyAdmin'); + session_id($_COOKIE['phpMyAdmin']); +} + +define('PMA_MINIMUM_COMMON', 1); + +require_once 'libraries/common.inc.php'; +require_once 'libraries/display_import_ajax.lib.php'; + +if (defined('SESSIONUPLOAD')) { + // write sessionupload back into the loaded PMA session + + $sessionupload = unserialize(SESSIONUPLOAD); + foreach ($sessionupload as $key => $value) { + $_SESSION[$key] = $value; + } + + // remove session upload data that are not set anymore + foreach ($_SESSION as $key => $value) { + if (substr($key, 0, strlen(UPLOAD_PREFIX)) == UPLOAD_PREFIX + && ! isset($sessionupload[$key]) + ) { + unset($_SESSION[$key]); + } + } +} // AJAX requests can't be cached! -PMA_no_cache_header(); +PMA_noCacheHeader(); -// $GLOBALS["message"] is used for asking for an import message -if (isset($GLOBALS["message"]) && $GLOBALS["message"]) { +// $_GET["message"] is used for asking for an import message +if (isset($_GET["message"]) && $_GET["message"]) { header('Content-type: text/html'); - // wait 0.3 sec before we check for $_SESSION variable, which is set inside import.php + // wait 0.3 sec before we check for $_SESSION variable, + // which is set inside import.php usleep(300000); // wait until message is available @@ -26,10 +83,11 @@ echo $_SESSION['Import_message']['message']; echo '
' . "\n"; - echo ' [ ' . __('Back') . ' ]' . "\n"; + echo ' [ ' . __('Back') . ' ]' . "\n"; echo '
'."\n"; } else { - PMA_importAjaxStatus($GLOBALS["id"]); + PMA_importAjaxStatus($_GET["id"]); } ?> diff --git a/phpMyAdmin/index.php b/phpMyAdmin/index.php index e23153f..61328fd 100644 --- a/phpMyAdmin/index.php +++ b/phpMyAdmin/index.php @@ -1,168 +1,653 @@ addJSON( + 'options', + PMA_RecentTable::getInstance()->getHtmlSelectOption() + ); + exit; +} -foreach ($drops as $each_drop) { - if (array_key_exists($each_drop, $_GET)) { - unset($_GET[$each_drop]); +if ($GLOBALS['PMA_Config']->isGitRevision()) { + if (isset($_REQUEST['git_revision']) && $GLOBALS['is_ajax_request'] == true) { + PMA_printGitRevision(); + exit; } + echo '
'; } -unset($drops, $each_drop); -if (! strlen($GLOBALS['db'])) { - $main_target = $GLOBALS['cfg']['DefaultTabServer']; -} elseif (! strlen($GLOBALS['table'])) { - $_GET['db'] = $GLOBALS['db']; - $main_target = $GLOBALS['cfg']['DefaultTabDatabase']; -} else { - $_GET['db'] = $GLOBALS['db']; - $_GET['table'] = $GLOBALS['table']; - $main_target = ! empty($GLOBALS['goto']) ? $GLOBALS['goto'] : $GLOBALS['cfg']['DefaultTabTable']; +// Handles some variables that may have been sent by the calling script +$GLOBALS['db'] = ''; +$GLOBALS['table'] = ''; +$show_query = '1'; + +// Any message to display? +if (! empty($message)) { + echo PMA_Util::getMessage($message); + unset($message); } -$url_query = PMA_generate_common_url($_GET); +$common_url_query = PMA_URL_getCommon('', ''); + +// when $server > 0, a server has been chosen so we can display +// all MySQL-related information +if ($server > 0) { + include 'libraries/server_common.inc.php'; + include 'libraries/StorageEngine.class.php'; + + // Use the verbose name of the server instead of the hostname + // if a value is set + $server_info = ''; + if (! empty($cfg['Server']['verbose'])) { + $server_info .= htmlspecialchars($cfg['Server']['verbose']); + if ($GLOBALS['cfg']['ShowServerInfo']) { + $server_info .= ' ('; + } + } + if ($GLOBALS['cfg']['ShowServerInfo'] || empty($cfg['Server']['verbose'])) { + $server_info .= $GLOBALS['dbi']->getHostInfo(); + } + if (! empty($cfg['Server']['verbose']) && $GLOBALS['cfg']['ShowServerInfo']) { + $server_info .= ')'; + } + $mysql_cur_user_and_host = $GLOBALS['dbi']->fetchValue('SELECT USER();'); -if (isset($GLOBALS['target']) && is_string($GLOBALS['target']) && !empty($GLOBALS['target']) && in_array($GLOBALS['target'], $goto_whitelist)) { - $main_target = $GLOBALS['target']; + // should we add the port info here? + $short_server_info = (!empty($GLOBALS['cfg']['Server']['verbose']) + ? $GLOBALS['cfg']['Server']['verbose'] + : $GLOBALS['cfg']['Server']['host']); } -$main_target .= $url_query; +echo '
' . "\n"; +echo '
'; +if ($server > 0 || count($cfg['Servers']) > 1 +) { + if ($cfg['DBG']['demo']) { + echo '
'; + echo '

' . __('phpMyAdmin Demo Server') . '

'; + echo '

'; + printf( + __( + 'You are using the demo server. You can do anything here, but ' + . 'please do not change root, debian-sys-maint and pma users. ' + . 'More information is available at %s.' + ), + 'demo.phpmyadmin.net' + ); + echo '

'; + echo '
'; + } + echo '
'; + echo '

' . __('General Settings') . '

'; + echo '
    '; -$lang_iso_code = $GLOBALS['available_languages'][$GLOBALS['lang']][1]; + /** + * Displays the MySQL servers choice form + */ + if ($cfg['ServerDefault'] == 0 + || (! $cfg['NavigationDisplayServers'] + && (count($cfg['Servers']) > 1 + || ($server == 0 && count($cfg['Servers']) == 1))) + ) { + echo '
  • '; + include_once 'libraries/select_server.lib.php'; + echo PMA_Util::getImage('s_host.png') . " " . PMA_selectServer(true, true); + echo '
  • '; + } + /** + * Displays the mysql server related links + */ + if ($server > 0 && ! PMA_DRIZZLE) { + include_once 'libraries/check_user_privileges.lib.php'; -// start output -require './libraries/header_http.inc.php'; -?> - - - - - -phpMyAdmin <?php echo PMA_VERSION; ?> - - <?php echo htmlspecialchars($HTTP_HOST); ?> - - - -'; + echo '
'; +} + +echo '
'; +echo '

phpMyAdmin

'; +echo '
    '; +$class = null; +// We rely on CSP to allow access to http://www.phpmyadmin.net, but IE lacks +// support here and does not allow request to http once using https. +if ($GLOBALS['cfg']['VersionCheck'] + && (! $GLOBALS['PMA_Config']->get('is_https') || PMA_USR_BROWSER_AGENT != 'IE') +) { + $class = 'jsversioncheck'; +} +PMA_printListItem( + __('Version information:') . ' ' . PMA_VERSION, + 'li_pma_version', + null, + null, + null, + null, + $class +); +PMA_printListItem( + __('Documentation'), + 'li_pma_docs', + PMA_Util::getDocuLink('index'), + null, + '_blank' +); +PMA_printListItem( + __('Wiki'), + 'li_pma_wiki', + PMA_linkURL('http://wiki.phpmyadmin.net/'), + null, + '_blank' +); + +// does not work if no target specified, don't know why +PMA_printListItem( + __('Official Homepage'), + 'li_pma_homepage', + PMA_linkURL('http://www.phpMyAdmin.net/'), + null, + '_blank' +); +PMA_printListItem( + __('Contribute'), + 'li_pma_contribute', + PMA_linkURL('http://www.phpmyadmin.net/home_page/improve.php'), + null, + '_blank' +); +PMA_printListItem( + __('Get support'), + 'li_pma_support', + PMA_linkURL('http://www.phpmyadmin.net/home_page/support.php'), + null, + '_blank' +); +PMA_printListItem( + __('List of changes'), + 'li_pma_changes', + PMA_linkURL('changelog.php'), + null, + '_blank' +); +echo '
'; +echo '
'; + +echo '
'; + +echo '
'; + +/** + * Warning if using the default MySQL privileged account + */ +if ($server != 0 + && $cfg['Server']['user'] == 'root' + && $cfg['Server']['password'] == '' +) { + trigger_error( + __( + 'Your configuration file contains settings (root with no password)' + . ' that correspond to the default MySQL privileged account.' + . ' Your MySQL server is running with this default, is open to' + . ' intrusion, and you really should fix this security hole by' + . ' setting a password for user \'root\'.' + ), + E_USER_WARNING + ); +} + +/** + * As we try to handle charsets by ourself, mbstring overloads just + * break it, see bug 1063821. + */ +if (@extension_loaded('mbstring') && @ini_get('mbstring.func_overload') > 1) { + trigger_error( + __( + 'You have enabled mbstring.func_overload in your PHP ' + . 'configuration. This option is incompatible with phpMyAdmin ' + . 'and might cause some data to be corrupted!' + ), + E_USER_WARNING + ); +} + +/** + * mbstring is used for handling multibyte inside parser, so it is good + * to tell user something might be broken without it, see bug #1063149. + */ +if (! @extension_loaded('mbstring')) { + trigger_error( + __( + 'The mbstring PHP extension was not found and you seem to be using' + . ' a multibyte charset. Without the mbstring extension phpMyAdmin' + . ' is unable to split strings correctly and it may result in' + . ' unexpected results.' + ), + E_USER_WARNING + ); +} + +/** + * Check whether session.gc_maxlifetime limits session validity. + */ +$gc_time = (int)@ini_get('session.gc_maxlifetime'); +if ($gc_time < $GLOBALS['cfg']['LoginCookieValidity'] ) { + trigger_error( + __('Your PHP parameter [a@http://php.net/manual/en/session.configuration.php#ini.session.gc-maxlifetime@_blank]session.gc_maxlifetime[/a] is lower than cookie validity configured in phpMyAdmin, because of this, your login will expire sooner than configured in phpMyAdmin.'), + E_USER_WARNING + ); +} + +/** + * Check whether LoginCookieValidity is limited by LoginCookieStore. + */ +if ($GLOBALS['cfg']['LoginCookieStore'] != 0 + && $GLOBALS['cfg']['LoginCookieStore'] < $GLOBALS['cfg']['LoginCookieValidity'] +) { + trigger_error( + __('Login cookie store is lower than cookie validity configured in phpMyAdmin, because of this, your login will expire sooner than configured in phpMyAdmin.'), + E_USER_WARNING + ); +} + +/** + * Check if user does not have defined blowfish secret and it is being used. + */ +if (! empty($_SESSION['auto_blowfish_secret']) + && empty($GLOBALS['cfg']['blowfish_secret']) +) { + trigger_error( + __('The configuration file now needs a secret passphrase (blowfish_secret).'), + E_USER_WARNING + ); +} + +/** + * Check for existence of config directory which should not exist in + * production environment. + */ +if (file_exists('config')) { + trigger_error( + __('Directory [code]config[/code], which is used by the setup script, still exists in your phpMyAdmin directory. It is strongly recommended to remove it once phpMyAdmin has been configured. Otherwise the security of your server may be compromised by unauthorized people downloading your configuration.'), + E_USER_WARNING + ); +} + +if ($server > 0) { + $cfgRelation = PMA_getRelationsParam(); + if (! $cfgRelation['allworks'] + && $cfg['PmaNoRelation_DisableWarning'] == false + ) { + $msg = PMA_Message::notice(__('The phpMyAdmin configuration storage is not completely configured, some extended features have been deactivated. To find out why click %shere%s.')); + $msg->addParam( + '', + false + ); + $msg->addParam('', false); + /* Show error if user has configured something, notice elsewhere */ + if (!empty($cfg['Servers'][$server]['pmadb'])) { + $msg->isError(true); + } + $msg->display(); + } // end if +} + +/** + * Warning about different MySQL library and server version + * (a difference on the third digit does not count). + * If someday there is a constant that we can check about mysqlnd, + * we can use it instead of strpos(). + * If no default server is set, $GLOBALS['dbi'] is not defined yet. + * Drizzle can speak MySQL protocol, so don't warn about version mismatch for + * Drizzle servers. + */ +if (isset($GLOBALS['dbi']) + && !PMA_DRIZZLE + && $cfg['ServerLibraryDifference_DisableWarning'] == false +) { + $_client_info = $GLOBALS['dbi']->getClientInfo(); + if ($server > 0 + && strpos($_client_info, 'mysqlnd') === false + && substr(PMA_MYSQL_CLIENT_API, 0, 3) != substr(PMA_MYSQL_INT_VERSION, 0, 3) + ) { + trigger_error( + PMA_sanitize( + sprintf( + __('Your PHP MySQL library version %s differs from your MySQL server version %s. This may cause unpredictable behavior.'), + $_client_info, + substr( + PMA_MYSQL_STR_VERSION, + 0, + strpos(PMA_MYSQL_STR_VERSION . '-', '-') + ) + ) + ), + E_USER_NOTICE + ); + } + unset($_client_info); +} + +/** + * Warning about Suhosin only if its simulation mode is not enabled + */ +if ($cfg['SuhosinDisableWarning'] == false + && @ini_get('suhosin.request.max_value_length') + && @ini_get('suhosin.simulation') == '0' +) { + trigger_error( + sprintf( + __('Server running with Suhosin. Please refer to %sdocumentation%s for possible issues.'), + '[doc@faq1-38]', + '[/doc]' + ), + E_USER_WARNING + ); +} + +/** + * Warning about mcrypt. + */ +if (! function_exists('mcrypt_encrypt') + && ! $GLOBALS['cfg']['McryptDisableWarning'] +) { + PMA_warnMissingExtension('mcrypt'); +} + +/** + * Warning about incomplete translations. + * + * The data file is created while creating release by ./scripts/remove-incomplete-mo + */ +if (file_exists('libraries/language_stats.inc.php')) { + include 'libraries/language_stats.inc.php'; + /* + * This message is intentionally not translated, because we're + * handling incomplete translations here and focus on english + * speaking users. + */ + if (isset($GLOBALS['language_stats'][$lang]) + && $GLOBALS['language_stats'][$lang] < $cfg['TranslationWarningThreshold'] + ) { + trigger_error( + 'You are using an incomplete translation, please help to make it ' + . 'better by [a@http://www.phpmyadmin.net/home_page/improve.php' + . '#translate@_blank]contributing[/a].', + E_USER_NOTICE + ); + } +} + +/** + * prints list item for main page + * + * @param string $name displayed text + * @param string $id id, used for css styles + * @param string $url make item as link with $url as target + * @param string $mysql_help_page display a link to MySQL's manual + * @param string $target special target for $url + * @param string $a_id id for the anchor, + * used for jQuery to hook in functions + * @param string $class class for the li element + * @param string $a_class class for the anchor element + * + * @return void + */ +function PMA_printListItem($name, $id = null, $url = null, + $mysql_help_page = null, $target = null, $a_id = null, $class = null, + $a_class = null +) { + echo '
  • '; + if (null !== $url) { + echo ''; + } + + echo $name; + + if (null !== $url) { + echo '' . "\n"; + } + if (null !== $mysql_help_page) { + echo PMA_Util::showMySQLDocu($mysql_help_page); + } + echo '
  • '; +} ?> - - - - - - - - - - - <body> - <p><?php echo __('phpMyAdmin is more friendly with a <b>frames-capable</b> browser.'); ?></p> - </body> - - - diff --git a/phpMyAdmin/js/OpenStreetMap.js b/phpMyAdmin/js/OpenStreetMap.js index 4b52f0f..51694bc 100644 --- a/phpMyAdmin/js/OpenStreetMap.js +++ b/phpMyAdmin/js/OpenStreetMap.js @@ -1,4 +1,126 @@ -OpenLayers.Util.OSM={};OpenLayers.Util.OSM.MISSING_TILE_URL="http://www.openstreetmap.org/openlayers/img/404.png";OpenLayers.Util.OSM.originalOnImageLoadError=OpenLayers.Util.onImageLoadError;OpenLayers.Util.onImageLoadError=function(){if(this.src.match(/^http:\/\/[abc]\.[a-z]+\.openstreetmap\.org\//))this.src=OpenLayers.Util.OSM.MISSING_TILE_URL;else this.src.match(/^http:\/\/[def]\.tah\.openstreetmap\.org\//)}; -OpenLayers.Layer.OSM.Mapnik=OpenLayers.Class(OpenLayers.Layer.OSM,{initialize:function(b,a){a=OpenLayers.Util.extend({numZoomLevels:19,buffer:0,transitionEffect:"resize"},a);OpenLayers.Layer.OSM.prototype.initialize.apply(this,[b,["http://a.tile.openstreetmap.org/${z}/${x}/${y}.png","http://b.tile.openstreetmap.org/${z}/${x}/${y}.png","http://c.tile.openstreetmap.org/${z}/${x}/${y}.png"],a])},CLASS_NAME:"OpenLayers.Layer.OSM.Mapnik"}); -OpenLayers.Layer.OSM.Osmarender=OpenLayers.Class(OpenLayers.Layer.OSM,{initialize:function(b,a){a=OpenLayers.Util.extend({numZoomLevels:18,buffer:0,transitionEffect:"resize"},a);OpenLayers.Layer.OSM.prototype.initialize.apply(this,[b,["http://a.tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png","http://b.tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png","http://c.tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png"],a])},CLASS_NAME:"OpenLayers.Layer.OSM.Osmarender"}); -OpenLayers.Layer.OSM.CycleMap=OpenLayers.Class(OpenLayers.Layer.OSM,{initialize:function(b,a){a=OpenLayers.Util.extend({numZoomLevels:19,buffer:0,transitionEffect:"resize"},a);OpenLayers.Layer.OSM.prototype.initialize.apply(this,[b,["http://a.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png","http://b.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png","http://c.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png"],a])},CLASS_NAME:"OpenLayers.Layer.OSM.CycleMap"}); +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Namespace: Util.OSM + */ +OpenLayers.Util.OSM = {}; + +/** + * Constant: MISSING_TILE_URL + * {String} URL of image to display for missing tiles + */ +OpenLayers.Util.OSM.MISSING_TILE_URL = "http://www.openstreetmap.org/openlayers/img/404.png"; + +/** + * Property: originalOnImageLoadError + * {Function} Original onImageLoadError function. + */ +OpenLayers.Util.OSM.originalOnImageLoadError = OpenLayers.Util.onImageLoadError; + +/** + * Function: onImageLoadError + */ +OpenLayers.Util.onImageLoadError = function () { + if (this.src.match(/^http:\/\/[abc]\.[a-z]+\.openstreetmap\.org\//)) { + this.src = OpenLayers.Util.OSM.MISSING_TILE_URL; + } else if (this.src.match(/^http:\/\/[def]\.tah\.openstreetmap\.org\//)) { + // do nothing - this layer is transparent + } else { + OpenLayers.Util.OSM.originalOnImageLoadError; + } +}; + +/** + * Class: OpenLayers.Layer.OSM.Mapnik + * + * Inherits from: + * - + */ +OpenLayers.Layer.OSM.Mapnik = OpenLayers.Class(OpenLayers.Layer.OSM, { + /** + * Constructor: OpenLayers.Layer.OSM.Mapnik + * + * Parameters: + * name - {String} + * options - {Object} Hashtable of extra options to tag onto the layer + */ + initialize: function (name, options) { + var url = [ + "http://a.tile.openstreetmap.org/${z}/${x}/${y}.png", + "http://b.tile.openstreetmap.org/${z}/${x}/${y}.png", + "http://c.tile.openstreetmap.org/${z}/${x}/${y}.png" + ]; + options = OpenLayers.Util.extend({ + numZoomLevels: 19, + buffer: 0, + transitionEffect: "resize" + }, options); + var newArguments = [name, url, options]; + OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments); + }, + + CLASS_NAME: "OpenLayers.Layer.OSM.Mapnik" +}); + +/** + * Class: OpenLayers.Layer.OSM.Osmarender + * + * Inherits from: + * - + */ +OpenLayers.Layer.OSM.Osmarender = OpenLayers.Class(OpenLayers.Layer.OSM, { + /** + * Constructor: OpenLayers.Layer.OSM.Osmarender + * + * Parameters: + * name - {String} + * options - {Object} Hashtable of extra options to tag onto the layer + */ + initialize: function (name, options) { + var url = [ + "http://a.tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png", + "http://b.tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png", + "http://c.tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png" + ]; + options = OpenLayers.Util.extend({ + numZoomLevels: 18, + buffer: 0, + transitionEffect: "resize" + }, options); + var newArguments = [name, url, options]; + OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments); + }, + + CLASS_NAME: "OpenLayers.Layer.OSM.Osmarender" +}); + +/** + * Class: OpenLayers.Layer.OSM.CycleMap + * + * Inherits from: + * - + */ +OpenLayers.Layer.OSM.CycleMap = OpenLayers.Class(OpenLayers.Layer.OSM, { + /** + * Constructor: OpenLayers.Layer.OSM.CycleMap + * + * Parameters: + * name - {String} + * options - {Object} Hashtable of extra options to tag onto the layer + */ + initialize: function (name, options) { + var url = [ + "http://a.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png", + "http://b.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png", + "http://c.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png" + ]; + options = OpenLayers.Util.extend({ + numZoomLevels: 19, + buffer: 0, + transitionEffect: "resize" + }, options); + var newArguments = [name, url, options]; + OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments); + }, + + CLASS_NAME: "OpenLayers.Layer.OSM.CycleMap" +}); diff --git a/phpMyAdmin/js/ajax.js b/phpMyAdmin/js/ajax.js new file mode 100644 index 0000000..2226514 --- /dev/null +++ b/phpMyAdmin/js/ajax.js @@ -0,0 +1,860 @@ +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * This object handles ajax requests for pages. It also + * handles the reloading of the main menu and scripts. + */ +var AJAX = { + /** + * @var bool active Whether we are busy + */ + active: false, + /** + * @var object source The object whose event initialized the request + */ + source: null, + /** + * @var object xhr A reference to the ajax request that is currently running + */ + xhr: null, + /** + * @var function Callback to execute after a successful request + * Used by PMA_commonFunctions from common.js + */ + _callback: function () {}, + /** + * @var bool _debug Makes noise in your Firebug console + */ + _debug: false, + /** + * @var object $msgbox A reference to a jQuery object that links to a message + * box that is generated by PMA_ajaxShowMessage() + */ + $msgbox: null, + /** + * Given the filename of a script, returns a hash to be + * used to refer to all the events registered for the file + * + * @param string key The filename for which to get the event name + * + * @return int + */ + hash: function (key) { + /* http://burtleburtle.net/bob/hash/doobs.html#one */ + key += ""; + var len = key.length, hash = 0, i = 0; + for (; i < len; ++i) { + hash += key.charCodeAt(i); + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + return Math.abs(hash); + }, + /** + * Registers an onload event for a file + * + * @param string file The filename for which to register the event + * @param function func The function to execute when the page is ready + * + * @return self For chaining + */ + registerOnload: function (file, func) { + var eventName = 'onload_' + AJAX.hash(file); + $(document).bind(eventName, func); + if (this._debug) { + console.log( + // no need to translate + "Registered event " + eventName + " for file " + file + ); + } + return this; + }, + /** + * Registers a teardown event for a file. This is useful to execute functions + * that unbind events for page elements that are about to be removed. + * + * @param string file The filename for which to register the event + * @param function func The function to execute when + * the page is about to be torn down + * + * @return self For chaining + */ + registerTeardown: function (file, func) { + var eventName = 'teardown_' + AJAX.hash(file); + $(document).bind(eventName, func); + if (this._debug) { + console.log( + // no need to translate + "Registered event " + eventName + " for file " + file + ); + } + return this; + }, + /** + * Called when a page has finished loading, once for every + * file that registered to the onload event of that file. + * + * @param string file The filename for which to fire the event + * + * @return void + */ + fireOnload: function (file) { + var eventName = 'onload_' + AJAX.hash(file); + $(document).trigger(eventName); + if (this._debug) { + console.log( + // no need to translate + "Fired event " + eventName + " for file " + file + ); + } + }, + /** + * Called just before a page is torn down, once for every + * file that registered to the teardown event of that file. + * + * @param string file The filename for which to fire the event + * + * @return void + */ + fireTeardown: function (file) { + var eventName = 'teardown_' + AJAX.hash(file); + $(document).triggerHandler(eventName); + if (this._debug) { + console.log( + // no need to translate + "Fired event " + eventName + " for file " + file + ); + } + }, + /** + * Event handler for clicks on links and form submissions + * + * @param object e Event data + * + * @return void + */ + requestHandler: function (event) { + // In some cases we don't want to handle the request here and either + // leave the browser deal with it natively (e.g: file download) + // or leave an existing ajax event handler present elsewhere deal with it + var href = $(this).attr('href'); + if (typeof event != 'undefined' && (event.shiftKey || event.ctrlKey)) { + return true; + } else if ($(this).attr('target')) { + return true; + } else if ($(this).hasClass('ajax') || $(this).hasClass('disableAjax')) { + return true; + } else if (href && href.match(/^#/)) { + return true; + } else if (href && href.match(/^mailto/)) { + return true; + } else if ($(this).hasClass('ui-datepicker-next') || + $(this).hasClass('ui-datepicker-prev') + ) { + return true; + } + + if (typeof event != 'undefined') { + event.preventDefault(); + event.stopImmediatePropagation(); + } + if (AJAX.active === true) { + // Cancel the old request if abortable, when the user requests + // something else. Otherwise silently bail out, as there is already + // a request well in progress. + if (AJAX.xhr) { + //In case of a link request, attempt aborting + AJAX.xhr.abort(); + if(AJAX.xhr.status === 0 && AJAX.xhr.statusText === 'abort') { + //If aborted + AJAX.$msgbox = PMA_ajaxShowMessage(PMA_messages.strAbortedRequest); + AJAX.active = false; + AJAX.xhr = null; + } else { + //If can't abort + return false; + } + } else { + //In case submitting a form, don't attempt aborting + return false; + } + } + + AJAX.source = $(this); + + $('html, body').animate({scrollTop: 0}, 'fast'); + + var isLink = !! href || false; + var url = isLink ? href : $(this).attr('action'); + var params = 'ajax_request=true&ajax_page_request=true'; + if (! isLink) { + params += '&' + $(this).serialize(); + } + // Add a list of menu hashes that we have in the cache to the request + params += AJAX.cache.menus.getRequestParam(); + + if (AJAX._debug) { + console.log("Loading: " + url); // no need to translate + } + + if (isLink) { + AJAX.active = true; + AJAX.$msgbox = PMA_ajaxShowMessage(); + //Save reference for the new link request + AJAX.xhr = $.get(url, params, AJAX.responseHandler); + } else { + /** + * Manually fire the onsubmit event for the form, if any. + * The event was saved in the jQuery data object by an onload + * handler defined below. Workaround for bug #3583316 + */ + var onsubmit = $(this).data('onsubmit'); + // Submit the request if there is no onsubmit handler + // or if it returns a value that evaluates to true + if (typeof onsubmit !== 'function' || onsubmit.apply(this, [event])) { + AJAX.active = true; + AJAX.$msgbox = PMA_ajaxShowMessage(); + $.post(url, params, AJAX.responseHandler); + } + } + }, + /** + * Called after the request that was initiated by this.requestHandler() + * has completed successfully or with a caught error. For completely + * failed requests or requests with uncaught errors, see the .ajaxError + * handler at the bottom of this file. + * + * To refer to self use 'AJAX', instead of 'this' as this function + * is called in the jQuery context. + * + * @param object e Event data + * + * @return void + */ + responseHandler: function (data) { + if (data.success) { + $table_clone = false; + PMA_ajaxRemoveMessage(AJAX.$msgbox); + + if (data._redirect) { + PMA_ajaxShowMessage(data._redirect, false); + AJAX.active = false; + AJAX.xhr = null; + return; + } + + AJAX.scriptHandler.reset(function () { + if (data._reloadNavigation) { + PMA_reloadNavigation(); + } + if (data._reloadQuerywindow) { + var params = data._reloadQuerywindow; + PMA_querywindow.reload( + params.db, + params.table, + params.sql_query + ); + } + if (data._focusQuerywindow) { + PMA_querywindow.focus( + data._focusQuerywindow + ); + } + if (data._title) { + $('title').replaceWith(data._title); + } + if (data._menu) { + AJAX.cache.menus.replace(data._menu); + AJAX.cache.menus.add(data._menuHash, data._menu); + } else if (data._menuHash) { + AJAX.cache.menus.replace(AJAX.cache.menus.get(data._menuHash)); + } + + // Remove all containers that may have + // been added outside of #page_content + $('body').children() + .not('#pma_navigation') + .not('#floating_menubar') + .not('#goto_pagetop') + .not('#page_content') + .not('#selflink') + .not('#session_debug') + .not('#pma_header') + .not('#pma_footer') + .not('#pma_demo') + .remove(); + // Replace #page_content with new content + if (data.message && data.message.length > 0) { + $('#page_content').replaceWith( + "
    " + data.message + "
    " + ); + PMA_highlightSQL($('#page_content')); + } + + if (data._selflink) { + $('#selflink > a').attr('href', data._selflink); + } + if (data._scripts) { + AJAX.scriptHandler.load(data._scripts, data._params.token); + } + if (data._selflink && data._scripts && data._menuHash && data._params) { + AJAX.cache.add( + data._selflink, + data._scripts, + data._menuHash, + data._params, + AJAX.source.attr('rel') + ); + } + if (data._params) { + PMA_commonParams.setAll(data._params); + } + if (data._displayMessage) { + $('#page_content').prepend(data._displayMessage); + PMA_highlightSQL($('#page_content')); + } + + $('#pma_errors').remove(); + if (data._errors) { + $('
    ', {id : 'pma_errors'}) + .insertAfter('#selflink') + .append(data._errors); + } + + if (typeof AJAX._callback === 'function') { + AJAX._callback.call(); + } + AJAX._callback = function () {}; + }); + } else { + PMA_ajaxShowMessage(data.error, false); + AJAX.active = false; + AJAX.xhr = null; + } + }, + /** + * This object is in charge of downloading scripts, + * keeping track of what's downloaded and firing + * the onload event for them when the page is ready. + */ + scriptHandler: { + /** + * @var array _scripts The list of files already downloaded + */ + _scripts: [], + /** + * @var array _scriptsToBeLoaded The list of files that + * need to be downloaded + */ + _scriptsToBeLoaded: [], + /** + * @var array _scriptsToBeFired The list of files for which + * to fire the onload event + */ + _scriptsToBeFired: [], + /** + * Records that a file has been downloaded + * + * @param string file The filename + * @param string fire Whether this file will be registering + * onload/teardown events + * + * @return self For chaining + */ + add: function (file, fire) { + this._scripts.push(file); + if (fire) { + // Record whether to fire any events for the file + // This is necessary to correctly tear down the initial page + this._scriptsToBeFired.push(file); + } + return this; + }, + /** + * Download a list of js files in one request + * + * @param array files An array of filenames and flags + * + * @return void + */ + load: function (files, token) { + var self = this; + self._scriptsToBeLoaded = []; + self._scriptsToBeFired = []; + for (var i in files) { + self._scriptsToBeLoaded.push(files[i].name); + if (files[i].fire) { + self._scriptsToBeFired.push(files[i].name); + } + } + // Generate a request string + var request = []; + var needRequest = false; + for (var index in self._scriptsToBeLoaded) { + var script = self._scriptsToBeLoaded[index]; + // Only for scripts that we don't already have + if ($.inArray(script, self._scripts) == -1) { + needRequest = true; + this.add(script); + request.push("scripts[]=" + script); + } + } + request.push("token=" + token); + request.push("call_done=1"); + // Download the composite js file, if necessary + if (needRequest) { + this.appendScript("js/get_scripts.js.php?" + request.join("&")); + } else { + self.done(); + } + }, + /** + * Called whenever all files are loaded + * + * @return void + */ + done: function () { + if (typeof ErrorReport !== 'undefined') { + ErrorReport.wrap_global_functions(); + } + for (var i in this._scriptsToBeFired) { + AJAX.fireOnload(this._scriptsToBeFired[i]); + } + AJAX.active = false; + }, + /** + * Appends a script element to the head to load the scripts + * + * @return void + */ + appendScript: function (url) { + var head = document.head || document.getElementsByTagName('head')[0]; + var script = document.createElement('script'); + script.type = 'text/javascript'; + script.src = url; + head.appendChild(script); + }, + /** + * Fires all the teardown event handlers for the current page + * and rebinds all forms and links to the request handler + * + * @param function callback The callback to call after resetting + * + * @return void + */ + reset: function (callback) { + for (var i in this._scriptsToBeFired) { + AJAX.fireTeardown(this._scriptsToBeFired[i]); + } + this._scriptsToBeFired = []; + /** + * Re-attach a generic event handler to clicks + * on pages and submissions of forms + */ + $('a').die('click').live('click', AJAX.requestHandler); + $('form').die('submit').live('submit', AJAX.requestHandler); + AJAX.cache.update(); + callback(); + } + } +}; + +/** + * Here we register a function that will remove the onsubmit event from all + * forms that will be handled by the generic page loader. We then save this + * event handler in the "jQuery data", so that we can fire it up later in + * AJAX.requestHandler(). + * + * See bug #3583316 + */ +AJAX.registerOnload('functions.js', function () { + // Registering the onload event for functions.js + // ensures that it will be fired for all pages + $('form').not('.ajax').not('.disableAjax').each(function () { + if ($(this).attr('onsubmit')) { + $(this).data('onsubmit', this.onsubmit).attr('onsubmit', ''); + } + }); +}); + +/** + * An implementation of a client-side page cache. + * This object also uses the cache to provide a simple microhistory, + * that is the ability to use the back and forward buttons in the browser + */ +AJAX.cache = { + /** + * @var int The maximum number of pages to keep in the cache + */ + MAX: 6, + /** + * @var object A hash used to prime the cache with data about the initially + * loaded page. This is set in the footer, and then loaded + * by a double-queued event further down this file. + */ + primer: {}, + /** + * @var array Stores the content of the cached pages + */ + pages: [], + /** + * @var int The index of the currently loaded page + * This is used to know at which point in the history we are + */ + current: 0, + /** + * Saves a new page in the cache + * + * @param string hash The hash part of the url that is being loaded + * @param array scripts A list of scripts that is requured for the page + * @param string menu A hash that links to a menu stored + * in a dedicated menu cache + * @param array params A list of parameters used by PMA_commonParams() + * @param string rel A relationship to the current page: + * 'samepage': Forces the response to be treated as + * the same page as the current one + * 'newpage': Forces the response to be treated as + * a new page + * undefined: Default behaviour, 'samepage' if the + * selflinks of the two pages are the same. + * 'newpage' otherwise + * + * @return void + */ + add: function (hash, scripts, menu, params, rel) { + if (this.pages.length > AJAX.cache.MAX) { + // Trim the cache, to the maximum number of allowed entries + // This way we will have a cached menu for every page + for (var i = 0; i < this.pages.length - this.MAX; i++) { + delete this.pages[i]; + } + } + while (this.current < this.pages.length) { + // trim the cache if we went back in the history + // and are now going forward again + this.pages.pop(); + } + if (rel === 'newpage' || + ( + typeof rel === 'undefined' && ( + typeof this.pages[this.current - 1] === 'undefined' || + this.pages[this.current - 1].hash !== hash + ) + ) + ) { + this.pages.push({ + hash: hash, + content: $('#page_content').html(), + scripts: scripts, + selflink: $('#selflink').html(), + menu: menu, + params: params + }); + AJAX.setUrlHash(this.current, hash); + this.current++; + } + }, + /** + * Restores a page from the cache. This is called when the hash + * part of the url changes and it's structure appears to be valid + * + * @param string index Which page from the history to load + * + * @return void + */ + navigate: function (index) { + if (typeof this.pages[index] === 'undefined' + || typeof this.pages[index].content === 'undefined' + || typeof this.pages[index].menu === 'undefined' + || ! AJAX.cache.menus.get(this.pages[index].menu) + ) { + PMA_ajaxShowMessage( + '
    ' + PMA_messages.strInvalidPage + '
    ', + false + ); + } else { + AJAX.active = true; + var record = this.pages[index]; + AJAX.scriptHandler.reset(function () { + $('#page_content').html(record.content); + $('#selflink').html(record.selflink); + AJAX.cache.menus.replace(AJAX.cache.menus.get(record.menu)); + PMA_commonParams.setAll(record.params); + AJAX.scriptHandler.load(record.scripts, record.params ? record.params.token : PMA_commonParams.get('token')); + AJAX.cache.current = ++index; + }); + } + }, + /** + * Resaves the content of the current page in the cache. + * Necessary in order not to show the user some outdated version of the page + * + * @return void + */ + update: function () { + var page = this.pages[this.current - 1]; + if (page) { + page.content = $('#page_content').html(); + } + }, + /** + * @var object Dedicated menu cache + */ + menus: { + /** + * Returns the number of items in an associative array + * + * @return int + */ + size: function (obj) { + var size = 0, key; + for (key in obj) { + if (obj.hasOwnProperty(key)) { + size++; + } + } + return size; + }, + /** + * @var hash Stores the content of the cached menus + */ + data: {}, + /** + * Saves a new menu in the cache + * + * @param string hash The hash (trimmed md5) of the menu to be saved + * @param string content The HTML code of the menu to be saved + * + * @return void + */ + add: function (hash, content) { + if (this.size(this.data) > AJAX.cache.MAX) { + // when the cache grows, we remove the oldest entry + var oldest, key, init = 0; + for (var i in this.data) { + if (this.data[i]) { + if (! init || this.data[i].timestamp.getTime() < oldest.getTime()) { + oldest = this.data[i].timestamp; + key = i; + init = 1; + } + } + } + delete this.data[key]; + } + this.data[hash] = { + content: content, + timestamp: new Date() + }; + }, + /** + * Retrieves a menu given its hash + * + * @param string hash The hash of the menu to be retrieved + * + * @return string + */ + get: function (hash) { + if (this.data[hash]) { + return this.data[hash].content; + } else { + // This should never happen as long as the number of stored menus + // is larger or equal to the number of pages in the page cache + return ''; + } + }, + /** + * Prepares part of the parameter string used during page requests, + * this is necessary to tell the server which menus we have in the cache + * + * @return string + */ + getRequestParam: function () { + var param = ''; + var menuHashes = []; + for (var i in this.data) { + menuHashes.push(i); + } + var menuHashesParam = menuHashes.join('-'); + if (menuHashesParam) { + param = '&menuHashes=' + menuHashesParam; + } + return param; + }, + /** + * Replaces the menu with new content + * + * @return void + */ + replace: function (content) { + $('#floating_menubar').html(content) + // Remove duplicate wrapper + // TODO: don't send it in the response + .children().first().remove(); + $('#topmenu').menuResizer(PMA_mainMenuResizerCallback); + } + } +}; + +/** + * URL hash management module. + * Allows direct bookmarking and microhistory. + */ +AJAX.setUrlHash = (function (jQuery, window) { + "use strict"; + /** + * Indictaes whether we have already completed + * the initialisation of the hash + * + * @access private + */ + var ready = false; + /** + * Stores a hash that needed to be set when we were not ready + * + * @access private + */ + var savedHash = ""; + /** + * Flag to indicate if the change of hash was triggered + * by a user pressing the back/forward button or if + * the change was triggered internally + * + * @access private + */ + var userChange = true; + + // Fix favicon disappearing in Firefox when setting location.hash + function resetFavicon() { + if (jQuery.browser.mozilla) { + // Move the link tags for the favicon to the bottom + // of the head element to force a reload of the favicon + $('head > link[href=favicon\\.ico]').appendTo('head'); + } + } + + /** + * Sets the hash part of the URL + * + * @access public + */ + function setUrlHash(index, hash) { + /* + * Known problem: + * Setting hash leads to reload in webkit: + * http://www.quirksmode.org/bugreports/archives/2005/05/Safari_13_visual_anomaly_with_windowlocationhref.html + * + * so we expect that users are not running an ancient Safari version + */ + + userChange = false; + if (ready) { + window.location.hash = "PMAURL-" + index + ":" + hash; + resetFavicon(); + } else { + savedHash = "PMAURL-" + index + ":" + hash; + } + } + /** + * Start initialisation + */ + if (window.location.hash.substring(0, 8) == '#PMAURL-') { + // We have a valid hash, let's redirect the user + // to the page that it's pointing to + window.location = window.location.hash.substring( + window.location.hash.indexOf(':') + 1 + ); + } else { + // We don't have a valid hash, so we'll set it up + // when the page finishes loading + jQuery(function () { + /* Check if we should set URL */ + if (savedHash !== "") { + window.location.hash = savedHash; + savedHash = ""; + resetFavicon(); + } + // Indicate that we're done initialising + ready = true; + }); + } + /** + * Register an event handler for when the url hash changes + */ + jQuery(function () { + jQuery(window).hashchange(function () { + if (userChange === false) { + // Ignore internally triggered hash changes + userChange = true; + } else if (/^#PMAURL-\d+:/.test(window.location.hash)) { + // Change page if the hash changed was triggered by a user action + var index = window.location.hash.substring( + 8, window.location.hash.indexOf(':') + ); + AJAX.cache.navigate(index); + } + }); + }); + /** + * Publicly exposes a reference to the otherwise private setUrlHash function + */ + return setUrlHash; +})(jQuery, window); + +/** + * Page load event handler + */ +$(function () { + // Add the menu from the initial page into the cache + // The cache primer is set by the footer class + if (AJAX.cache.primer.url) { + AJAX.cache.menus.add( + AJAX.cache.primer.menuHash, + $('
    ') + .append('
    ') + .append($('#serverinfo').clone()) + .append($('#topmenucontainer').clone()) + .html() + ); + } + $(function () { + // Queue up this event twice to make sure that we get a copy + // of the page after all other onload events have been fired + if (AJAX.cache.primer.url) { + AJAX.cache.add( + AJAX.cache.primer.url, + AJAX.cache.primer.scripts, + AJAX.cache.primer.menuHash + ); + } + }); +}); + +/** + * Attach a generic event handler to clicks + * on pages and submissions of forms + */ +$('a').live('click', AJAX.requestHandler); +$('form').live('submit', AJAX.requestHandler); + +/** + * Gracefully handle fatal server errors + * (e.g: 500 - Internal server error) + */ +$(document).ajaxError(function (event, request, settings) { + if (request.status !== 0) { // Don't handle aborted requests + var errorCode = $.sprintf(PMA_messages.strErrorCode, request.status); + var errorText = $.sprintf(PMA_messages.strErrorText, request.statusText); + PMA_ajaxShowMessage( + '
    ' + + PMA_messages.strErrorProcessingRequest + + '
    ' + errorCode + '
    ' + + '
    ' + errorText + '
    ' + + '
    ', + false + ); + AJAX.active = false; + } +}); diff --git a/phpMyAdmin/js/canvg/canvg.js b/phpMyAdmin/js/canvg/canvg.js index 326880f..dbc5a9d 100644 --- a/phpMyAdmin/js/canvg/canvg.js +++ b/phpMyAdmin/js/canvg/canvg.js @@ -1,98 +1,2509 @@ /* - Use it if you like it -*/ -if(!window.console){window.console={};window.console.log=function(){};window.console.dir=function(){}}if(!Array.indexOf)Array.prototype.indexOf=function(r){for(var b=0;b]*>/,"");var c=new ActiveXObject("Microsoft.XMLDOM");c.async="false";c.loadXML(e);return c}};b.Property=function(e,c){this.name=e;this.value=c;this.hasValue=function(){return this.value!=null&&this.value!=""};this.numValue=function(){if(!this.hasValue())return 0;var f=parseFloat(this.value);if((this.value+"").match(/%$/))f/= -100;return f};this.valueOrDefault=function(f){if(this.hasValue())return this.value;return f};this.numValueOrDefault=function(f){if(this.hasValue())return this.numValue();return f};var a=this;this.Color={addOpacity:function(f){var d=a.value;if(f!=null&&f!=""){var g=new RGBColor(a.value);if(g.ok)d="rgba("+g.r+", "+g.g+", "+g.b+", "+f+")"}return new b.Property(a.name,d)}};this.Definition={getDefinition:function(){var f=a.value.replace(/^(url\()?#([^\)]+)\)?$/,"$2");return b.Definitions[f]},isUrl:function(){return a.value.indexOf("url(")== -0},getFillStyle:function(f){var d=this.getDefinition();if(d!=null&&d.createGradient)return d.createGradient(b.ctx,f);if(d!=null&&d.createPattern)return d.createPattern(b.ctx,f);return null}};this.Length={DPI:function(){return 96},EM:function(f){var d=12,g=new b.Property("fontSize",b.Font.Parse(b.ctx.font).fontSize);if(g.hasValue())d=g.Length.toPixels(f);return d},toPixels:function(f){if(!a.hasValue())return 0;var d=a.value+"";if(d.match(/em$/))return a.numValue()*this.EM(f);if(d.match(/ex$/))return a.numValue()* -this.EM(f)/2;if(d.match(/px$/))return a.numValue();if(d.match(/pt$/))return a.numValue()*1.25;if(d.match(/pc$/))return a.numValue()*15;if(d.match(/cm$/))return a.numValue()*this.DPI(f)/2.54;if(d.match(/mm$/))return a.numValue()*this.DPI(f)/25.4;if(d.match(/in$/))return a.numValue()*this.DPI(f);if(d.match(/%$/))return a.numValue()*b.ViewPort.ComputeSize(f);return a.numValue()}};this.Time={toMilliseconds:function(){if(!a.hasValue())return 0;var f=a.value+"";if(f.match(/s$/))return a.numValue()*1E3; -if(f.match(/ms$/))return a.numValue();return a.numValue()}};this.Angle={toRadians:function(){if(!a.hasValue())return 0;var f=a.value+"";if(f.match(/deg$/))return a.numValue()*(Math.PI/180);if(f.match(/grad$/))return a.numValue()*(Math.PI/200);if(f.match(/rad$/))return a.numValue();return a.numValue()*(Math.PI/180)}}};b.Font=new function(){this.Styles=["normal","italic","oblique","inherit"];this.Variants=["normal","small-caps","inherit"];this.Weights=["normal","bold","bolder","lighter","100","200", -"300","400","500","600","700","800","900","inherit"];this.CreateFont=function(c,a,f,d,g,h){h=h!=null?this.Parse(h):this.CreateFont("","","","","",b.ctx.font);return{fontFamily:g||h.fontFamily,fontSize:d||h.fontSize,fontStyle:c||h.fontStyle,fontWeight:f||h.fontWeight,fontVariant:a||h.fontVariant,toString:function(){return[this.fontStyle,this.fontVariant,this.fontWeight,this.fontSize,this.fontFamily].join(" ")}}};var e=this;this.Parse=function(c){var a={};c=b.trim(b.compressSpaces(c||"")).split(" "); -for(var f={fontSize:false,fontStyle:false,fontWeight:false,fontVariant:false},d="",g=0;gthis.x2)this.x2=d}if(g!=null){if(isNaN(this.y1)||isNaN(this.y2))this.y2=this.y1=g;if(gthis.y2)this.y2=g}};this.addX=function(d){this.addPoint(d,null)};this.addY=function(d){this.addPoint(null,d)};this.addBoundingBox=function(d){this.addPoint(d.x1,d.y1);this.addPoint(d.x2,d.y2)};this.addQuadraticCurve=function(d,g,h,j,k,l){h=d+2/3*(h-d);j=g+2/3*(j-g);this.addBezierCurve(d,g,h,h+1/3*(k-d),j,j+1/3*(l-g),k,l)};this.addBezierCurve=function(d, -g,h,j,k,l,p,m){var o=[d,g],n=[h,j],q=[k,l],u=[p,m];this.addPoint(o[0],o[1]);this.addPoint(u[0],u[1]);for(i=0;i<=1;i++){d=function(s){return Math.pow(1-s,3)*o[i]+3*Math.pow(1-s,2)*s*n[i]+3*(1-s)*Math.pow(s,2)*q[i]+Math.pow(s,3)*u[i]};g=6*o[i]-12*n[i]+6*q[i];h=-3*o[i]+9*n[i]-9*q[i]+3*u[i];j=3*n[i]-3*o[i];if(h==0){if(g!=0){g=-j/g;if(0=this.tokens.length-1};this.isCommandOrEnd=function(){if(this.isEnd())return true;return this.tokens[this.i+1].match(/[A-Za-z]/)!=null};this.isRelativeCommand=function(){return this.command==this.command.toLowerCase()};this.getToken=function(){this.i+=1;return this.tokens[this.i]};this.getScalar=function(){return parseFloat(this.getToken())};this.nextCommand=function(){this.previousCommand=this.command;this.command= -this.getToken()};this.getPoint=function(){return this.makeAbsolute(new b.Point(this.getScalar(),this.getScalar()))};this.getAsControlPoint=function(){var a=this.getPoint();return this.control=a};this.getAsCurrentPoint=function(){var a=this.getPoint();return this.current=a};this.getReflectedControlPoint=function(){if(this.previousCommand.toLowerCase()!="c"&&this.previousCommand.toLowerCase()!="s")return this.current;return new b.Point(2*this.current.x-this.control.x,2*this.current.y-this.control.y)}; -this.makeAbsolute=function(a){if(this.isRelativeCommand()){a.x=this.current.x+a.x;a.y=this.current.y+a.y}return a};this.addMarker=function(a,f){this.addMarkerAngle(a,f==null?null:f.angleTo(a))};this.addMarkerAngle=function(a,f){this.points.push(a);this.angles.push(f)};this.getMarkerPoints=function(){return this.points};this.getMarkerAngles=function(){for(var a=0;a1){k*=Math.sqrt(o);l*=Math.sqrt(o)}p=(p==j?-1:1)*Math.sqrt((Math.pow(k,2)*Math.pow(l,2)-Math.pow(k,2)*Math.pow(m.y,2)-Math.pow(l,2)*Math.pow(m.x,2))/(Math.pow(k,2)*Math.pow(m.y,2)+Math.pow(l, -2)*Math.pow(m.x,2)));if(isNaN(p))p=0;var n=new b.Point(p*k*m.y/l,p*-l*m.x/k);h=new b.Point((h.x+d.x)/2+Math.cos(g)*n.x-Math.sin(g)*n.y,(h.y+d.y)/2+Math.sin(g)*n.x+Math.cos(g)*n.y);var q=function(s,t){return(s[0]*t[0]+s[1]*t[1])/(Math.sqrt(Math.pow(s[0],2)+Math.pow(s[1],2))*Math.sqrt(Math.pow(t[0],2)+Math.pow(t[1],2)))},u=function(s,t){return(s[0]*t[1]=1)m=0;if(j==0&&m>0)m-=2*Math.PI;if(j==1&&m<0)m+=2*Math.PI;o=new b.Point(h.x-k*Math.cos((p+m)/2),h.y-l*Math.sin((p+m)/2));a.addMarkerAngle(o,(p+m)/2+(j==0?1:-1)*Math.PI/2);a.addMarkerAngle(d,m+(j==0?1:-1)*Math.PI/2);f.addPoint(d.x,d.y);if(c!=null){q=k>l?k:l;d=k>l?1:k/l;k=k>l?l/k:1;c.translate(h.x,h.y);c.rotate(g);c.scale(d,k);c.arc(0,0,q,p,p+m,1-j);c.scale(1/d,1/k);c.rotate(-g);c.translate(-h.x,-h.y)}}break;case "Z":c!=null&&c.closePath();a.current=a.start}}return f}};this.getMarkers= -function(){for(var c=this.PathParser.getMarkerPoints(),a=this.PathParser.getMarkerAngles(),f=[],d=0;dthis.maxDuration)if(this.attribute("repeatCount").value=="indefinite")this.duration=0;else if(this.attribute("fill").valueOrDefault("remove")=="remove"&&!this.removed){this.removed=true;this.getProperty().value=this.initialValue;return true}else return false;this.duration+=c;c=false;if(this.begin255?255:this.r;this.g=this.g<0||isNaN(this.g)? -0:this.g>255?255:this.g;this.b=this.b<0||isNaN(this.b)?0:this.b>255?255:this.b;this.toRGB=function(){return"rgb("+this.r+", "+this.g+", "+this.b+")"};this.toHex=function(){var d=this.r.toString(16),g=this.g.toString(16),h=this.b.toString(16);if(d.length==1)d="0"+d;if(g.length==1)g="0"+g;if(h.length==1)h="0"+h;return"#"+d+g+h};this.getHelpXML=function(){for(var d=[],g=0;g "+p.toRGB()+" -> "+p.toHex());l.appendChild(m);l.appendChild(o);h.appendChild(l)}catch(n){}return h}}; + * canvg.js - Javascript SVG parser and renderer on Canvas + * MIT Licensed + * Gabe Lerner (gabelerner@gmail.com) + * http://code.google.com/p/canvg/ + * + * Requires: rgbcolor.js - http://www.phpied.com/rgb-color-parser-in-javascript/ + */ +if(!window.console) { + window.console = {}; + window.console.log = function(str) {}; + window.console.dir = function(str) {}; +} + +// <3 IE +if(!Array.indexOf){ + Array.prototype.indexOf = function(obj){ + for(var i=0; i ignore mouse events + // ignoreAnimation: true => ignore animations + // ignoreDimensions: true => does not try to resize canvas + // ignoreClear: true => does not clear canvas + // offsetX: int => draws at a x offset + // offsetY: int => draws at a y offset + // scaleWidth: int => scales horizontally to width + // scaleHeight: int => scales vertically to height + // renderCallback: function => will call the function after the first render is completed + // forceRedraw: function => will call the function on every frame, if it returns true, will redraw + this.canvg = function (target, s, opts) { + // no parameters + if (target == null && s == null && opts == null) { + var svgTags = document.getElementsByTagName('svg'); + for (var i=0; i]*>/, ''); + var xmlDoc = new ActiveXObject('Microsoft.XMLDOM'); + xmlDoc.async = 'false'; + xmlDoc.loadXML(xml); + return xmlDoc; + } + } + + svg.Property = function(name, value) { + this.name = name; + this.value = value; + + this.hasValue = function() { + return (this.value != null && this.value != ''); + } + + // return the numerical value of the property + this.numValue = function() { + if (!this.hasValue()) return 0; + + var n = parseFloat(this.value); + if ((this.value + '').match(/%$/)) { + n = n / 100.0; + } + return n; + } + + this.valueOrDefault = function(def) { + if (this.hasValue()) return this.value; + return def; + } + + this.numValueOrDefault = function(def) { + if (this.hasValue()) return this.numValue(); + return def; + } + + /* EXTENSIONS */ + var that = this; + + // color extensions + this.Color = { + // augment the current color value with the opacity + addOpacity: function(opacity) { + var newValue = that.value; + if (opacity != null && opacity != '') { + var color = new RGBColor(that.value); + if (color.ok) { + newValue = 'rgba(' + color.r + ', ' + color.g + ', ' + color.b + ', ' + opacity + ')'; + } + } + return new svg.Property(that.name, newValue); + } + } + + // definition extensions + this.Definition = { + // get the definition from the definitions table + getDefinition: function() { + var name = that.value.replace(/^(url\()?#([^\)]+)\)?$/, '$2'); + return svg.Definitions[name]; + }, + + isUrl: function() { + return that.value.indexOf('url(') == 0 + }, + + getFillStyle: function(e) { + var def = this.getDefinition(); + + // gradient + if (def != null && def.createGradient) { + return def.createGradient(svg.ctx, e); + } + + // pattern + if (def != null && def.createPattern) { + return def.createPattern(svg.ctx, e); + } + + return null; + } + } + + // length extensions + this.Length = { + DPI: function(viewPort) { + return 96.0; // TODO: compute? + }, + + EM: function(viewPort) { + var em = 12; + + var fontSize = new svg.Property('fontSize', svg.Font.Parse(svg.ctx.font).fontSize); + if (fontSize.hasValue()) em = fontSize.Length.toPixels(viewPort); + + return em; + }, + + // get the length as pixels + toPixels: function(viewPort) { + if (!that.hasValue()) return 0; + var s = that.value+''; + if (s.match(/em$/)) return that.numValue() * this.EM(viewPort); + if (s.match(/ex$/)) return that.numValue() * this.EM(viewPort) / 2.0; + if (s.match(/px$/)) return that.numValue(); + if (s.match(/pt$/)) return that.numValue() * 1.25; + if (s.match(/pc$/)) return that.numValue() * 15; + if (s.match(/cm$/)) return that.numValue() * this.DPI(viewPort) / 2.54; + if (s.match(/mm$/)) return that.numValue() * this.DPI(viewPort) / 25.4; + if (s.match(/in$/)) return that.numValue() * this.DPI(viewPort); + if (s.match(/%$/)) return that.numValue() * svg.ViewPort.ComputeSize(viewPort); + return that.numValue(); + } + } + + // time extensions + this.Time = { + // get the time as milliseconds + toMilliseconds: function() { + if (!that.hasValue()) return 0; + var s = that.value+''; + if (s.match(/s$/)) return that.numValue() * 1000; + if (s.match(/ms$/)) return that.numValue(); + return that.numValue(); + } + } + + // angle extensions + this.Angle = { + // get the angle as radians + toRadians: function() { + if (!that.hasValue()) return 0; + var s = that.value+''; + if (s.match(/deg$/)) return that.numValue() * (Math.PI / 180.0); + if (s.match(/grad$/)) return that.numValue() * (Math.PI / 200.0); + if (s.match(/rad$/)) return that.numValue(); + return that.numValue() * (Math.PI / 180.0); + } + } + } + + // fonts + svg.Font = new (function() { + this.Styles = ['normal','italic','oblique','inherit']; + this.Variants = ['normal','small-caps','inherit']; + this.Weights = ['normal','bold','bolder','lighter','100','200','300','400','500','600','700','800','900','inherit']; + + this.CreateFont = function(fontStyle, fontVariant, fontWeight, fontSize, fontFamily, inherit) { + var f = inherit != null ? this.Parse(inherit) : this.CreateFont('', '', '', '', '', svg.ctx.font); + return { + fontFamily: fontFamily || f.fontFamily, + fontSize: fontSize || f.fontSize, + fontStyle: fontStyle || f.fontStyle, + fontWeight: fontWeight || f.fontWeight, + fontVariant: fontVariant || f.fontVariant, + toString: function () { return [this.fontStyle, this.fontVariant, this.fontWeight, this.fontSize, this.fontFamily].join(' ') } + } + } + + var that = this; + this.Parse = function(s) { + var f = {}; + var d = svg.trim(svg.compressSpaces(s || '')).split(' '); + var set = { fontSize: false, fontStyle: false, fontWeight: false, fontVariant: false } + var ff = ''; + for (var i=0; i this.x2) this.x2 = x; + } + + if (y != null) { + if (isNaN(this.y1) || isNaN(this.y2)) { + this.y1 = y; + this.y2 = y; + } + if (y < this.y1) this.y1 = y; + if (y > this.y2) this.y2 = y; + } + } + this.addX = function(x) { this.addPoint(x, null); } + this.addY = function(y) { this.addPoint(null, y); } + + this.addBoundingBox = function(bb) { + this.addPoint(bb.x1, bb.y1); + this.addPoint(bb.x2, bb.y2); + } + + this.addQuadraticCurve = function(p0x, p0y, p1x, p1y, p2x, p2y) { + var cp1x = p0x + 2/3 * (p1x - p0x); // CP1 = QP0 + 2/3 *(QP1-QP0) + var cp1y = p0y + 2/3 * (p1y - p0y); // CP1 = QP0 + 2/3 *(QP1-QP0) + var cp2x = cp1x + 1/3 * (p2x - p0x); // CP2 = CP1 + 1/3 *(QP2-QP0) + var cp2y = cp1y + 1/3 * (p2y - p0y); // CP2 = CP1 + 1/3 *(QP2-QP0) + this.addBezierCurve(p0x, p0y, cp1x, cp2x, cp1y, cp2y, p2x, p2y); + } + + this.addBezierCurve = function(p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y) { + // from http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html + var p0 = [p0x, p0y], p1 = [p1x, p1y], p2 = [p2x, p2y], p3 = [p3x, p3y]; + this.addPoint(p0[0], p0[1]); + this.addPoint(p3[0], p3[1]); + + for (i=0; i<=1; i++) { + var f = function(t) { + return Math.pow(1-t, 3) * p0[i] + + 3 * Math.pow(1-t, 2) * t * p1[i] + + 3 * (1-t) * Math.pow(t, 2) * p2[i] + + Math.pow(t, 3) * p3[i]; + } + + var b = 6 * p0[i] - 12 * p1[i] + 6 * p2[i]; + var a = -3 * p0[i] + 9 * p1[i] - 9 * p2[i] + 3 * p3[i]; + var c = 3 * p1[i] - 3 * p0[i]; + + if (a == 0) { + if (b == 0) continue; + var t = -c / b; + if (0 < t && t < 1) { + if (i == 0) this.addX(f(t)); + if (i == 1) this.addY(f(t)); + } + continue; + } + + var b2ac = Math.pow(b, 2) - 4 * c * a; + if (b2ac < 0) continue; + var t1 = (-b + Math.sqrt(b2ac)) / (2 * a); + if (0 < t1 && t1 < 1) { + if (i == 0) this.addX(f(t1)); + if (i == 1) this.addY(f(t1)); + } + var t2 = (-b - Math.sqrt(b2ac)) / (2 * a); + if (0 < t2 && t2 < 1) { + if (i == 0) this.addX(f(t2)); + if (i == 1) this.addY(f(t2)); + } + } + } + + this.isPointInBox = function(x, y) { + return (this.x1 <= x && x <= this.x2 && this.y1 <= y && y <= this.y2); + } + + this.addPoint(x1, y1); + this.addPoint(x2, y2); + } + + // transforms + svg.Transform = function(v) { + var that = this; + this.Type = {} + + // translate + this.Type.translate = function(s) { + this.p = svg.CreatePoint(s); + this.apply = function(ctx) { + ctx.translate(this.p.x || 0.0, this.p.y || 0.0); + } + this.applyToPoint = function(p) { + p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]); + } + } + + // rotate + this.Type.rotate = function(s) { + var a = svg.ToNumberArray(s); + this.angle = new svg.Property('angle', a[0]); + this.cx = a[1] || 0; + this.cy = a[2] || 0; + this.apply = function(ctx) { + ctx.translate(this.cx, this.cy); + ctx.rotate(this.angle.Angle.toRadians()); + ctx.translate(-this.cx, -this.cy); + } + this.applyToPoint = function(p) { + var a = this.angle.Angle.toRadians(); + p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]); + p.applyTransform([Math.cos(a), Math.sin(a), -Math.sin(a), Math.cos(a), 0, 0]); + p.applyTransform([1, 0, 0, 1, -this.p.x || 0.0, -this.p.y || 0.0]); + } + } + + this.Type.scale = function(s) { + this.p = svg.CreatePoint(s); + this.apply = function(ctx) { + ctx.scale(this.p.x || 1.0, this.p.y || this.p.x || 1.0); + } + this.applyToPoint = function(p) { + p.applyTransform([this.p.x || 0.0, 0, 0, this.p.y || 0.0, 0, 0]); + } + } + + this.Type.matrix = function(s) { + this.m = svg.ToNumberArray(s); + this.apply = function(ctx) { + ctx.transform(this.m[0], this.m[1], this.m[2], this.m[3], this.m[4], this.m[5]); + } + this.applyToPoint = function(p) { + p.applyTransform(this.m); + } + } + + this.Type.SkewBase = function(s) { + this.base = that.Type.matrix; + this.base(s); + this.angle = new svg.Property('angle', s); + } + this.Type.SkewBase.prototype = new this.Type.matrix; + + this.Type.skewX = function(s) { + this.base = that.Type.SkewBase; + this.base(s); + this.m = [1, 0, Math.tan(this.angle.Angle.toRadians()), 1, 0, 0]; + } + this.Type.skewX.prototype = new this.Type.SkewBase; + + this.Type.skewY = function(s) { + this.base = that.Type.SkewBase; + this.base(s); + this.m = [1, Math.tan(this.angle.Angle.toRadians()), 0, 1, 0, 0]; + } + this.Type.skewY.prototype = new this.Type.SkewBase; + + this.transforms = []; + + this.apply = function(ctx) { + for (var i=0; i= this.tokens.length - 1; + } + + this.isCommandOrEnd = function() { + if (this.isEnd()) return true; + return this.tokens[this.i + 1].match(/[A-Za-z]/) != null; + } + + this.isRelativeCommand = function() { + return this.command == this.command.toLowerCase(); + } + + this.getToken = function() { + this.i = this.i + 1; + return this.tokens[this.i]; + } + + this.getScalar = function() { + return parseFloat(this.getToken()); + } + + this.nextCommand = function() { + this.previousCommand = this.command; + this.command = this.getToken(); + } + + this.getPoint = function() { + var p = new svg.Point(this.getScalar(), this.getScalar()); + return this.makeAbsolute(p); + } + + this.getAsControlPoint = function() { + var p = this.getPoint(); + this.control = p; + return p; + } + + this.getAsCurrentPoint = function() { + var p = this.getPoint(); + this.current = p; + return p; + } + + this.getReflectedControlPoint = function() { + if (this.previousCommand.toLowerCase() != 'c' && this.previousCommand.toLowerCase() != 's') { + return this.current; + } + + // reflect point + var p = new svg.Point(2 * this.current.x - this.control.x, 2 * this.current.y - this.control.y); + return p; + } + + this.makeAbsolute = function(p) { + if (this.isRelativeCommand()) { + p.x = this.current.x + p.x; + p.y = this.current.y + p.y; + } + return p; + } + + this.addMarker = function(p, from) { + this.addMarkerAngle(p, from == null ? null : from.angleTo(p)); + } + + this.addMarkerAngle = function(p, a) { + this.points.push(p); + this.angles.push(a); + } + + this.getMarkerPoints = function() { return this.points; } + this.getMarkerAngles = function() { + for (var i=0; i 1) { + rx *= Math.sqrt(l); + ry *= Math.sqrt(l); + } + // cx', cy' + var s = (largeArcFlag == sweepFlag ? -1 : 1) * Math.sqrt( + ((Math.pow(rx,2)*Math.pow(ry,2))-(Math.pow(rx,2)*Math.pow(currp.y,2))-(Math.pow(ry,2)*Math.pow(currp.x,2))) / + (Math.pow(rx,2)*Math.pow(currp.y,2)+Math.pow(ry,2)*Math.pow(currp.x,2)) + ); + if (isNaN(s)) s = 0; + var cpp = new svg.Point(s * rx * currp.y / ry, s * -ry * currp.x / rx); + // cx, cy + var centp = new svg.Point( + (curr.x + cp.x) / 2.0 + Math.cos(xAxisRotation) * cpp.x - Math.sin(xAxisRotation) * cpp.y, + (curr.y + cp.y) / 2.0 + Math.sin(xAxisRotation) * cpp.x + Math.cos(xAxisRotation) * cpp.y + ); + // vector magnitude + var m = function(v) { return Math.sqrt(Math.pow(v[0],2) + Math.pow(v[1],2)); } + // ratio between two vectors + var r = function(u, v) { return (u[0]*v[0]+u[1]*v[1]) / (m(u)*m(v)) } + // angle between two vectors + var a = function(u, v) { return (u[0]*v[1] < u[1]*v[0] ? -1 : 1) * Math.acos(r(u,v)); } + // initial angle + var a1 = a([1,0], [(currp.x-cpp.x)/rx,(currp.y-cpp.y)/ry]); + // angle delta + var u = [(currp.x-cpp.x)/rx,(currp.y-cpp.y)/ry]; + var v = [(-currp.x-cpp.x)/rx,(-currp.y-cpp.y)/ry]; + var ad = a(u, v); + if (r(u,v) <= -1) ad = Math.PI; + if (r(u,v) >= 1) ad = 0; + + if (sweepFlag == 0 && ad > 0) ad = ad - 2 * Math.PI; + if (sweepFlag == 1 && ad < 0) ad = ad + 2 * Math.PI; + + // for markers + var halfWay = new svg.Point( + centp.x - rx * Math.cos((a1 + ad) / 2), + centp.y - ry * Math.sin((a1 + ad) / 2) + ); + pp.addMarkerAngle(halfWay, (a1 + ad) / 2 + (sweepFlag == 0 ? 1 : -1) * Math.PI / 2); + pp.addMarkerAngle(cp, ad + (sweepFlag == 0 ? 1 : -1) * Math.PI / 2); + + bb.addPoint(cp.x, cp.y); // TODO: this is too naive, make it better + if (ctx != null) { + var r = rx > ry ? rx : ry; + var sx = rx > ry ? 1 : rx / ry; + var sy = rx > ry ? ry / rx : 1; + + ctx.translate(centp.x, centp.y); + ctx.rotate(xAxisRotation); + ctx.scale(sx, sy); + ctx.arc(0, 0, r, a1, a1 + ad, 1 - sweepFlag); + ctx.scale(1/sx, 1/sy); + ctx.rotate(-xAxisRotation); + ctx.translate(-centp.x, -centp.y); + } + } + break; + case 'Z': + if (ctx != null) ctx.closePath(); + pp.current = pp.start; + } + } + + return bb; + } + + this.getMarkers = function() { + var points = this.PathParser.getMarkerPoints(); + var angles = this.PathParser.getMarkerAngles(); + + var markers = []; + for (var i=0; i this.maxDuration) { + // loop for indefinitely repeating animations + if (this.attribute('repeatCount').value == 'indefinite') { + this.duration = 0.0 + } + else if (this.attribute('fill').valueOrDefault('remove') == 'remove' && !this.removed) { + this.removed = true; + this.getProperty().value = this.initialValue; + return true; + } + else { + return false; // no updates made + } + } + this.duration = this.duration + delta; + + // if we're past the begin time + var updated = false; + if (this.begin < this.duration) { + var newValue = this.calcValue(); // tween + + if (this.attribute('type').hasValue()) { + // for transform, etc. + var type = this.attribute('type').value; + newValue = type + '(' + newValue + ')'; + } + + this.getProperty().value = newValue; + updated = true; + } + + return updated; + } + + // fraction of duration we've covered + this.progress = function() { + return ((this.duration - this.begin) / (this.maxDuration - this.begin)); + } + } + svg.Element.AnimateBase.prototype = new svg.Element.ElementBase; + + // animate element + svg.Element.animate = function(node) { + this.base = svg.Element.AnimateBase; + this.base(node); + + this.calcValue = function() { + var from = this.attribute('from').numValue(); + var to = this.attribute('to').numValue(); + + // tween value linearly + return from + (to - from) * this.progress(); + }; + } + svg.Element.animate.prototype = new svg.Element.AnimateBase; + + // animate color element + svg.Element.animateColor = function(node) { + this.base = svg.Element.AnimateBase; + this.base(node); + + this.calcValue = function() { + var from = new RGBColor(this.attribute('from').value); + var to = new RGBColor(this.attribute('to').value); + + if (from.ok && to.ok) { + // tween color linearly + var r = from.r + (to.r - from.r) * this.progress(); + var g = from.g + (to.g - from.g) * this.progress(); + var b = from.b + (to.b - from.b) * this.progress(); + return 'rgb('+parseInt(r,10)+','+parseInt(g,10)+','+parseInt(b,10)+')'; + } + return this.attribute('from').value; + }; + } + svg.Element.animateColor.prototype = new svg.Element.AnimateBase; + + // animate transform element + svg.Element.animateTransform = function(node) { + this.base = svg.Element.animate; + this.base(node); + } + svg.Element.animateTransform.prototype = new svg.Element.animate; + + // text element + svg.Element.text = function(node) { + this.base = svg.Element.RenderedElementBase; + this.base(node); + + if (node != null) { + // add children + this.children = []; + for (var i=0; i + * @link http://www.phpied.com/rgb-color-parser-in-javascript/ + * @license Use it if you like it + */ +function RGBColor(color_string) +{ + this.ok = false; + + // strip any leading # + if (color_string.charAt(0) == '#') { // remove # if any + color_string = color_string.substr(1,6); + } + + color_string = color_string.replace(/ /g,''); + color_string = color_string.toLowerCase(); + + // before getting into regexps, try simple matches + // and overwrite the input + var simple_colors = { + aliceblue: 'f0f8ff', + antiquewhite: 'faebd7', + aqua: '00ffff', + aquamarine: '7fffd4', + azure: 'f0ffff', + beige: 'f5f5dc', + bisque: 'ffe4c4', + black: '000000', + blanchedalmond: 'ffebcd', + blue: '0000ff', + blueviolet: '8a2be2', + brown: 'a52a2a', + burlywood: 'deb887', + cadetblue: '5f9ea0', + chartreuse: '7fff00', + chocolate: 'd2691e', + coral: 'ff7f50', + cornflowerblue: '6495ed', + cornsilk: 'fff8dc', + crimson: 'dc143c', + cyan: '00ffff', + darkblue: '00008b', + darkcyan: '008b8b', + darkgoldenrod: 'b8860b', + darkgray: 'a9a9a9', + darkgreen: '006400', + darkkhaki: 'bdb76b', + darkmagenta: '8b008b', + darkolivegreen: '556b2f', + darkorange: 'ff8c00', + darkorchid: '9932cc', + darkred: '8b0000', + darksalmon: 'e9967a', + darkseagreen: '8fbc8f', + darkslateblue: '483d8b', + darkslategray: '2f4f4f', + darkturquoise: '00ced1', + darkviolet: '9400d3', + deeppink: 'ff1493', + deepskyblue: '00bfff', + dimgray: '696969', + dodgerblue: '1e90ff', + feldspar: 'd19275', + firebrick: 'b22222', + floralwhite: 'fffaf0', + forestgreen: '228b22', + fuchsia: 'ff00ff', + gainsboro: 'dcdcdc', + ghostwhite: 'f8f8ff', + gold: 'ffd700', + goldenrod: 'daa520', + gray: '808080', + green: '008000', + greenyellow: 'adff2f', + honeydew: 'f0fff0', + hotpink: 'ff69b4', + indianred : 'cd5c5c', + indigo : '4b0082', + ivory: 'fffff0', + khaki: 'f0e68c', + lavender: 'e6e6fa', + lavenderblush: 'fff0f5', + lawngreen: '7cfc00', + lemonchiffon: 'fffacd', + lightblue: 'add8e6', + lightcoral: 'f08080', + lightcyan: 'e0ffff', + lightgoldenrodyellow: 'fafad2', + lightgrey: 'd3d3d3', + lightgreen: '90ee90', + lightpink: 'ffb6c1', + lightsalmon: 'ffa07a', + lightseagreen: '20b2aa', + lightskyblue: '87cefa', + lightslateblue: '8470ff', + lightslategray: '778899', + lightsteelblue: 'b0c4de', + lightyellow: 'ffffe0', + lime: '00ff00', + limegreen: '32cd32', + linen: 'faf0e6', + magenta: 'ff00ff', + maroon: '800000', + mediumaquamarine: '66cdaa', + mediumblue: '0000cd', + mediumorchid: 'ba55d3', + mediumpurple: '9370d8', + mediumseagreen: '3cb371', + mediumslateblue: '7b68ee', + mediumspringgreen: '00fa9a', + mediumturquoise: '48d1cc', + mediumvioletred: 'c71585', + midnightblue: '191970', + mintcream: 'f5fffa', + mistyrose: 'ffe4e1', + moccasin: 'ffe4b5', + navajowhite: 'ffdead', + navy: '000080', + oldlace: 'fdf5e6', + olive: '808000', + olivedrab: '6b8e23', + orange: 'ffa500', + orangered: 'ff4500', + orchid: 'da70d6', + palegoldenrod: 'eee8aa', + palegreen: '98fb98', + paleturquoise: 'afeeee', + palevioletred: 'd87093', + papayawhip: 'ffefd5', + peachpuff: 'ffdab9', + peru: 'cd853f', + pink: 'ffc0cb', + plum: 'dda0dd', + powderblue: 'b0e0e6', + purple: '800080', + red: 'ff0000', + rosybrown: 'bc8f8f', + royalblue: '4169e1', + saddlebrown: '8b4513', + salmon: 'fa8072', + sandybrown: 'f4a460', + seagreen: '2e8b57', + seashell: 'fff5ee', + sienna: 'a0522d', + silver: 'c0c0c0', + skyblue: '87ceeb', + slateblue: '6a5acd', + slategray: '708090', + snow: 'fffafa', + springgreen: '00ff7f', + steelblue: '4682b4', + tan: 'd2b48c', + teal: '008080', + thistle: 'd8bfd8', + tomato: 'ff6347', + turquoise: '40e0d0', + violet: 'ee82ee', + violetred: 'd02090', + wheat: 'f5deb3', + white: 'ffffff', + whitesmoke: 'f5f5f5', + yellow: 'ffff00', + yellowgreen: '9acd32' + }; + for (var key in simple_colors) { + if (color_string == key) { + color_string = simple_colors[key]; + } + } + // emd of simple type-in colors + + // array of color definition objects + var color_defs = [ + { + re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/, + example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'], + process: function (bits){ + return [ + parseInt(bits[1]), + parseInt(bits[2]), + parseInt(bits[3]) + ]; + } + }, + { + re: /^(\w{2})(\w{2})(\w{2})$/, + example: ['#00ff00', '336699'], + process: function (bits){ + return [ + parseInt(bits[1], 16), + parseInt(bits[2], 16), + parseInt(bits[3], 16) + ]; + } + }, + { + re: /^(\w{1})(\w{1})(\w{1})$/, + example: ['#fb0', 'f0f'], + process: function (bits){ + return [ + parseInt(bits[1] + bits[1], 16), + parseInt(bits[2] + bits[2], 16), + parseInt(bits[3] + bits[3], 16) + ]; + } + } + ]; + + // search through the definitions to find a match + for (var i = 0; i < color_defs.length; i++) { + var re = color_defs[i].re; + var processor = color_defs[i].process; + var bits = re.exec(color_string); + if (bits) { + channels = processor(bits); + this.r = channels[0]; + this.g = channels[1]; + this.b = channels[2]; + this.ok = true; + } + + } + + // validate/cleanup values + this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r); + this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g); + this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b); + + // some getters + this.toRGB = function () { + return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')'; + } + this.toHex = function () { + var r = this.r.toString(16); + var g = this.g.toString(16); + var b = this.b.toString(16); + if (r.length == 1) r = '0' + r; + if (g.length == 1) g = '0' + g; + if (b.length == 1) b = '0' + b; + return '#' + r + g + b; + } + + // help + this.getHelpXML = function () { + + var examples = new Array(); + // add regexps + for (var i = 0; i < color_defs.length; i++) { + var example = color_defs[i].example; + for (var j = 0; j < example.length; j++) { + examples[examples.length] = example[j]; + } + } + // add type-in colors + for (var sc in simple_colors) { + examples[examples.length] = sc; + } + + var xml = document.createElement('ul'); + xml.setAttribute('id', 'rgbcolor-examples'); + for (var i = 0; i < examples.length; i++) { + try { + var list_item = document.createElement('li'); + var list_color = new RGBColor(examples[i]); + var example_div = document.createElement('div'); + example_div.style.cssText = + 'margin: 3px; ' + + 'border: 1px solid black; ' + + 'background:' + list_color.toHex() + '; ' + + 'color:' + list_color.toHex() + ; + example_div.appendChild(document.createTextNode('test')); + var list_item_value = document.createTextNode( + ' ' + examples[i] + ' -> ' + list_color.toRGB() + ' -> ' + list_color.toHex() + ); + list_item.appendChild(example_div); + list_item.appendChild(list_item_value); + xml.appendChild(list_item); + + } catch(e){} + } + return xml; + + } + +} \ No newline at end of file diff --git a/phpMyAdmin/js/canvg/flashcanvas.js b/phpMyAdmin/js/canvg/flashcanvas.js deleted file mode 100644 index b1db6e2..0000000 --- a/phpMyAdmin/js/canvg/flashcanvas.js +++ /dev/null @@ -1,25 +0,0 @@ -window.ActiveXObject&&!window.CanvasRenderingContext2D&&function(h,j,D){function A(){if(j.readyState==="complete"){j.detachEvent(E,A);for(var a=j.getElementsByTagName(r),b=0,c=a.length;b=8?a.src:a.getAttribute("src",4)}function t(a){return(""+a).replace(/&/g,"&").replace(/0)return eval(this._swf.CallFunction(''+a.join("�")+""))},_resize:function(a,b){this._executeCommand();this._initialize();if(a>0)this._swf.width=a;if(b>0)this._swf.height=b;this._queue.push(e.resize, -a,b)}};var y=function(a){this._ctx=a;this.id=a._gradientPatternId++};y.prototype={addColorStop:function(a,b){if(isNaN(a)||a<0||a>1)i(1);this._ctx._queue.push(e.addColorStop,this.id,a,b)}};var R=function(a){this.id=a._gradientPatternId++},W=function(a){this.width=a},P=function(a){this.code=a;this.message=X[a]};P.prototype=Error();var X={1:"INDEX_SIZE_ERR",9:"NOT_SUPPORTED_ERR",11:"INVALID_STATE_ERR",12:"SYNTAX_ERR",17:"TYPE_MISMATCH_ERR",18:"SECURITY_ERR"},B={initElement:function(a){if(a.getContext)return a; -var b=Math.random().toString(36).slice(2)||"0",c="external"+b;v[b]=false;n[b]=1;Q(a);a.innerHTML=''; -s[b]=a;var d=a.firstChild;w[b]=a.lastChild;var f=j.body.contains;if(f(a))d.movie=u;else var g=setInterval(function(){if(f(a)){clearInterval(g);d.movie=u}},0);if(j.compatMode==="BackCompat"||!h.XMLHttpRequest)w[b].style.overflow="hidden";var o=new x(a,d);a.getContext=function(l){return l==="2d"?o:k};a.toDataURL=function(l,z){(""+l).replace(/[A-Z]+/g,V)==="image/jpeg"?o._queue.push(e.toDataURL,l,typeof z==="number"?z:""):o._queue.push(e.toDataURL,l);return o._executeCommand()};d.attachEvent(J,F);return a}, -saveImage:function(a){a.firstChild.saveImage()},setOptions:function(){},trigger:function(a,b){s[a].fireEvent("on"+b)},unlock:function(a,b){n[a]&&--n[a];if(b){var c=s[a],d=c.firstChild,f,g;Q(c);f=c.width;g=c.height;c.style.width=f+"px";c.style.height=g+"px";if(f>0)d.width=f;if(g>0)d.height=g;d.resize(f,g);c.attachEvent(K,G);v[a]=true}}};j.createElement(r);j.createStyleSheet().cssText=r+"{display:inline-block;overflow:hidden;width:300px;height:150px}";j.readyState==="complete"?A():j.attachEvent(E,A); -h.attachEvent(I,H);if(u.indexOf(location.protocol+"//"+location.host+"/")===0){var T=new ActiveXObject("Microsoft.XMLHTTP");T.open("GET",u,false);T.send(k)}h[L]=x;h[M]=y;h[N]=R;h[C]=B;h[O]={init:function(){},init_:function(){},initElement:B.initElement};keep=x.measureText}(window,document); diff --git a/phpMyAdmin/js/canvg/flashcanvas.swf b/phpMyAdmin/js/canvg/flashcanvas.swf deleted file mode 100644 index 66ff213fb9b86811d17f032be3c73df61547e597..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21235 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 diff --git a/phpMyAdmin/js/chart.js b/phpMyAdmin/js/chart.js new file mode 100644 index 0000000..fb0d9af --- /dev/null +++ b/phpMyAdmin/js/chart.js @@ -0,0 +1,546 @@ +/** + * Chart type enumerations + */ +var ChartType = { + LINE : 'line', + SPLINE : 'spline', + AREA : 'area', + BAR : 'bar', + COLUMN : 'column', + PIE : 'pie', + TIMELINE: 'timeline' +}; + +/** + * Abstract chart factory which defines the contract for chart factories + */ +var ChartFactory = function () { +}; +ChartFactory.prototype = { + createChart : function (type, options) { + throw new Error("createChart must be implemented by a subclass"); + } +}; + +/** + * Abstract chart which defines the contract for charts + * + * @param elementId + * id of the div element the chart is drawn in + */ +var Chart = function (elementId) { + this.elementId = elementId; +}; +Chart.prototype = { + draw : function (data, options) { + throw new Error("draw must be implemented by a subclass"); + }, + redraw : function (options) { + throw new Error("redraw must be implemented by a subclass"); + }, + destroy : function () { + throw new Error("destroy must be implemented by a subclass"); + } +}; + +/** + * Abstract representation of charts that operates on DataTable where,
    + *
      + *
    • First column provides index to the data.
    • + *
    • Each subsequent columns are of type + * ColumnType.NUMBER and represents a data series.
    • + *
    + * Line chart, area chart, bar chart, column chart are typical examples. + * + * @param elementId + * id of the div element the chart is drawn in + */ +var BaseChart = function (elementId) { + Chart.call(this, elementId); +}; +BaseChart.prototype = new Chart(); +BaseChart.prototype.constructor = BaseChart; +BaseChart.prototype.validateColumns = function (dataTable) { + var columns = dataTable.getColumns(); + if (columns.length < 2) { + throw new Error("Minimum of two columns are required for this chart"); + } + for (var i = 1; i < columns.length; i++) { + if (columns[i].type != ColumnType.NUMBER) { + throw new Error("Column " + (i + 1) + " should be of type 'Number'"); + } + } + return true; +}; + +/** + * Abstract pie chart + * + * @param elementId + * id of the div element the chart is drawn in + */ +var PieChart = function (elementId) { + BaseChart.call(this, elementId); +}; +PieChart.prototype = new BaseChart(); +PieChart.prototype.constructor = PieChart; +PieChart.prototype.validateColumns = function (dataTable) { + var columns = dataTable.getColumns(); + if (columns.length > 2) { + throw new Error("Pie charts can draw only one series"); + } + return BaseChart.prototype.validateColumns.call(this, dataTable); +}; + +/** + * Abstract timeline chart + * + * @param elementId + * id of the div element the chart is drawn in + */ +var TimelineChart = function (elementId) { + BaseChart.call(this, elementId); +}; +TimelineChart.prototype = new BaseChart(); +TimelineChart.prototype.constructor = TimelineChart; +TimelineChart.prototype.validateColumns = function (dataTable) { + var result = BaseChart.prototype.validateColumns.call(this, dataTable); + if (result) { + var columns = dataTable.getColumns(); + if (columns[0].type != ColumnType.DATE) { + throw new Error("First column of timeline chart need to be a date column"); + } + } + return result; +}; + +/** + * The data table contains column information and data for the chart. + */ +var DataTable = function () { + var columns = []; + var data; + + this.addColumn = function (type, name) { + columns.push({ + 'type' : type, + 'name' : name + }); + }; + + this.getColumns = function () { + return columns; + }; + + this.setData = function (rows) { + data = rows; + fillMissingValues(); + }; + + this.getData = function () { + return data; + }; + + var fillMissingValues = function () { + if (columns.length === 0) { + throw new Error("Set columns first"); + } + var row, column; + for (var i = 0; i < data.length; i++) { + row = data[i]; + if (row.length > columns.length) { + row.splice(columns.length - 1, row.length - columns.length); + } else if (row.length < columns.length) { + for (var j = row.length; j < columns.length; j++) { + row.push(null); + } + } + } + }; +}; + +/** + * Column type enumeration + */ +var ColumnType = { + STRING : 'string', + NUMBER : 'number', + BOOLEAN : 'boolean', + DATE : 'date' +}; + +/******************************************************************************* + * JQPlot specific code + ******************************************************************************/ + +/** + * Chart factory that returns JQPlotCharts + */ +var JQPlotChartFactory = function () { +}; +JQPlotChartFactory.prototype = new ChartFactory(); +JQPlotChartFactory.prototype.createChart = function (type, elementId) { + var chart; + switch (type) { + case ChartType.LINE: + chart = new JQPlotLineChart(elementId); + break; + case ChartType.SPLINE: + chart = new JQPlotSplineChart(elementId); + break; + case ChartType.TIMELINE: + chart = new JQPlotTimelineChart(elementId); + break; + case ChartType.AREA: + chart = new JQPlotAreaChart(elementId); + break; + case ChartType.BAR: + chart = new JQPlotBarChart(elementId); + break; + case ChartType.COLUMN: + chart = new JQPlotColumnChart(elementId); + break; + case ChartType.PIE: + chart = new JQPlotPieChart(elementId); + break; + } + + return chart; +}; + +/** + * Abstract JQplot chart + * + * @param elementId + * id of the div element the chart is drawn in + */ +var JQPlotChart = function (elementId) { + Chart.call(this, elementId); + this.plot = null; + this.validator; +}; +JQPlotChart.prototype = new Chart(); +JQPlotChart.prototype.constructor = JQPlotChart; +JQPlotChart.prototype.draw = function (data, options) { + if (this.validator.validateColumns(data)) { + this.plot = $.jqplot(this.elementId, this.prepareData(data), this + .populateOptions(data, options)); + } +}; +JQPlotChart.prototype.destroy = function () { + if (this.plot !== null) { + this.plot.destroy(); + } +}; +JQPlotChart.prototype.redraw = function (options) { + if (this.plot !== null) { + this.plot.replot(options); + } +}; +JQPlotChart.prototype.populateOptions = function (dataTable, options) { + throw new Error("populateOptions must be implemented by a subclass"); +}; +JQPlotChart.prototype.prepareData = function (dataTable) { + throw new Error("prepareData must be implemented by a subclass"); +}; + +/** + * JQPlot line chart + * + * @param elementId + * id of the div element the chart is drawn in + */ +var JQPlotLineChart = function (elementId) { + JQPlotChart.call(this, elementId); + this.validator = BaseChart.prototype; +}; +JQPlotLineChart.prototype = new JQPlotChart(); +JQPlotLineChart.prototype.constructor = JQPlotLineChart; + +JQPlotLineChart.prototype.populateOptions = function (dataTable, options) { + var columns = dataTable.getColumns(); + var optional = { + axes : { + xaxis : { + label : columns[0].name, + renderer : $.jqplot.CategoryAxisRenderer, + ticks : [] + }, + yaxis : { + label : (columns.length == 2 ? columns[1].name : 'Values'), + labelRenderer : $.jqplot.CanvasAxisLabelRenderer + } + }, + series : [] + }; + $.extend(true, optional, options); + + if (optional.series.length === 0) { + for (var i = 1; i < columns.length; i++) { + optional.series.push({ + label : columns[i].name.toString() + }); + } + } + if (optional.axes.xaxis.ticks.length === 0) { + var data = dataTable.getData(); + for (var i = 0; i < data.length; i++) { + optional.axes.xaxis.ticks.push(data[i][0].toString()); + } + } + return optional; +}; + +JQPlotLineChart.prototype.prepareData = function (dataTable) { + var data = dataTable.getData(), row; + var retData = [], retRow; + for (var i = 0; i < data.length; i++) { + row = data[i]; + for (var j = 1; j < row.length; j++) { + retRow = retData[j - 1]; + if (retRow === undefined) { + retRow = []; + retData[j - 1] = retRow; + } + retRow.push(row[j]); + } + } + return retData; +}; + +/** + * JQPlot spline chart + * + * @param elementId + * id of the div element the chart is drawn in + */ +var JQPlotSplineChart = function (elementId) { + JQPlotLineChart.call(this, elementId); +}; +JQPlotSplineChart.prototype = new JQPlotLineChart(); +JQPlotSplineChart.prototype.constructor = JQPlotSplineChart; + +JQPlotSplineChart.prototype.populateOptions = function (dataTable, options) { + var optional = {}; + var opt = JQPlotLineChart.prototype.populateOptions.call(this, dataTable, + options); + var compulsory = { + seriesDefaults : { + rendererOptions : { + smooth : true + } + } + }; + $.extend(true, optional, opt, compulsory); + return optional; +}; + +/** + * JQPlot timeline chart + * + * @param elementId + * id of the div element the chart is drawn in + */ +var JQPlotTimelineChart = function (elementId) { + JQPlotLineChart.call(this, elementId); + this.validator = TimelineChart.prototype; +}; +JQPlotTimelineChart.prototype = new JQPlotLineChart(); +JQPlotTimelineChart.prototype.constructor = JQPlotAreaChart; + +JQPlotTimelineChart.prototype.populateOptions = function (dataTable, options) { + var optional = { + axes : { + xaxis : { + tickOptions : { + formatString: '%b %#d, %y' + } + } + } + }; + var opt = JQPlotLineChart.prototype.populateOptions.call(this, dataTable, options); + var compulsory = { + axes : { + xaxis : { + renderer : $.jqplot.DateAxisRenderer + } + } + }; + $.extend(true, optional, opt, compulsory); + return optional; +}; + +JQPlotTimelineChart.prototype.prepareData = function (dataTable) { + var data = dataTable.getData(), row, d; + var retData = [], retRow; + for (var i = 0; i < data.length; i++) { + row = data[i]; + d = row[0]; + for (var j = 1; j < row.length; j++) { + retRow = retData[j - 1]; + if (retRow === undefined) { + retRow = []; + retData[j - 1] = retRow; + } + if (d !== null) { + retRow.push([d.getTime(), row[j]]); + } + } + } + return retData; +}; + +/** + * JQPlot area chart + * + * @param elementId + * id of the div element the chart is drawn in + */ +var JQPlotAreaChart = function (elementId) { + JQPlotLineChart.call(this, elementId); +}; +JQPlotAreaChart.prototype = new JQPlotLineChart(); +JQPlotAreaChart.prototype.constructor = JQPlotAreaChart; + +JQPlotAreaChart.prototype.populateOptions = function (dataTable, options) { + var optional = { + seriesDefaults : { + fillToZero : true + } + }; + var opt = JQPlotLineChart.prototype.populateOptions.call(this, dataTable, + options); + var compulsory = { + seriesDefaults : { + fill : true + } + }; + $.extend(true, optional, opt, compulsory); + return optional; +}; + +/** + * JQPlot column chart + * + * @param elementId + * id of the div element the chart is drawn in + */ +var JQPlotColumnChart = function (elementId) { + JQPlotLineChart.call(this, elementId); +}; +JQPlotColumnChart.prototype = new JQPlotLineChart(); +JQPlotColumnChart.prototype.constructor = JQPlotColumnChart; + +JQPlotColumnChart.prototype.populateOptions = function (dataTable, options) { + var optional = { + seriesDefaults : { + fillToZero : true + } + }; + var opt = JQPlotLineChart.prototype.populateOptions.call(this, dataTable, + options); + var compulsory = { + seriesDefaults : { + renderer : $.jqplot.BarRenderer + } + }; + $.extend(true, optional, opt, compulsory); + return optional; +}; + +/** + * JQPlot bar chart + * + * @param elementId + * id of the div element the chart is drawn in + */ +var JQPlotBarChart = function (elementId) { + JQPlotLineChart.call(this, elementId); +}; +JQPlotBarChart.prototype = new JQPlotLineChart(); +JQPlotBarChart.prototype.constructor = JQPlotBarChart; + +JQPlotBarChart.prototype.populateOptions = function (dataTable, options) { + var columns = dataTable.getColumns(); + var optional = { + axes : { + yaxis : { + label : columns[0].name, + labelRenderer : $.jqplot.CanvasAxisLabelRenderer, + renderer : $.jqplot.CategoryAxisRenderer, + ticks : [] + }, + xaxis : { + label : (columns.length == 2 ? columns[1].name : 'Values'), + labelRenderer : $.jqplot.CanvasAxisLabelRenderer + } + }, + series : [], + seriesDefaults : { + fillToZero : true + } + }; + var compulsory = { + seriesDefaults : { + renderer : $.jqplot.BarRenderer, + rendererOptions : { + barDirection : 'horizontal' + } + } + }; + $.extend(true, optional, options, compulsory); + + if (optional.axes.yaxis.ticks.length === 0) { + var data = dataTable.getData(); + for (var i = 0; i < data.length; i++) { + optional.axes.yaxis.ticks.push(data[i][0].toString()); + } + } + if (optional.series.length === 0) { + for (var i = 1; i < columns.length; i++) { + optional.series.push({ + label : columns[i].name.toString() + }); + } + } + return optional; +}; + +/** + * JQPlot pie chart + * + * @param elementId + * id of the div element the chart is drawn in + */ +var JQPlotPieChart = function (elementId) { + JQPlotChart.call(this, elementId); + this.validator = PieChart.prototype; +}; +JQPlotPieChart.prototype = new JQPlotChart(); +JQPlotPieChart.prototype.constructor = JQPlotPieChart; + +JQPlotPieChart.prototype.populateOptions = function (dataTable, options) { + var optional = { + highlighter: { + formatString:'%s, %d', + useAxesFormatters: false + } + }; + var compulsory = { + seriesDefaults : { + renderer : $.jqplot.PieRenderer + } + }; + $.extend(true, optional, options, compulsory); + return optional; +}; + +JQPlotPieChart.prototype.prepareData = function (dataTable) { + var data = dataTable.getData(), row; + var retData = []; + for (var i = 0; i < data.length; i++) { + row = data[i]; + retData.push([ row[0], row[1] ]); + } + return [ retData ]; +}; diff --git a/phpMyAdmin/js/codemirror/LICENSE b/phpMyAdmin/js/codemirror/LICENSE index 3f7c0bb..482d55e 100644 --- a/phpMyAdmin/js/codemirror/LICENSE +++ b/phpMyAdmin/js/codemirror/LICENSE @@ -1,4 +1,4 @@ -Copyright (C) 2011 by Marijn Haverbeke +Copyright (C) 2013 by Marijn Haverbeke Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -17,3 +17,7 @@ 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. + +Please note that some subdirectories of the CodeMirror distribution +include their own LICENSE files, and are released under different +licences. diff --git a/phpMyAdmin/js/codemirror/addon/runmode/runmode.js b/phpMyAdmin/js/codemirror/addon/runmode/runmode.js new file mode 100644 index 0000000..a7da6d7 --- /dev/null +++ b/phpMyAdmin/js/codemirror/addon/runmode/runmode.js @@ -0,0 +1,56 @@ +CodeMirror.runMode = function(string, modespec, callback, options) { + var mode = CodeMirror.getMode(CodeMirror.defaults, modespec); + var ie = /MSIE \d/.test(navigator.userAgent); + var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9); + + if (callback.nodeType == 1) { + var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize; + var node = callback, col = 0; + node.innerHTML = ""; + callback = function(text, style) { + if (text == "\n") { + // Emitting LF or CRLF on IE8 or earlier results in an incorrect display. + // Emitting a carriage return makes everything ok. + node.appendChild(document.createTextNode(ie_lt9 ? '\r' : text)); + col = 0; + return; + } + var content = ""; + // replace tabs + for (var pos = 0;;) { + var idx = text.indexOf("\t", pos); + if (idx == -1) { + content += text.slice(pos); + col += text.length - pos; + break; + } else { + col += idx - pos; + content += text.slice(pos, idx); + var size = tabSize - col % tabSize; + col += size; + for (var i = 0; i < size; ++i) content += " "; + pos = idx + 1; + } + } + + if (style) { + var sp = node.appendChild(document.createElement("span")); + sp.className = "cm-" + style.replace(/ +/g, " cm-"); + sp.appendChild(document.createTextNode(content)); + } else { + node.appendChild(document.createTextNode(content)); + } + }; + } + + var lines = CodeMirror.splitLines(string), state = CodeMirror.startState(mode); + for (var i = 0, e = lines.length; i < e; ++i) { + if (i) callback("\n"); + var stream = new CodeMirror.StringStream(lines[i]); + while (!stream.eol()) { + var style = mode.token(stream, state); + callback(stream.current(), style, i, stream.start); + stream.start = stream.pos; + } + } +}; diff --git a/phpMyAdmin/js/codemirror/lib/codemirror.js b/phpMyAdmin/js/codemirror/lib/codemirror.js index 4109887..1d0d996 100644 --- a/phpMyAdmin/js/codemirror/lib/codemirror.js +++ b/phpMyAdmin/js/codemirror/lib/codemirror.js @@ -1,94 +1,5799 @@ -var CodeMirror=function(){function F(b,e){function h(a){return a>=0&&as.undoDepth;)$.done.shift()}ka(a,c,d,g,i)}function aa(a,c){var d=a.pop();if(d){var g= -[],i=d.start+d.added;t.iter(d.start,i,function(l){g.push(l.text)});c.push({start:d.start,added:d.old.length,old:g});var j=I({line:d.start+d.old.length-1,ch:zc(g[g.length-1],d.old[d.old.length-1])});ka({line:d.start,ch:0},{line:i-1,ch:f(i-1).text.length},d.old,j,j);W=true}}function da(){aa($.done,$.undone)}function la(){aa($.undone,$.done)}function ka(a,c,d,g,i){var j=false,l=qa.length;s.lineWrapping||t.iter(a.line,c.line,function(v){if(v.text.length==l)return j=true});var o=c.line-a.line,m=f(a.line), -r=f(c.line);if(m==r)if(d.length==1)m.replace(a.ch,c.ch,d[0]);else{r=m.split(c.ch,d[d.length-1]);m.replace(a.ch,null,d[0]);m.fixMarkEnds(r);for(var u=[],w=1,A=d.length-1;w1&&t.remove(a.line+ -1,o-1);t.insert(a.line+1,u)}if(s.lineWrapping){var G=x.clientWidth/Db()-3;t.iter(a.line,a.line+d.length,function(v){if(!v.hidden){var S=Math.ceil(v.text.length/G)||1;S!=v.height&&k(v,S)}})}else{t.iter(a.line,w+d.length,function(v){v=v.text;if(v.length>l){qa=v;l=v.length;ra=null;j=false}});if(j){l=0;qa="";ra=null;t.iter(0,t.size,function(v){v=v.text;if(v.length>l){l=v.length;qa=v}})}}m=[];o=d.length-o-1;w=0;for(r=ea.length;wc.line&&m.push(u+o)}w=a.line+ -Math.min(d.length,500);Ac(a.line,w);m.push(w);ea=m;Eb(100);L.push({from:a.line,to:c.line+1,diff:o});Fb={from:a,to:c,text:d};xa(g,i,n.from.line<=Math.min(c.line,c.line+o)?n.from.line:n.from.line+o,n.to.line<=Math.min(c.line,c.line+o)?n.to.line:n.to.line+o);V.style.height=t.height*fa()+2*D.offsetTop+"px"}function X(a,c,d){function g(j){if(ga(j,c))return j;if(!ga(d,j))return i;var l=j.line+a.length-(d.line-c.line)-1,o=j.ch;if(j.line==d.line)o+=a[a.length-1].length-(d.ch-(d.line==c.line?c.ch:0));return{line:l, -ch:o}}c=I(c);d=d?I(d):c;a=va(a);var i;Oa(a,c,d,function(j){i=j;return{from:g(n.from),to:g(n.to)}});return i}function Q(a,c){Oa(va(a),n.from,n.to,function(d){return c=="end"?{from:d,to:d}:c=="start"?{from:n.from,to:n.from}:{from:n.from,to:d}})}function Oa(a,c,d,g){g=g({line:c.line+a.length-1,ch:a.length==1?a[0].length+c.ch:a[a.length-1].length});z(c,d,a,g.from,g.to)}function R(a,c){var d=a.line,g=c.line;if(d==g)return f(d).text.slice(a.ch,c.ch);var i=[f(d).text.slice(a.ch)];t.iter(d+1,g,function(j){i.push(j.text)}); -i.push(f(g).text.slice(0,c.ch));return i.join("\n")}function ma(){return R(n.from,n.to)}function pa(){Gb||Hb.set(Ea,function(){Ib();na();Z&&pa();Jb()})}function ha(a){function c(){Ib();var g=na();if(g&&a){if(g=="moved"&&Fa[a]==null)Fa[a]=true;if(g=="changed")Fa[a]=false}if(!g&&!d){d=true;Hb.set(80,c)}else{Gb=false;pa()}Jb()}var d=false;Gb=true;Hb.set(20,c)}function na(){function a(S,oa){for(var T=0;;){var ya=d.indexOf("\n",T);if(ya==-1||(d.charAt(ya-1)=="\r"?ya-1:ya)>=S)return{line:oa,ch:S-T};++oa; -T=ya+1}}if(!(Na||!Z)){var c=false,d=C.value,g=bb(C);if(!g)return false;c=M.text!=d;var i=za,j=c||g.start!=M.start||g.end!=(i?M.start:M.end);if(!j&&!i)return false;if(c){ca=za=null;if(s.readOnly){W=true;return"changed"}}var l=a(g.start,M.from),o=a(g.end,M.from);if(i){var m=g.start==i.anchor?o:l;o=ca?n.to:g.start==i.anchor?l:o;if(n.inverted=ga(m,o)){l=m;o=o}else{za=null;l=o;o=m}}if(l.line==o.line&&l.line==n.from.line&&l.line==n.to.line&&!ca)W=false;if(c){m=0;i=d.length;for(var r=Math.min(i,M.text.length), -u,w=M.from,A=-1;m-1?m-A:m;for(var G=M.to-1,v=M.text.length;;){u=M.text.charAt(v);if(d.charAt(i)!=u){++i;++v;break}u=="\n"&&G--;if(v<=m||i<=m)break;--i;--v}A=M.text.lastIndexOf("\n",v-1);z({line:w,ch:r},{line:G,ch:A==-1?v:v-A-1},va(d.slice(m,i)),l,o);if(w!=G||l.line!=w)W=true}else xa(l,o);M.text=d;M.start=g.start;M.end=g.end;return c?"changed":j?"moved":false}}function Da(){var a=[],c=Math.max(0,n.from.line-1),d=Math.min(t.size,n.to.line+ -2);t.iter(c,d,function(j){a.push(j.text)});a=C.value=a.join(cb);var g=n.from.ch,i=n.to.ch;t.iter(c,n.from.line,function(j){g+=cb.length+j.text.length});t.iter(c,n.to.line,function(j){i+=cb.length+j.text.length});M={text:a,from:c,to:d,start:g,end:i};Pa(C,g,za?g:i)}function Aa(){s.readOnly!="nocursor"&&C.focus()}function Bc(){if(ia.getBoundingClientRect){var a=ia.getBoundingClientRect(),c=window.innerHeight||Math.max(document.body.offsetHeight,document.documentElement.offsetHeight);if(a.top<0||a.bottom> -c)ia.scrollIntoView()}}function $b(){var a=db(n.inverted?n.from:n.to),c=s.lineWrapping?Math.min(a.x,D.offsetWidth):a.x;return ac(c,a.y,c,a.yBot)}function ac(a,c,d,g){var i=D.offsetLeft,j=D.offsetTop,l=fa();c+=j;g+=j;a+=i;d+=i;var o=x.clientHeight,m=x.scrollTop;i=false;j=true;if(cm+o){x.scrollTop=g+l-o;i=true}c=x.clientWidth;g=x.scrollLeft;l=s.fixedGutter?U.clientWidth:0;if(ac+g){x.scrollLeft= -d+10-c;i=true;if(d>V.clientWidth)j=false}i&&s.onScroll&&s.onScroll(P);return j}function bc(){var a=fa(),c=x.scrollTop-D.offsetTop,d=Math.ceil((c+x.clientHeight)/a);return{from:eb(t,Math.max(0,Math.floor(c/a))),to:eb(t,d)}}function fb(a){if(x.clientWidth){var c=bc();if(!(a!==true&&a.length==0&&c.from>=N&&c.to<=Y)){var d=Math.max(c.from-100,0);c=Math.min(t.size,c.to+100);if(Nc&&Y-c<20)c=Math.min(t.size,Y);a=a===true?[]:Cc([{from:N,to:Y,domStart:0}],a);for(var g=0,i=0;ic)j.to=c;if(j.from>=j.to)a.splice(i--,1);else g+=j.to-j.from}if(g!=c-d){a.sort(function(m,r){return m.domStart-r.domStart});var l=fa();g=U.style.display;ba.style.display=U.style.display="none";Dc(d,c,a);ba.style.display="";if(i=d!=N||c!=Y||cc!=x.clientHeight)cc=x.clientHeight;N=d;Y=c;Ga=gb(t,d);hb.style.top=Ga*l+"px";V.style.height=t.height*l+2*D.offsetTop+"px";if(ba.childNodes.length!=Y-N)throw Error("BAD PATCH! "+JSON.stringify(a)+" size="+ -(Y-N)+" nodes="+ba.childNodes.length);if(s.lineWrapping){ra=x.clientWidth;var o=ba.firstChild;t.iter(N,Y,function(m){if(!m.hidden){var r=Math.round(o.offsetHeight/l)||1;if(m.height!=r){k(m,r);ja=true}}o=o.nextSibling})}else{if(ra==null)ra=Kb(qa);if(ra>x.clientWidth){D.style.width=ra+"px";V.style.width="";V.style.width=x.scrollWidth+"px"}else D.style.width=V.style.width=""}U.style.display=g;if(i||ja)dc();ec()}}}else N=Y=Ga=0}function Cc(a,c){for(var d=0,g=c.length||0;d=r.to)j.push(r);else{i.from>r.from&&j.push({from:r.from,to:i.from,domStart:r.domStart});i.to -i;){j=g(j);i++}var m=0;for(o=o.to-o.from;m=a,G=Ba.createElement("div");t.iter(a,c,function(v){var S=null,oa=null;if(A){S=0;if(w==m){A=false;oa=n.to.ch}}else if(u==m)if(w==m){S=n.from.ch;oa=n.to.ch}else{A=true;S=n.from.ch}if(r&&r.to==m)r=d.shift();if(!r||r.from>m){G.innerHTML=v.hidden?"
    ":v.getHTML(S,oa,true);ba.insertBefore(G.firstChild,j)}else j=j.nextSibling;
    -++m})}function dc(){if(s.gutter||s.lineNumbers){var a=hb.offsetHeight,c=x.clientHeight;U.style.height=(a-c<2?c:a)+"px";var d=[],g=N;t.iter(N,Math.max(Y,N+1),function(l){if(l.hidden)d.push("
    ");else{var o=l.gutterMarker,m=s.lineNumbers?g+s.firstLineNumber:null;if(o&&o.text)m=o.text.replace("%N%",m!=null?m:"");else if(m==null)m="\u00a0";d.push(o&&o.style?'
    ':"
    ",m);for(o=1;o ");d.push("
    ")}++g});U.style.display="none";Qa.innerHTML= -d.join("");a=String(t.size).length;c=Qa.firstChild;for(var i=c.textContent||c.innerText||c.nodeValue||"",j="";i.length+j.lengthd||i>o.text.length)i=o.text.length;return{line:j,ch:i}}j+=i}}if(!f(a.line).hidden)return a;return a.line>= -c?g(1)||g(-1):g(-1)||g(1)}function ua(a,c,d){a=I({line:a,ch:c||0});(d?sa:xa)(a,a)}function jb(a){return Math.max(0,Math.min(a,t.size-1))}function I(a){if(a.line<0)return{line:0,ch:0};if(a.line>=t.size)return{line:t.size-1,ch:f(t.size-1).text.length};var c=a.ch,d=f(a.line).text.length;return c==null||c>d?{line:a.line,ch:d}:c<0?{line:a.line,ch:0}:a}function fc(a){for(var c=f(a.line).text,d=a.ch,g=a.ch;d>0&&/\w/.test(c.charAt(d-1));)--d;for(;g -qa.length)qa=c.text})}L.push({from:0,to:t.size})}function Lb(){this.set=[]}function Mb(a,c,d){function g(o,m,r,u){mark=f(o).addMark(new mb(m,r,u,i.set))}a=I(a);c=I(c);var i=new Lb;if(a.line==c.line)g(a.line,a.ch,c.ch,d);else{g(a.line,a.ch,null,d);for(var j=a.line+1,l=c.line;j"+a.getHTML(null, -null,false,c)+''+(a.text.charAt(c)||" ")+""+d+"
    ";d=document.getElementById("CodeMirror-temp-"+kc);var g=d.offsetTop,i=d.offsetLeft;if(ob&&c&&g==0&&i==0){g=document.createElement("span");g.innerHTML="x";d.parentNode.insertBefore(g,d.nextSibling);g=g.offsetTop}return{top:g,left:i}}function db(a,c){var d,g=fa(),i=g*(gb(t,a.line)-(c?Ga:0));if(a.ch==0)d=0;else{var j=jc(f(a.line),a.ch);d=j.left;if(s.lineWrapping)i+=Math.max(0,j.top)}return{x:d,y:i,yBot:i+g}} -function lc(a,c){function d(v){v=jc(o,v);if(r)return Math.max(0,v.left+(Math.round(v.top/g)-u)*x.clientWidth);return v.left}if(c<0)c=0;var g=fa(),i=Db(),j=Ga+Math.floor(c/g),l=eb(t,j);if(l>=t.size)return{line:t.size-1,ch:0};var o=f(l),m=o.text,r=s.lineWrapping,u=r?j-gb(t,l):0;if(a<=0&&u==0)return{line:l,ch:0};var w=j=0;m=m.length;var A;for(i=Math.min(m,Math.ceil((a+u*x.clientWidth*0.9)/i));;){var G=d(i);if(G<=a&&iA)return{line:l,ch:m};i=Math.floor(m* -0.8);G=d(i);if(Ga-w?j:m};i=Math.ceil((j+m)/2);G=d(i);if(G>a){m=i;A=G}else{j=i;w=G}}}function mc(a){a=db(a,true);var c=Sa(D);return{x:c.left+a.x,y:c.top+a.y,yBot:c.top+a.yBot}}function fa(){var a=ba.offsetHeight;if(a==Ta)return nc;Ta=a;Ca.innerHTML="
    x
    x
    x
    x
    x
    x
    x
    x
    x
    x
    ";return nc=Ca.firstChild.offsetHeight/10||1}function Db(){if(x.clientWidth==Ta)return oc;Ta=x.clientWidth;return oc=Kb("x")}function Ia(a,c){var d= -Sa(x,true),g,i;try{g=a.clientX;i=a.clientY}catch(j){return null}if(!c&&(g-d.left>x.clientWidth||i-d.top>x.clientHeight))return null;d=Sa(D,true);return lc(g-d.left,i-d.top)}function pc(a){function c(){var l=va(C.value).join("\n");l!=i&&y(Q)(l,"end");Ra.style.position="relative";C.style.cssText=g;Na=false;Da();pa()}var d=Ia(a);if(!(!d||window.opera)){if(J(n.from,n.to)||ga(d,n.from)||!ga(d,n.to))y(ua)(d.line,d.ch);var g=C.style.cssText;Ra.style.position="absolute";C.style.cssText="position: fixed; width: 30px; height: 30px; top: "+ -(a.clientY-5)+"px; left: "+(a.clientX-5)+"px; z-index: 1000; background: white; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";Na=true;var i=C.value=ma();Aa();Pa(C,0,C.value.length);if(Ja){pb(a);var j=E(window,"mouseup",function(){j();setTimeout(c,20)},true)}else setTimeout(c,50)}}function Zb(){clearInterval(Cb);var a=true;ia.style.visibility="";Cb=setInterval(function(){ia.style.visibility=(a=!a)?"":"hidden"},650)}function qc(a){function c(T,ya,Ic){if(T.text){var Ua= -T.styles;T=l?0:T.text.length-1;for(var Nb,Va=l?0:Ua.length-2,Jc=l?Ua.length:-2;Va!=Jc;Va+=2*o){var qb=Ua[Va];if(Ua[Va+1]!=null&&Ua[Va+1]!=w)T+=o*qb.length;else for(var Ob=l?0:qb.length-1,Kc=l?qb.length:-1;Ob!=Kc;Ob+=o,T+=o)if(T>=ya&&T"==l)A.push(Nb);else if(A.pop()!=rc.charAt(0))return{pos:T,match:false};else if(!A.length)return{pos:T,match:true}}}}}var d=n.inverted?n.from:n.to,g=f(d.line),i=d.ch-1,j=i>=0&&Pb[g.text.charAt(i)]||Pb[g.text.charAt(++i)]; -if(j){j.charAt(0);var l=j.charAt(1)==">",o=l?1:-1,m=g.styles,r=i+1;j=0;for(var u=m.length;ja;--g){if(g==0)return 0;var i=f(g-1);if(i.stateAfter)return g;i=i.indentation();if(d==null||c>i){d=g-1;c=i}}return d}function kb(a){var c=sc(a),d=c&&f(c-1).stateAfter;d=d?Ka(O,d):Qb(O);t.iter(c,a,function(g){g.highlight(O,d);g.stateAfter=Ka(O,d)});c=t.size)){var g=sc(d),i=g&&f(g-1).stateAfter;i=i?Ka(O,i):Qb(O);var j=0,l=O.compareStates,o=false,m=g,r=false;t.iter(m,t.size,function(u){var w=u.stateAfter;if(+new Date>a){ea.push(m);Eb(s.workDelay);o&&L.push({from:d,to:m+1});return r=true}var A=u.highlight(O,i);if(A)o=true;u.stateAfter=Ka(O,i);if(l){if(w&&l(w,i))return true}else if(A!== -false||!w)j=0;else if(++j>3)return true;++m});if(r)return;o&&L.push({from:d,to:m+1})}}c&&s.onHighlightComplete&&s.onHighlightComplete(P)}function Eb(a){ea.length&&Mc.set(a,y(Lc))}function Ib(){W=null;L=[];Fb=ta=false}function Jb(){var a=false;if(ta)a=!$b();if(L.length)fb(L);else{ta&&ec();ja&&dc()}a&&$b();if(ta){Bc();Zb()}if(Z&&!Na&&(W===true||W!==false&&ta))Da();ta&&s.matchBrackets&&setTimeout(y(function(){if(rb){rb();rb=null}qc(false)}),20);a=Fb;ta&&s.onCursorActivity&&s.onCursorActivity(P);a&&s.onChange&& -P&&s.onChange(P,a)}function y(a){return function(){tc++||Ib();try{var c=a.apply(this,arguments)}finally{--tc||Jb()}return c}}function uc(a,c,d){this.atOccurrence=false;if(d==null)d=typeof a=="string"&&a==a.toLowerCase();c=c&&typeof c=="object"?I(c):{line:0,ch:0};this.pos={from:c,to:c};if(typeof a!="string")this.matches=function(j,l){if(j)for(var o=f(l.line).text.slice(0,l.ch),m=o.match(a),r=0;m;){var u=o.indexOf(m[0]);r+=u;o=o.slice(u+1);if(u=o.match(a))m=u;else break;r++}else{o=f(l.line).text.slice(l.ch); -r=(m=o.match(a))&&l.ch+o.indexOf(m[0])}if(m)return{from:{line:l.line,ch:r},to:{line:l.line,ch:r+m[0].length},match:m}};else{if(d)a=a.toLowerCase();var g=d?function(j){return j.toLowerCase()}:function(j){return j},i=a.split("\n");this.matches=i.length==1?function(j,l){var o=g(f(l.line).text),m=a.length,r;if(j?l.ch>=m&&(r=o.lastIndexOf(a,l.ch-m))!=-1:(r=o.indexOf(a,l.ch))!=-1)return{from:{line:l.line,ch:r},to:{line:l.line,ch:r+m}}}:function(j,l){var o=l.line,m=j?i.length-1:0,r=i[m],u=g(f(o).text),w= -j?u.indexOf(r)+r.length:u.lastIndexOf(r);if(!(j?w>=l.ch||w!=r.length:w<=l.ch||w!=u.length-r.length))for(;;){if(j?!o:o==t.size-1)break;u=g(f(o+=j?-1:1).text);r=i[j?--m:++m];if(m>0&&m
     
    '; -b.appendChild?b.appendChild(K):b(K);var Ra=K.firstChild,C=Ra.firstChild,x=K.lastChild,V=x.firstChild,hb=V.firstChild,U=hb.firstChild,Qa=U.firstChild,D=U.nextSibling.firstChild,Ca=D.firstChild,ia=Ca.nextSibling,ba=ia.nextSibling;if(!sb)D.draggable=true;if(s.tabindex!=null)C.tabindex=s.tabindex;if(!s.gutter&&!s.lineNumbers)U.style.display="none";try{Kb("x")}catch(Sb){if(Sb.message.match(/unknown runtime/i))Sb=Error("A CodeMirror inside a P-style element does not work in Internet Explorer. (innerHTML bug)"); -throw Sb;}var Hb=new Tb,Mc=new Tb,Cb,O,t=new tb([new ub([new wa("")])]),ea,Z;gc();var n={from:{line:0,ch:0},to:{line:0,ch:0},inverted:false},ca,za,vb,Xa,Ub,W,L,Fb,ta,Na,ja,Ga=0,N=0,Y=0,cc=0,La=null,M,rb,qa="",ra;y(function(){p(s.value||"");W=false})();var $=new Vb,Ea=2E3,Wb=!vc&&!Ya&&(Ja||window.opera);if(s.pollForIME&&Wb)Ea=50;E(x,"mousedown",y(function(a){function c(m){var r=Ia(m,true);if(r&&!J(r,i)){Z||q();i=r;sa(g,r);W=false;var u=bc();if(r.line>=u.to||r.lined-400&&J(Xa.pos,g)){H(a);setTimeout(Aa,20);return Ec(g.line)}else if(vb&&vb.time>d-400&&J(vb.pos,g)){Xa={time:d,pos:g};H(a);return fc(g)}else vb= -{time:d,pos:g};var i=g,j;if(wc&&!J(n.from,n.to)&&!ga(g,n.from)&&!ga(n.to,g)){if(sb)D.draggable=true;var l=E(Ba,"mouseup",y(function(m){if(sb)D.draggable=false;Ub=false;l();if(Math.abs(a.clientX-m.clientX)+Math.abs(a.clientY-m.clientY)<10){H(m);ua(g.line,g.ch,true);Aa()}}),true);Ub=true}else{H(a);ua(g.line,g.ch,true);var o=E(Ba,"mousemove",y(function(m){clearTimeout(j);H(m);c(m)}),true);l=E(Ba,"mouseup",y(function(m){clearTimeout(j);var r=Ia(m);r&&sa(g,r);H(m);Aa();W=true;o();l()}),true)}}else(a.target|| -a.srcElement)==x&&H(a)}));E(x,"dblclick",y(function(a){for(var c=a.target||a.srcElement;c!=K;c=c.parentNode)if(c.parentNode==Qa)return H(a);if(c=Ia(a)){Xa={time:+new Date,pos:c};H(a);fc(c)}}));E(D,"dragstart",function(a){var c=ma();$a(c);a.dataTransfer.setDragImage(ab,0,0);a.dataTransfer.setData("Text",c)});E(D,"selectstart",H);Ja||E(x,"contextmenu",pc);E(x,"scroll",function(){fb([]);if(s.fixedGutter)U.style.left=x.scrollLeft+"px";s.onScroll&&s.onScroll(P)});E(window,"resize",function(){fb(true)}); -E(C,"keyup",y(function(a){if(!(s.onKeyEvent&&s.onKeyEvent(P,Xb(a)))){if(za){za=null;W=true}if(a.keyCode==16)ca=null;if(Ea<2E3&&!Wb)Ea=2E3}}));E(C,"input",function(){ha(La)});E(C,"keydown",y(function(a){Z||q();var c=a.keyCode;if(ob&&c==27)a.returnValue=false;var d=(Ya?a.metaKey:a.ctrlKey)&&!a.altKey,g=a.ctrlKey||a.altKey||a.metaKey;ca=c==16||a.shiftKey?ca||(n.inverted?n.to:n.from):null;if(!(s.onKeyEvent&&s.onKeyEvent(P,Xb(a)))){if(c==33||c==34){d=c==34;g=Math.floor(x.clientHeight/fa());c=n.inverted? -n.from:n.to;d=gb(t,c.line)+Math.max(g-1,1)*(d?1:-1);ua(eb(t,d),c.ch,true);return H(a)}if(d&&(c==36||c==35||Ya&&(c==38||c==40))){c=c==36||c==38?{line:0,ch:0}:{line:t.size-1,ch:f(t.size-1).text.length};sa(c,c);return H(a)}if(d&&c==65){c=t.size-1;xa({line:0,ch:0},{line:c,ch:f(c).text.length});return H(a)}if(!s.readOnly){if(!g&&c==13)return;if(!g&&c==9&&Fc(a.shiftKey))return H(a);if(d&&c==90){da();return H(a)}if(d&&(a.shiftKey&&c==90||c==89)){la();return H(a)}}if(c==36)if(s.smartHome){c=Math.max(0,f(n.from.line).text.search(/\S/)); -ua(n.from.line,n.from.ch<=c&&n.from.ch?0:c,true);return H(a)}La=(d?"c":"")+(a.altKey?"a":"")+c;if(n.inverted&&Fa[La]===true)if(g=bb(C)){za={anchor:g.start};Pa(C,g.start,g.start)}if(!d&&!a.altKey)La=null;ha(La);if(s.pollForIME&&(vc&&(Ja&&c==229||window.opera&&c==197)||Ya&&Ja))Ea=50}}));E(C,"keypress",y(function(a){if(!(s.onKeyEvent&&s.onKeyEvent(P,Xb(a)))){if(s.electricChars&&O.electricChars){var c=String.fromCharCode(a.charCode==null?a.keyCode:a.charCode);O.electricChars.indexOf(c)>-1&&setTimeout(y(function(){Ha(n.to.line, -"smart")}),50)}c=a.keyCode;if(c==13){if(!s.readOnly){Q("\n","end");if(s.enterMode!="flat")Ha(n.from.line,s.enterMode=="keep"?"prev":"smart")}H(a)}else!a.ctrlKey&&!a.altKey&&!a.metaKey&&c==9&&s.tabMode!="default"?H(a):ha(La)}}));E(C,"focus",q);E(C,"blur",B);E(x,"dragenter",pb);E(x,"dragover",pb);E(x,"drop",y(function(a){a.preventDefault();var c=Ia(a,true),d=a.dataTransfer.files;if(!(!c||s.readOnly))if(d&&d.length&&window.FileReader&&window.File){a=function(u,w){var A=new FileReader;A.onload=function(){i[w]= -A.result;if(++j==g){c=I(c);y(function(){var G=X(i.join(""),c,c);sa(c,G)})()}};A.readAsText(u)};for(var g=d.length,i=Array(g),j=0,l=0;lg&&a.y>c.offsetHeight)j=a.y-c.offsetHeight;if(l+c.offsetWidth>o)l=o-c.offsetWidth}c.style.top=j+D.offsetTop+"px";c.style.left=c.style.right="";if(i=="right"){l=V.clientWidth-c.offsetWidth;c.style.right="0px"}else{if(i=="left")l=0;else if(i=="middle")l=(V.clientWidth-c.offsetWidth)/2;c.style.left=l+D.offsetLeft+"px"}d&&ac(l,j,l+c.offsetWidth,j+c.offsetHeight)},lineCount:function(){return t.size},getCursor:function(a){if(a==null)a=n.inverted;return{line:(a? -n.from:n.to).line,ch:(a?n.from:n.to).ch}},somethingSelected:function(){return!J(n.from,n.to)},setCursor:y(function(a,c){c==null&&typeof a.line=="number"?ua(a.line,a.ch):ua(a,c)}),setSelection:y(function(a,c){xa(I(a),I(c||a))}),getLine:function(a){if(h(a))return f(a).text},setLine:y(function(a,c){h(a)&&X(c,{line:a,ch:0},{line:a,ch:f(a).text.length})}),removeLine:y(function(a){h(a)&&X("",{line:a,ch:0},I({line:a+1,ch:0}))}),replaceRange:y(X),getRange:function(a,c){return R(I(a),I(c))},coordsFromIndex:function(a){var c= -0,d;t.iter(0,t.size,function(g){g=g.text.length+1;if(g>a){d=a;return true}a-=g;++c});return I({line:c,ch:d})},operation:function(a){return y(a)()},refresh:function(){fb(true)},getInputField:function(){return C},getWrapperElement:function(){return K},getScrollerElement:function(){return x},getGutterElement:function(){return U}},Gb=false;Lb.prototype.clear=y(function(){for(var a=0,c=this.set.length;a",")":"(<","[":"]>","]":"[<","{":"}>","}":"{<"},tc=0;uc.prototype={findNext:function(){return this.find(false)}, -findPrevious:function(){return this.find(true)},find:function(a){function c(i){i={line:i,ch:0};d.pos={from:i,to:i};return d.atOccurrence=false}for(var d=this,g=I(a?this.pos.from:this.pos.to);;){if(this.pos=this.matches(a,g)){this.atOccurrence=true;return this.pos.match||true}if(a){if(!g.line)return c(0);g={line:g.line-1,ch:f(g.line-1).text.length}}else{if(g.line==t.size-1)return c(t.size);g={line:g.line+1,ch:0}}}},from:function(){if(this.atOccurrence)return{line:this.pos.from.line,ch:this.pos.from.ch}}, -to:function(){if(this.atOccurrence)return{line:this.pos.to.line,ch:this.pos.to.ch}},replace:function(a){var c=this;this.atOccurrence&&y(function(){c.pos.to=X(a,c.pos.from,c.pos.to)})()}};for(var wb in xb)if(xb.propertyIsEnumerable(wb)&&!P.propertyIsEnumerable(wb))P[wb]=xb[wb];return P}function Ka(b,e){if(e===true)return e;if(b.copyState)return b.copyState(e);var h={},f;for(f in e){var k=e[f];if(k instanceof Array)k=k.concat([]);h[f]=k}return h}function Qb(b,e,h){return b.startState?b.startState(e, -h):true}function yb(b){this.pos=this.start=0;this.string=b}function mb(b,e,h,f){this.from=b;this.to=e;this.style=h;this.set=f}function yc(b){this.to=this.from=b;this.line=null}function wa(b,e){this.styles=e||[b,null];this.text=b;this.height=1;this.stateAfter=this.parent=this.hidden=this.marked=this.gutterMarker=this.className=null}function zb(b,e,h,f){for(var k=0,p=0,q=0;pb&&f.push(B.slice(b-p,Math.min(B.length,e-p)),h[k+1]);if(z>=b)q=1}else if(q==1)z>e? -f.push(B.slice(0,e-p),h[k+1]):f.push(B,h[k+1]);p=z}}function ub(b){this.lines=b;this.parent=null;for(var e=0,h=b.length,f=0;e=0&&f>=0;--h,--f)if(b.charAt(h)!=e.charAt(f))break;return f+1}function Za(b,e){if(b.indexOf)return b.indexOf(e);for(var h=0,f=b.length;h=this.string.length},sol:function(){return this.pos==0},peek:function(){return this.string.charAt(this.pos)},next:function(){if(this.pose},eatSpace:function(){for(var b= -this.pos;/[\s\u00a0]/.test(this.string.charAt(this.pos));)++this.pos;return this.pos>b},skipToEnd:function(){this.pos=this.string.length},skipTo:function(b){b=this.string.indexOf(b,this.pos);if(b>-1){this.pos=b;return true}},backUp:function(b){this.pos-=b},column:function(){return Yb(this.string,this.start)},indentation:function(){return Yb(this.string)},match:function(b,e,h){if(typeof b=="string"){if((h?this.string.toLowerCase():this.string).indexOf(h?b.toLowerCase():b,this.pos)==this.pos){if(e!== -false)this.pos+=b.length;return true}}else{if((b=this.string.slice(this.pos).match(b))&&e!==false)this.pos+=b[0].length;return b}},current:function(){return this.string.slice(this.start,this.pos)}};F.StringStream=yb;mb.prototype={attach:function(b){this.set.push(b)},detach:function(b){b=Za(this.set,b);b>-1&&this.set.splice(b,1)},split:function(b,e){if(this.to<=b&&this.to!=null)return null;return new mb(this.from=e)this.from=Math.max(f,this.from)+k;if(this.to!=null&&this.to>e)this.to=fthis.from&&(fthis.from||this.from==null))this.to=null},isDead:function(){return this.from!=null&&this.to!=null&&this.from>=this.to},sameSet:function(b){return this.set==b.set}};yc.prototype={attach:function(b){this.line= -b},detach:function(b){if(this.line==b)this.line=null},split:function(b,e){if(bthis.to},clipTo:function(b,e,h,f,k){if((b||ethis.to)){this.from=0;this.to=-1}else if(this.from>e)this.from=this.to=Math.max(f,this.from)+k},sameSet:function(){return false},find:function(){if(!this.line||!this.line.parent)return null;return{line:nb(this.line),ch:this.from}},clear:function(){if(this.line){var b= -Za(this.line.marked,this);b!=-1&&this.line.marked.splice(b,1);this.line=null}}};wa.inheritMarks=function(b,e){var h=new wa(b),f=e.marked;if(f)for(var k=0;k5E3){f[k++]=this.text.slice(h.pos);f[k++]=null;break}}if(f.length!=k){f.length=k;p=true}if(k&&f[k-2]!=B)p=true;return p||(f.length<5&&this.text.length<10?null:false)},getTokenAt:function(b,e,h){for(var f=new yb(this.text);f.pos',$a(na),""):p.push($a(na))}}var p=[],q=true;if(h)p.push(this.className?'
    ':"
    ");var B=this.styles,z=this.text,aa=this.marked;if(b==e)b=null;var da=z.length;if(f!=null)da=Math.min(f,da);if(!z&&f==null)k(" ",b!=null&&e==null?"CodeMirror-selected":null);else if(!aa&&b==null)for(b=f=0;bda)e=e.slice(0,da-b);b+=z;k(e,la&&"cm-"+la)}else{f=z=0;var ka="",X=-1,Q=null,Oa=function(){if(aa){X+=1;Q=Xz)R=b;else if(e==null||e>z){ma=" CodeMirror-selected";if(e!=null)R=Math.min(R,e)}for(;Q&&Q.to!=null&&Q.to<=z;)Oa();if(Q)if(Q.from>z)R=Math.min(R,Q.from);else{ma+=" "+Q.style;if(Q.to!=null)R=Math.min(R,Q.to)}for(;;){var pa=z+ka.length,ha=la;if(ma)ha=la?la+ma:ma;k(pa>R?ka.slice(0,R-z):ka,ha);if(pa>=R){ka=ka.slice(R-
    -z);z=R;break}z=pa;ka=B[f++];la="cm-"+B[f++]}}b!=null&&e==null&&k(" ","CodeMirror-selected")}h&&p.push("
    ");return p.join("")},cleanUp:function(){this.parent=null;if(this.marked)for(var b=0,e=this.marked.length;b -50){for(;p.lines.length>50;){b=p.lines.splice(p.lines.length-25,25);b=new ub(b);p.height-=b.height;this.children.splice(f+1,0,b);b.parent=this}this.maybeSpill()}break}b-=q}},maybeSpill:function(){if(!(this.children.length<=10)){var b=this;do{var e=b.children.splice(b.children.length-5,5);e=new tb(e);if(b.parent){b.size-=e.size;b.height-=e.height;var h=Za(b.parent.children,b);b.parent.children.splice(h+1,0,e)}else{h=new tb(b.children);h.parent=b;b.children=[h,e];b=h}e.parent=b.parent}while(b.children.length> -10);b.parent.maybeSpill()}},iter:function(b,e,h){this.iterN(b,e-b,h)},iterN:function(b,e,h){for(var f=0,k=this.children.length;f400||!k||k.start>b+e||k.start+k.added=0;--q)k.old.unshift(h[q]);k.added+=k.start-b;k.start=b}else if(k.start-1)cb="\r\n"})();for(var lb=8,Ya=/Mac/.test(navigator.platform),vc=/Win/.test(navigator.platform),Fa={},Bb=35;Bb<=40;++Bb)Fa[Bb]=Fa["c"+Bb]=true;if(document.documentElement.getBoundingClientRect!=null)Sa=function(b,e){try{var h=b.getBoundingClientRect();h={top:h.top,left:h.left}}catch(f){h={top:0,left:0}}if(!e)if(window.pageYOffset==null){var k=document.documentElement||document.body.parentNode; -if(k.scrollTop==null)k=document.body;h.top+=k.scrollTop;h.left+=k.scrollLeft}else{h.top+=window.pageYOffset;h.left+=window.pageXOffset}return h};var ab=document.createElement("pre"),Pc=$a("\t")!="\t";F.htmlEscape=$a;var va,bb,Pa;va="\n\nb".split(/\n/).length!=3?function(b){for(var e=0,h,f=[];(h=b.indexOf("\n",e))>-1;){f.push(b.slice(e,b.charAt(h-1)=="\r"?h-1:h));e=h+1}f.push(b.slice(e));return f}:function(b){return b.split(/\r?\n/)};F.splitLines=va;if(window.getSelection){bb=function(b){try{return{start:b.selectionStart, -end:b.selectionEnd}}catch(e){return null}};Pa=sb?function(b,e,h){if(e==h)b.setSelectionRange(e,h);else{b.setSelectionRange(e,h-1);window.getSelection().modify("extend","forward","character")}}:function(b,e,h){try{b.setSelectionRange(e,h)}catch(f){}}}else{bb=function(b){try{var e=b.ownerDocument.selection.createRange()}catch(h){return null}if(!e||e.parentElement()!=b)return null;var f=b.value,k=f.length,p=b.createTextRange();p.moveToBookmark(e.getBookmark());var q=b.createTextRange();q.collapse(false); -if(p.compareEndPoints("StartToEnd",q)>-1)return{start:k,end:k};b=-p.moveStart("character",-k);for(e=f.indexOf("\r");e>-1&&e-1)return{start:b,end:k};k=-p.moveEnd("character",-k);for(e=f.indexOf("\r");e>-1&&e-1&&q-1&&q= 15) { opera = false; webkit = true; } + // Some browsers use the wrong event properties to signal cmd/ctrl on OS X + var flipCtrlCmd = mac && (qtwebkit || opera && (opera_version == null || opera_version < 12.11)); + var captureMiddleClick = gecko || (ie && !ie_lt9); + + // Optimize some code when these features are not used + var sawReadOnlySpans = false, sawCollapsedSpans = false; + + // CONSTRUCTOR + + function CodeMirror(place, options) { + if (!(this instanceof CodeMirror)) return new CodeMirror(place, options); + + this.options = options = options || {}; + // Determine effective options based on given values and defaults. + for (var opt in defaults) if (!options.hasOwnProperty(opt) && defaults.hasOwnProperty(opt)) + options[opt] = defaults[opt]; + setGuttersForLineNumbers(options); + + var docStart = typeof options.value == "string" ? 0 : options.value.first; + var display = this.display = makeDisplay(place, docStart); + display.wrapper.CodeMirror = this; + updateGutters(this); + if (options.autofocus && !mobile) focusInput(this); + + this.state = {keyMaps: [], + overlays: [], + modeGen: 0, + overwrite: false, focused: false, + suppressEdits: false, pasteIncoming: false, + draggingText: false, + highlight: new Delayed()}; + + themeChanged(this); + if (options.lineWrapping) + this.display.wrapper.className += " CodeMirror-wrap"; + + var doc = options.value; + if (typeof doc == "string") doc = new Doc(options.value, options.mode); + operation(this, attachDoc)(this, doc); + + // Override magic textarea content restore that IE sometimes does + // on our hidden textarea on reload + if (ie) setTimeout(bind(resetInput, this, true), 20); + + registerEventHandlers(this); + // IE throws unspecified error in certain cases, when + // trying to access activeElement before onload + var hasFocus; try { hasFocus = (document.activeElement == display.input); } catch(e) { } + if (hasFocus || (options.autofocus && !mobile)) setTimeout(bind(onFocus, this), 20); + else onBlur(this); + + operation(this, function() { + for (var opt in optionHandlers) + if (optionHandlers.propertyIsEnumerable(opt)) + optionHandlers[opt](this, options[opt], Init); + for (var i = 0; i < initHooks.length; ++i) initHooks[i](this); + })(); + } + + // DISPLAY CONSTRUCTOR + + function makeDisplay(place, docStart) { + var d = {}; + + var input = d.input = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none; font-size: 4px;"); + if (webkit) input.style.width = "1000px"; + else input.setAttribute("wrap", "off"); + // if border: 0; -- iOS fails to open keyboard (issue #1287) + if (ios) input.style.border = "1px solid black"; + input.setAttribute("autocorrect", "off"); input.setAttribute("autocapitalize", "off"); input.setAttribute("spellcheck", "false"); + + // Wraps and hides input textarea + d.inputDiv = elt("div", [input], null, "overflow: hidden; position: relative; width: 3px; height: 0px;"); + // The actual fake scrollbars. + d.scrollbarH = elt("div", [elt("div", null, null, "height: 1px")], "CodeMirror-hscrollbar"); + d.scrollbarV = elt("div", [elt("div", null, null, "width: 1px")], "CodeMirror-vscrollbar"); + d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler"); + d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler"); + // DIVs containing the selection and the actual code + d.lineDiv = elt("div", null, "CodeMirror-code"); + d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1"); + // Blinky cursor, and element used to ensure cursor fits at the end of a line + d.cursor = elt("div", "\u00a0", "CodeMirror-cursor"); + // Secondary cursor, shown when on a 'jump' in bi-directional text + d.otherCursor = elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"); + // Used to measure text size + d.measure = elt("div", null, "CodeMirror-measure"); + // Wraps everything that needs to exist inside the vertically-padded coordinate system + d.lineSpace = elt("div", [d.measure, d.selectionDiv, d.lineDiv, d.cursor, d.otherCursor], + null, "position: relative; outline: none"); + // Moved around its parent to cover visible view + d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative"); + // Set to the height of the text, causes scrolling + d.sizer = elt("div", [d.mover], "CodeMirror-sizer"); + // D is needed because behavior of elts with overflow: auto and padding is inconsistent across browsers + d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerCutOff + "px; width: 1px;"); + // Will contain the gutters, if any + d.gutters = elt("div", null, "CodeMirror-gutters"); + d.lineGutter = null; + // Provides scrolling + d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll"); + d.scroller.setAttribute("tabIndex", "-1"); + // The element in which the editor lives. + d.wrapper = elt("div", [d.inputDiv, d.scrollbarH, d.scrollbarV, + d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror"); + // Work around IE7 z-index bug + if (ie_lt8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; } + if (place.appendChild) place.appendChild(d.wrapper); else place(d.wrapper); + + // Needed to hide big blue blinking cursor on Mobile Safari + if (ios) input.style.width = "0px"; + if (!webkit) d.scroller.draggable = true; + // Needed to handle Tab key in KHTML + if (khtml) { d.inputDiv.style.height = "1px"; d.inputDiv.style.position = "absolute"; } + // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8). + else if (ie_lt8) d.scrollbarH.style.minWidth = d.scrollbarV.style.minWidth = "18px"; + + // Current visible range (may be bigger than the view window). + d.viewOffset = d.lastSizeC = 0; + d.showingFrom = d.showingTo = docStart; + + // Used to only resize the line number gutter when necessary (when + // the amount of lines crosses a boundary that makes its width change) + d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null; + // See readInput and resetInput + d.prevInput = ""; + // Set to true when a non-horizontal-scrolling widget is added. As + // an optimization, widget aligning is skipped when d is false. + d.alignWidgets = false; + // Flag that indicates whether we currently expect input to appear + // (after some event like 'keypress' or 'input') and are polling + // intensively. + d.pollingFast = false; + // Self-resetting timeout for the poller + d.poll = new Delayed(); + + d.cachedCharWidth = d.cachedTextHeight = null; + d.measureLineCache = []; + d.measureLineCachePos = 0; + + // Tracks when resetInput has punted to just putting a short + // string instead of the (large) selection. + d.inaccurateSelection = false; + + // Tracks the maximum line length so that the horizontal scrollbar + // can be kept static when scrolling. + d.maxLine = null; + d.maxLineLength = 0; + d.maxLineChanged = false; + + // Used for measuring wheel scrolling granularity + d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null; + + return d; + } + + // STATE UPDATES + + // Used to get the editor into a consistent state again when options change. + + function loadMode(cm) { + cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption); + cm.doc.iter(function(line) { + if (line.stateAfter) line.stateAfter = null; + if (line.styles) line.styles = null; + }); + cm.doc.frontier = cm.doc.first; + startWorker(cm, 100); + cm.state.modeGen++; + if (cm.curOp) regChange(cm); + } + + function wrappingChanged(cm) { + if (cm.options.lineWrapping) { + cm.display.wrapper.className += " CodeMirror-wrap"; + cm.display.sizer.style.minWidth = ""; + } else { + cm.display.wrapper.className = cm.display.wrapper.className.replace(" CodeMirror-wrap", ""); + computeMaxLength(cm); + } + estimateLineHeights(cm); + regChange(cm); + clearCaches(cm); + setTimeout(function(){updateScrollbars(cm);}, 100); + } + + function estimateHeight(cm) { + var th = textHeight(cm.display), wrapping = cm.options.lineWrapping; + var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3); + return function(line) { + if (lineIsHidden(cm.doc, line)) + return 0; + else if (wrapping) + return (Math.ceil(line.text.length / perLine) || 1) * th; + else + return th; + }; + } + + function estimateLineHeights(cm) { + var doc = cm.doc, est = estimateHeight(cm); + doc.iter(function(line) { + var estHeight = est(line); + if (estHeight != line.height) updateLineHeight(line, estHeight); + }); + } + + function keyMapChanged(cm) { + var map = keyMap[cm.options.keyMap], style = map.style; + cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-keymap-\S+/g, "") + + (style ? " cm-keymap-" + style : ""); + cm.state.disableInput = map.disableInput; + } + + function themeChanged(cm) { + cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") + + cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-"); + clearCaches(cm); + } + + function guttersChanged(cm) { + updateGutters(cm); + regChange(cm); + setTimeout(function(){alignHorizontally(cm);}, 20); + } + + function updateGutters(cm) { + var gutters = cm.display.gutters, specs = cm.options.gutters; + removeChildren(gutters); + for (var i = 0; i < specs.length; ++i) { + var gutterClass = specs[i]; + var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass)); + if (gutterClass == "CodeMirror-linenumbers") { + cm.display.lineGutter = gElt; + gElt.style.width = (cm.display.lineNumWidth || 1) + "px"; + } + } + gutters.style.display = i ? "" : "none"; + } + + function lineLength(doc, line) { + if (line.height == 0) return 0; + var len = line.text.length, merged, cur = line; + while (merged = collapsedSpanAtStart(cur)) { + var found = merged.find(); + cur = getLine(doc, found.from.line); + len += found.from.ch - found.to.ch; + } + cur = line; + while (merged = collapsedSpanAtEnd(cur)) { + var found = merged.find(); + len -= cur.text.length - found.from.ch; + cur = getLine(doc, found.to.line); + len += cur.text.length - found.to.ch; + } + return len; + } + + function computeMaxLength(cm) { + var d = cm.display, doc = cm.doc; + d.maxLine = getLine(doc, doc.first); + d.maxLineLength = lineLength(doc, d.maxLine); + d.maxLineChanged = true; + doc.iter(function(line) { + var len = lineLength(doc, line); + if (len > d.maxLineLength) { + d.maxLineLength = len; + d.maxLine = line; + } + }); + } + + // Make sure the gutters options contains the element + // "CodeMirror-linenumbers" when the lineNumbers option is true. + function setGuttersForLineNumbers(options) { + var found = false; + for (var i = 0; i < options.gutters.length; ++i) { + if (options.gutters[i] == "CodeMirror-linenumbers") { + if (options.lineNumbers) found = true; + else options.gutters.splice(i--, 1); + } + } + if (!found && options.lineNumbers) + options.gutters.push("CodeMirror-linenumbers"); + } + + // SCROLLBARS + + // Re-synchronize the fake scrollbars with the actual size of the + // content. Optionally force a scrollTop. + function updateScrollbars(cm) { + var d = cm.display, docHeight = cm.doc.height; + var totalHeight = docHeight + paddingVert(d); + d.sizer.style.minHeight = d.heightForcer.style.top = totalHeight + "px"; + d.gutters.style.height = Math.max(totalHeight, d.scroller.clientHeight - scrollerCutOff) + "px"; + var scrollHeight = Math.max(totalHeight, d.scroller.scrollHeight); + var needsH = d.scroller.scrollWidth > (d.scroller.clientWidth + 1); + var needsV = scrollHeight > (d.scroller.clientHeight + 1); + if (needsV) { + d.scrollbarV.style.display = "block"; + d.scrollbarV.style.bottom = needsH ? scrollbarWidth(d.measure) + "px" : "0"; + d.scrollbarV.firstChild.style.height = + (scrollHeight - d.scroller.clientHeight + d.scrollbarV.clientHeight) + "px"; + } else d.scrollbarV.style.display = ""; + if (needsH) { + d.scrollbarH.style.display = "block"; + d.scrollbarH.style.right = needsV ? scrollbarWidth(d.measure) + "px" : "0"; + d.scrollbarH.firstChild.style.width = + (d.scroller.scrollWidth - d.scroller.clientWidth + d.scrollbarH.clientWidth) + "px"; + } else d.scrollbarH.style.display = ""; + if (needsH && needsV) { + d.scrollbarFiller.style.display = "block"; + d.scrollbarFiller.style.height = d.scrollbarFiller.style.width = scrollbarWidth(d.measure) + "px"; + } else d.scrollbarFiller.style.display = ""; + if (needsH && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) { + d.gutterFiller.style.display = "block"; + d.gutterFiller.style.height = scrollbarWidth(d.measure) + "px"; + d.gutterFiller.style.width = d.gutters.offsetWidth + "px"; + } else d.gutterFiller.style.display = ""; + + if (mac_geLion && scrollbarWidth(d.measure) === 0) + d.scrollbarV.style.minWidth = d.scrollbarH.style.minHeight = mac_geMountainLion ? "18px" : "12px"; + } + + function visibleLines(display, doc, viewPort) { + var top = display.scroller.scrollTop, height = display.wrapper.clientHeight; + if (typeof viewPort == "number") top = viewPort; + else if (viewPort) {top = viewPort.top; height = viewPort.bottom - viewPort.top;} + top = Math.floor(top - paddingTop(display)); + var bottom = Math.ceil(top + height); + return {from: lineAtHeight(doc, top), to: lineAtHeight(doc, bottom)}; + } + + // LINE NUMBERS + + function alignHorizontally(cm) { + var display = cm.display; + if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return; + var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft; + var gutterW = display.gutters.offsetWidth, l = comp + "px"; + for (var n = display.lineDiv.firstChild; n; n = n.nextSibling) if (n.alignable) { + for (var i = 0, a = n.alignable; i < a.length; ++i) a[i].style.left = l; + } + if (cm.options.fixedGutter) + display.gutters.style.left = (comp + gutterW) + "px"; + } + + function maybeUpdateLineNumberWidth(cm) { + if (!cm.options.lineNumbers) return false; + var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display; + if (last.length != display.lineNumChars) { + var test = display.measure.appendChild(elt("div", [elt("div", last)], + "CodeMirror-linenumber CodeMirror-gutter-elt")); + var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW; + display.lineGutter.style.width = ""; + display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding); + display.lineNumWidth = display.lineNumInnerWidth + padding; + display.lineNumChars = display.lineNumInnerWidth ? last.length : -1; + display.lineGutter.style.width = display.lineNumWidth + "px"; + return true; + } + return false; + } + + function lineNumberFor(options, i) { + return String(options.lineNumberFormatter(i + options.firstLineNumber)); + } + function compensateForHScroll(display) { + return getRect(display.scroller).left - getRect(display.sizer).left; + } + + // DISPLAY DRAWING + + function updateDisplay(cm, changes, viewPort, forced) { + var oldFrom = cm.display.showingFrom, oldTo = cm.display.showingTo, updated; + var visible = visibleLines(cm.display, cm.doc, viewPort); + for (;;) { + if (!updateDisplayInner(cm, changes, visible, forced)) break; + forced = false; + updated = true; + updateSelection(cm); + updateScrollbars(cm); + + // Clip forced viewport to actual scrollable area + if (viewPort) + viewPort = Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, + typeof viewPort == "number" ? viewPort : viewPort.top); + visible = visibleLines(cm.display, cm.doc, viewPort); + if (visible.from >= cm.display.showingFrom && visible.to <= cm.display.showingTo) + break; + changes = []; + } + + if (updated) { + signalLater(cm, "update", cm); + if (cm.display.showingFrom != oldFrom || cm.display.showingTo != oldTo) + signalLater(cm, "viewportChange", cm, cm.display.showingFrom, cm.display.showingTo); + } + return updated; + } + + // Uses a set of changes plus the current scroll position to + // determine which DOM updates have to be made, and makes the + // updates. + function updateDisplayInner(cm, changes, visible, forced) { + var display = cm.display, doc = cm.doc; + if (!display.wrapper.clientWidth) { + display.showingFrom = display.showingTo = doc.first; + display.viewOffset = 0; + return; + } + + // Bail out if the visible area is already rendered and nothing changed. + if (!forced && changes.length == 0 && + visible.from > display.showingFrom && visible.to < display.showingTo) + return; + + if (maybeUpdateLineNumberWidth(cm)) + changes = [{from: doc.first, to: doc.first + doc.size}]; + var gutterW = display.sizer.style.marginLeft = display.gutters.offsetWidth + "px"; + display.scrollbarH.style.left = cm.options.fixedGutter ? gutterW : "0"; + + // Used to determine which lines need their line numbers updated + var positionsChangedFrom = Infinity; + if (cm.options.lineNumbers) + for (var i = 0; i < changes.length; ++i) + if (changes[i].diff) { positionsChangedFrom = changes[i].from; break; } + + var end = doc.first + doc.size; + var from = Math.max(visible.from - cm.options.viewportMargin, doc.first); + var to = Math.min(end, visible.to + cm.options.viewportMargin); + if (display.showingFrom < from && from - display.showingFrom < 20) from = Math.max(doc.first, display.showingFrom); + if (display.showingTo > to && display.showingTo - to < 20) to = Math.min(end, display.showingTo); + if (sawCollapsedSpans) { + from = lineNo(visualLine(doc, getLine(doc, from))); + while (to < end && lineIsHidden(doc, getLine(doc, to))) ++to; + } + + // Create a range of theoretically intact lines, and punch holes + // in that using the change info. + var intact = [{from: Math.max(display.showingFrom, doc.first), + to: Math.min(display.showingTo, end)}]; + if (intact[0].from >= intact[0].to) intact = []; + else intact = computeIntact(intact, changes); + // When merged lines are present, we might have to reduce the + // intact ranges because changes in continued fragments of the + // intact lines do require the lines to be redrawn. + if (sawCollapsedSpans) + for (var i = 0; i < intact.length; ++i) { + var range = intact[i], merged; + while (merged = collapsedSpanAtEnd(getLine(doc, range.to - 1))) { + var newTo = merged.find().from.line; + if (newTo > range.from) range.to = newTo; + else { intact.splice(i--, 1); break; } + } + } + + // Clip off the parts that won't be visible + var intactLines = 0; + for (var i = 0; i < intact.length; ++i) { + var range = intact[i]; + if (range.from < from) range.from = from; + if (range.to > to) range.to = to; + if (range.from >= range.to) intact.splice(i--, 1); + else intactLines += range.to - range.from; + } + if (!forced && intactLines == to - from && from == display.showingFrom && to == display.showingTo) { + updateViewOffset(cm); + return; + } + intact.sort(function(a, b) {return a.from - b.from;}); + + // Avoid crashing on IE's "unspecified error" when in iframes + try { + var focused = document.activeElement; + } catch(e) {} + if (intactLines < (to - from) * .7) display.lineDiv.style.display = "none"; + patchDisplay(cm, from, to, intact, positionsChangedFrom); + display.lineDiv.style.display = ""; + if (focused && document.activeElement != focused && focused.offsetHeight) focused.focus(); + + var different = from != display.showingFrom || to != display.showingTo || + display.lastSizeC != display.wrapper.clientHeight; + // This is just a bogus formula that detects when the editor is + // resized or the font size changes. + if (different) { + display.lastSizeC = display.wrapper.clientHeight; + startWorker(cm, 400); + } + display.showingFrom = from; display.showingTo = to; + + updateHeightsInViewport(cm); + updateViewOffset(cm); + + return true; + } + + function updateHeightsInViewport(cm) { + var display = cm.display; + var prevBottom = display.lineDiv.offsetTop; + for (var node = display.lineDiv.firstChild, height; node; node = node.nextSibling) if (node.lineObj) { + if (ie_lt8) { + var bot = node.offsetTop + node.offsetHeight; + height = bot - prevBottom; + prevBottom = bot; + } else { + var box = getRect(node); + height = box.bottom - box.top; + } + var diff = node.lineObj.height - height; + if (height < 2) height = textHeight(display); + if (diff > .001 || diff < -.001) { + updateLineHeight(node.lineObj, height); + var widgets = node.lineObj.widgets; + if (widgets) for (var i = 0; i < widgets.length; ++i) + widgets[i].height = widgets[i].node.offsetHeight; + } + } + } + + function updateViewOffset(cm) { + var off = cm.display.viewOffset = heightAtLine(cm, getLine(cm.doc, cm.display.showingFrom)); + // Position the mover div to align with the current virtual scroll position + cm.display.mover.style.top = off + "px"; + } + + function computeIntact(intact, changes) { + for (var i = 0, l = changes.length || 0; i < l; ++i) { + var change = changes[i], intact2 = [], diff = change.diff || 0; + for (var j = 0, l2 = intact.length; j < l2; ++j) { + var range = intact[j]; + if (change.to <= range.from && change.diff) { + intact2.push({from: range.from + diff, to: range.to + diff}); + } else if (change.to <= range.from || change.from >= range.to) { + intact2.push(range); + } else { + if (change.from > range.from) + intact2.push({from: range.from, to: change.from}); + if (change.to < range.to) + intact2.push({from: change.to + diff, to: range.to + diff}); + } + } + intact = intact2; + } + return intact; + } + + function getDimensions(cm) { + var d = cm.display, left = {}, width = {}; + for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) { + left[cm.options.gutters[i]] = n.offsetLeft; + width[cm.options.gutters[i]] = n.offsetWidth; + } + return {fixedPos: compensateForHScroll(d), + gutterTotalWidth: d.gutters.offsetWidth, + gutterLeft: left, + gutterWidth: width, + wrapperWidth: d.wrapper.clientWidth}; + } + + function patchDisplay(cm, from, to, intact, updateNumbersFrom) { + var dims = getDimensions(cm); + var display = cm.display, lineNumbers = cm.options.lineNumbers; + if (!intact.length && (!webkit || !cm.display.currentWheelTarget)) + removeChildren(display.lineDiv); + var container = display.lineDiv, cur = container.firstChild; + + function rm(node) { + var next = node.nextSibling; + if (webkit && mac && cm.display.currentWheelTarget == node) { + node.style.display = "none"; + node.lineObj = null; + } else { + node.parentNode.removeChild(node); + } + return next; + } + + var nextIntact = intact.shift(), lineN = from; + cm.doc.iter(from, to, function(line) { + if (nextIntact && nextIntact.to == lineN) nextIntact = intact.shift(); + if (lineIsHidden(cm.doc, line)) { + if (line.height != 0) updateLineHeight(line, 0); + if (line.widgets && cur.previousSibling) for (var i = 0; i < line.widgets.length; ++i) { + var w = line.widgets[i]; + if (w.showIfHidden) { + var prev = cur.previousSibling; + if (/pre/i.test(prev.nodeName)) { + var wrap = elt("div", null, null, "position: relative"); + prev.parentNode.replaceChild(wrap, prev); + wrap.appendChild(prev); + prev = wrap; + } + var wnode = prev.appendChild(elt("div", [w.node], "CodeMirror-linewidget")); + if (!w.handleMouseEvents) wnode.ignoreEvents = true; + positionLineWidget(w, wnode, prev, dims); + } + } + } else if (nextIntact && nextIntact.from <= lineN && nextIntact.to > lineN) { + // This line is intact. Skip to the actual node. Update its + // line number if needed. + while (cur.lineObj != line) cur = rm(cur); + if (lineNumbers && updateNumbersFrom <= lineN && cur.lineNumber) + setTextContent(cur.lineNumber, lineNumberFor(cm.options, lineN)); + cur = cur.nextSibling; + } else { + // For lines with widgets, make an attempt to find and reuse + // the existing element, so that widgets aren't needlessly + // removed and re-inserted into the dom + if (line.widgets) for (var j = 0, search = cur, reuse; search && j < 20; ++j, search = search.nextSibling) + if (search.lineObj == line && /div/i.test(search.nodeName)) { reuse = search; break; } + // This line needs to be generated. + var lineNode = buildLineElement(cm, line, lineN, dims, reuse); + if (lineNode != reuse) { + container.insertBefore(lineNode, cur); + } else { + while (cur != reuse) cur = rm(cur); + cur = cur.nextSibling; + } + + lineNode.lineObj = line; + } + ++lineN; + }); + while (cur) cur = rm(cur); + } + + function buildLineElement(cm, line, lineNo, dims, reuse) { + var lineElement = lineContent(cm, line); + var markers = line.gutterMarkers, display = cm.display, wrap; + + if (!cm.options.lineNumbers && !markers && !line.bgClass && !line.wrapClass && !line.widgets) + return lineElement; + + // Lines with gutter elements, widgets or a background class need + // to be wrapped again, and have the extra elements added to the + // wrapper div + + if (reuse) { + reuse.alignable = null; + var isOk = true, widgetsSeen = 0, insertBefore = null; + for (var n = reuse.firstChild, next; n; n = next) { + next = n.nextSibling; + if (!/\bCodeMirror-linewidget\b/.test(n.className)) { + reuse.removeChild(n); + } else { + for (var i = 0; i < line.widgets.length; ++i) { + var widget = line.widgets[i]; + if (widget.node == n.firstChild) { + if (!widget.above && !insertBefore) insertBefore = n; + positionLineWidget(widget, n, reuse, dims); + ++widgetsSeen; + break; + } + } + if (i == line.widgets.length) { isOk = false; break; } + } + } + reuse.insertBefore(lineElement, insertBefore); + if (isOk && widgetsSeen == line.widgets.length) { + wrap = reuse; + reuse.className = line.wrapClass || ""; + } + } + if (!wrap) { + wrap = elt("div", null, line.wrapClass, "position: relative"); + wrap.appendChild(lineElement); + } + // Kludge to make sure the styled element lies behind the selection (by z-index) + if (line.bgClass) + wrap.insertBefore(elt("div", null, line.bgClass + " CodeMirror-linebackground"), wrap.firstChild); + if (cm.options.lineNumbers || markers) { + var gutterWrap = wrap.insertBefore(elt("div", null, null, "position: absolute; left: " + + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"), + wrap.firstChild); + if (cm.options.fixedGutter) (wrap.alignable || (wrap.alignable = [])).push(gutterWrap); + if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"])) + wrap.lineNumber = gutterWrap.appendChild( + elt("div", lineNumberFor(cm.options, lineNo), + "CodeMirror-linenumber CodeMirror-gutter-elt", + "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: " + + display.lineNumInnerWidth + "px")); + if (markers) + for (var k = 0; k < cm.options.gutters.length; ++k) { + var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id]; + if (found) + gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " + + dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px")); + } + } + if (ie_lt8) wrap.style.zIndex = 2; + if (line.widgets && wrap != reuse) for (var i = 0, ws = line.widgets; i < ws.length; ++i) { + var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget"); + if (!widget.handleMouseEvents) node.ignoreEvents = true; + positionLineWidget(widget, node, wrap, dims); + if (widget.above) + wrap.insertBefore(node, cm.options.lineNumbers && line.height != 0 ? gutterWrap : lineElement); + else + wrap.appendChild(node); + signalLater(widget, "redraw"); + } + return wrap; + } + + function positionLineWidget(widget, node, wrap, dims) { + if (widget.noHScroll) { + (wrap.alignable || (wrap.alignable = [])).push(node); + var width = dims.wrapperWidth; + node.style.left = dims.fixedPos + "px"; + if (!widget.coverGutter) { + width -= dims.gutterTotalWidth; + node.style.paddingLeft = dims.gutterTotalWidth + "px"; + } + node.style.width = width + "px"; + } + if (widget.coverGutter) { + node.style.zIndex = 5; + node.style.position = "relative"; + if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px"; + } + } + + // SELECTION / CURSOR + + function updateSelection(cm) { + var display = cm.display; + var collapsed = posEq(cm.doc.sel.from, cm.doc.sel.to); + if (collapsed || cm.options.showCursorWhenSelecting) + updateSelectionCursor(cm); + else + display.cursor.style.display = display.otherCursor.style.display = "none"; + if (!collapsed) + updateSelectionRange(cm); + else + display.selectionDiv.style.display = "none"; + + // Move the hidden textarea near the cursor to prevent scrolling artifacts + if (cm.options.moveInputWithCursor) { + var headPos = cursorCoords(cm, cm.doc.sel.head, "div"); + var wrapOff = getRect(display.wrapper), lineOff = getRect(display.lineDiv); + display.inputDiv.style.top = Math.max(0, Math.min(display.wrapper.clientHeight - 10, + headPos.top + lineOff.top - wrapOff.top)) + "px"; + display.inputDiv.style.left = Math.max(0, Math.min(display.wrapper.clientWidth - 10, + headPos.left + lineOff.left - wrapOff.left)) + "px"; + } + } + + // No selection, plain cursor + function updateSelectionCursor(cm) { + var display = cm.display, pos = cursorCoords(cm, cm.doc.sel.head, "div"); + display.cursor.style.left = pos.left + "px"; + display.cursor.style.top = pos.top + "px"; + display.cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px"; + display.cursor.style.display = ""; + + if (pos.other) { + display.otherCursor.style.display = ""; + display.otherCursor.style.left = pos.other.left + "px"; + display.otherCursor.style.top = pos.other.top + "px"; + display.otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px"; + } else { display.otherCursor.style.display = "none"; } + } + + // Highlight selection + function updateSelectionRange(cm) { + var display = cm.display, doc = cm.doc, sel = cm.doc.sel; + var fragment = document.createDocumentFragment(); + var clientWidth = display.lineSpace.offsetWidth, pl = paddingLeft(cm.display); + + function add(left, top, width, bottom) { + if (top < 0) top = 0; + fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left + + "px; top: " + top + "px; width: " + (width == null ? clientWidth - left : width) + + "px; height: " + (bottom - top) + "px")); + } + + function drawForLine(line, fromArg, toArg) { + var lineObj = getLine(doc, line); + var lineLen = lineObj.text.length; + var start, end; + function coords(ch, bias) { + return charCoords(cm, Pos(line, ch), "div", lineObj, bias); + } + + iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) { + var leftPos = coords(from, "left"), rightPos, left, right; + if (from == to) { + rightPos = leftPos; + left = right = leftPos.left; + } else { + rightPos = coords(to - 1, "right"); + if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; } + left = leftPos.left; + right = rightPos.right; + } + if (fromArg == null && from == 0) left = pl; + if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part + add(left, leftPos.top, null, leftPos.bottom); + left = pl; + if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top); + } + if (toArg == null && to == lineLen) right = clientWidth; + if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left) + start = leftPos; + if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right) + end = rightPos; + if (left < pl + 1) left = pl; + add(left, rightPos.top, right - left, rightPos.bottom); + }); + return {start: start, end: end}; + } + + if (sel.from.line == sel.to.line) { + drawForLine(sel.from.line, sel.from.ch, sel.to.ch); + } else { + var fromLine = getLine(doc, sel.from.line), toLine = getLine(doc, sel.to.line); + var singleVLine = visualLine(doc, fromLine) == visualLine(doc, toLine); + var leftEnd = drawForLine(sel.from.line, sel.from.ch, singleVLine ? fromLine.text.length : null).end; + var rightStart = drawForLine(sel.to.line, singleVLine ? 0 : null, sel.to.ch).start; + if (singleVLine) { + if (leftEnd.top < rightStart.top - 2) { + add(leftEnd.right, leftEnd.top, null, leftEnd.bottom); + add(pl, rightStart.top, rightStart.left, rightStart.bottom); + } else { + add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom); + } + } + if (leftEnd.bottom < rightStart.top) + add(pl, leftEnd.bottom, null, rightStart.top); + } + + removeChildrenAndAdd(display.selectionDiv, fragment); + display.selectionDiv.style.display = ""; + } + + // Cursor-blinking + function restartBlink(cm) { + if (!cm.state.focused) return; + var display = cm.display; + clearInterval(display.blinker); + var on = true; + display.cursor.style.visibility = display.otherCursor.style.visibility = ""; + display.blinker = setInterval(function() { + display.cursor.style.visibility = display.otherCursor.style.visibility = (on = !on) ? "" : "hidden"; + }, cm.options.cursorBlinkRate); + } + + // HIGHLIGHT WORKER + + function startWorker(cm, time) { + if (cm.doc.mode.startState && cm.doc.frontier < cm.display.showingTo) + cm.state.highlight.set(time, bind(highlightWorker, cm)); + } + + function highlightWorker(cm) { + var doc = cm.doc; + if (doc.frontier < doc.first) doc.frontier = doc.first; + if (doc.frontier >= cm.display.showingTo) return; + var end = +new Date + cm.options.workTime; + var state = copyState(doc.mode, getStateBefore(cm, doc.frontier)); + var changed = [], prevChange; + doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.showingTo + 500), function(line) { + if (doc.frontier >= cm.display.showingFrom) { // Visible + var oldStyles = line.styles; + line.styles = highlightLine(cm, line, state); + var ischange = !oldStyles || oldStyles.length != line.styles.length; + for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i]; + if (ischange) { + if (prevChange && prevChange.end == doc.frontier) prevChange.end++; + else changed.push(prevChange = {start: doc.frontier, end: doc.frontier + 1}); + } + line.stateAfter = copyState(doc.mode, state); + } else { + processLine(cm, line, state); + line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null; + } + ++doc.frontier; + if (+new Date > end) { + startWorker(cm, cm.options.workDelay); + return true; + } + }); + if (changed.length) + operation(cm, function() { + for (var i = 0; i < changed.length; ++i) + regChange(this, changed[i].start, changed[i].end); + })(); + } + + // Finds the line to start with when starting a parse. Tries to + // find a line with a stateAfter, so that it can start with a + // valid state. If that fails, it returns the line with the + // smallest indentation, which tends to need the least context to + // parse correctly. + function findStartLine(cm, n, precise) { + var minindent, minline, doc = cm.doc; + for (var search = n, lim = n - 100; search > lim; --search) { + if (search <= doc.first) return doc.first; + var line = getLine(doc, search - 1); + if (line.stateAfter && (!precise || search <= doc.frontier)) return search; + var indented = countColumn(line.text, null, cm.options.tabSize); + if (minline == null || minindent > indented) { + minline = search - 1; + minindent = indented; + } + } + return minline; + } + + function getStateBefore(cm, n, precise) { + var doc = cm.doc, display = cm.display; + if (!doc.mode.startState) return true; + var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter; + if (!state) state = startState(doc.mode); + else state = copyState(doc.mode, state); + doc.iter(pos, n, function(line) { + processLine(cm, line, state); + var save = pos == n - 1 || pos % 5 == 0 || pos >= display.showingFrom && pos < display.showingTo; + line.stateAfter = save ? copyState(doc.mode, state) : null; + ++pos; + }); + return state; + } + + // POSITION MEASUREMENT + + function paddingTop(display) {return display.lineSpace.offsetTop;} + function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight;} + function paddingLeft(display) { + var e = removeChildrenAndAdd(display.measure, elt("pre", null, null, "text-align: left")).appendChild(elt("span", "x")); + return e.offsetLeft; + } + + function measureChar(cm, line, ch, data, bias) { + var dir = -1; + data = data || measureLine(cm, line); + + for (var pos = ch;; pos += dir) { + var r = data[pos]; + if (r) break; + if (dir < 0 && pos == 0) dir = 1; + } + bias = pos > ch ? "left" : pos < ch ? "right" : bias; + if (bias == "left" && r.leftSide) r = r.leftSide; + else if (bias == "right" && r.rightSide) r = r.rightSide; + return {left: pos < ch ? r.right : r.left, + right: pos > ch ? r.left : r.right, + top: r.top, + bottom: r.bottom}; + } + + function findCachedMeasurement(cm, line) { + var cache = cm.display.measureLineCache; + for (var i = 0; i < cache.length; ++i) { + var memo = cache[i]; + if (memo.text == line.text && memo.markedSpans == line.markedSpans && + cm.display.scroller.clientWidth == memo.width && + memo.classes == line.textClass + "|" + line.bgClass + "|" + line.wrapClass) + return memo; + } + } + + function clearCachedMeasurement(cm, line) { + var exists = findCachedMeasurement(cm, line); + if (exists) exists.text = exists.measure = exists.markedSpans = null; + } + + function measureLine(cm, line) { + // First look in the cache + var cached = findCachedMeasurement(cm, line); + if (cached) return cached.measure; + + // Failing that, recompute and store result in cache + var measure = measureLineInner(cm, line); + var cache = cm.display.measureLineCache; + var memo = {text: line.text, width: cm.display.scroller.clientWidth, + markedSpans: line.markedSpans, measure: measure, + classes: line.textClass + "|" + line.bgClass + "|" + line.wrapClass}; + if (cache.length == 16) cache[++cm.display.measureLineCachePos % 16] = memo; + else cache.push(memo); + return measure; + } + + function measureLineInner(cm, line) { + var display = cm.display, measure = emptyArray(line.text.length); + var pre = lineContent(cm, line, measure, true); + + // IE does not cache element positions of inline elements between + // calls to getBoundingClientRect. This makes the loop below, + // which gathers the positions of all the characters on the line, + // do an amount of layout work quadratic to the number of + // characters. When line wrapping is off, we try to improve things + // by first subdividing the line into a bunch of inline blocks, so + // that IE can reuse most of the layout information from caches + // for those blocks. This does interfere with line wrapping, so it + // doesn't work when wrapping is on, but in that case the + // situation is slightly better, since IE does cache line-wrapping + // information and only recomputes per-line. + if (ie && !ie_lt8 && !cm.options.lineWrapping && pre.childNodes.length > 100) { + var fragment = document.createDocumentFragment(); + var chunk = 10, n = pre.childNodes.length; + for (var i = 0, chunks = Math.ceil(n / chunk); i < chunks; ++i) { + var wrap = elt("div", null, null, "display: inline-block"); + for (var j = 0; j < chunk && n; ++j) { + wrap.appendChild(pre.firstChild); + --n; + } + fragment.appendChild(wrap); + } + pre.appendChild(fragment); + } + + removeChildrenAndAdd(display.measure, pre); + + var outer = getRect(display.lineDiv); + var vranges = [], data = emptyArray(line.text.length), maxBot = pre.offsetHeight; + // Work around an IE7/8 bug where it will sometimes have randomly + // replaced our pre with a clone at this point. + if (ie_lt9 && display.measure.first != pre) + removeChildrenAndAdd(display.measure, pre); + + function measureRect(rect) { + var top = rect.top - outer.top, bot = rect.bottom - outer.top; + if (bot > maxBot) bot = maxBot; + if (top < 0) top = 0; + for (var i = vranges.length - 2; i >= 0; i -= 2) { + var rtop = vranges[i], rbot = vranges[i+1]; + if (rtop > bot || rbot < top) continue; + if (rtop <= top && rbot >= bot || + top <= rtop && bot >= rbot || + Math.min(bot, rbot) - Math.max(top, rtop) >= (bot - top) >> 1) { + vranges[i] = Math.min(top, rtop); + vranges[i+1] = Math.max(bot, rbot); + break; + } + } + if (i < 0) { i = vranges.length; vranges.push(top, bot); } + return {left: rect.left - outer.left, + right: rect.right - outer.left, + top: i, bottom: null}; + } + function finishRect(rect) { + rect.bottom = vranges[rect.top+1]; + rect.top = vranges[rect.top]; + } + + for (var i = 0, cur; i < measure.length; ++i) if (cur = measure[i]) { + var node = cur, rect = null; + // A widget might wrap, needs special care + if (/\bCodeMirror-widget\b/.test(cur.className) && cur.getClientRects) { + if (cur.firstChild.nodeType == 1) node = cur.firstChild; + var rects = node.getClientRects(); + if (rects.length > 1) { + rect = data[i] = measureRect(rects[0]); + rect.rightSide = measureRect(rects[rects.length - 1]); + } + } + if (!rect) rect = data[i] = measureRect(getRect(node)); + if (cur.measureRight) rect.right = getRect(cur.measureRight).left; + if (cur.leftSide) rect.leftSide = measureRect(getRect(cur.leftSide)); + } + for (var i = 0, cur; i < data.length; ++i) if (cur = data[i]) { + finishRect(cur); + if (cur.leftSide) finishRect(cur.leftSide); + if (cur.rightSide) finishRect(cur.rightSide); + } + return data; + } + + function measureLineWidth(cm, line) { + var hasBadSpan = false; + if (line.markedSpans) for (var i = 0; i < line.markedSpans; ++i) { + var sp = line.markedSpans[i]; + if (sp.collapsed && (sp.to == null || sp.to == line.text.length)) hasBadSpan = true; + } + var cached = !hasBadSpan && findCachedMeasurement(cm, line); + if (cached) return measureChar(cm, line, line.text.length, cached.measure, "right").right; + + var pre = lineContent(cm, line, null, true); + var end = pre.appendChild(zeroWidthElement(cm.display.measure)); + removeChildrenAndAdd(cm.display.measure, pre); + return getRect(end).right - getRect(cm.display.lineDiv).left; + } + + function clearCaches(cm) { + cm.display.measureLineCache.length = cm.display.measureLineCachePos = 0; + cm.display.cachedCharWidth = cm.display.cachedTextHeight = null; + if (!cm.options.lineWrapping) cm.display.maxLineChanged = true; + cm.display.lineNumChars = null; + } + + function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; } + function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; } + + // Context is one of "line", "div" (display.lineDiv), "local"/null (editor), or "page" + function intoCoordSystem(cm, lineObj, rect, context) { + if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) { + var size = widgetHeight(lineObj.widgets[i]); + rect.top += size; rect.bottom += size; + } + if (context == "line") return rect; + if (!context) context = "local"; + var yOff = heightAtLine(cm, lineObj); + if (context == "local") yOff += paddingTop(cm.display); + else yOff -= cm.display.viewOffset; + if (context == "page" || context == "window") { + var lOff = getRect(cm.display.lineSpace); + yOff += lOff.top + (context == "window" ? 0 : pageScrollY()); + var xOff = lOff.left + (context == "window" ? 0 : pageScrollX()); + rect.left += xOff; rect.right += xOff; + } + rect.top += yOff; rect.bottom += yOff; + return rect; + } + + // Context may be "window", "page", "div", or "local"/null + // Result is in "div" coords + function fromCoordSystem(cm, coords, context) { + if (context == "div") return coords; + var left = coords.left, top = coords.top; + // First move into "page" coordinate system + if (context == "page") { + left -= pageScrollX(); + top -= pageScrollY(); + } else if (context == "local" || !context) { + var localBox = getRect(cm.display.sizer); + left += localBox.left; + top += localBox.top; + } + + var lineSpaceBox = getRect(cm.display.lineSpace); + return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}; + } + + function charCoords(cm, pos, context, lineObj, bias) { + if (!lineObj) lineObj = getLine(cm.doc, pos.line); + return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, null, bias), context); + } + + function cursorCoords(cm, pos, context, lineObj, measurement) { + lineObj = lineObj || getLine(cm.doc, pos.line); + if (!measurement) measurement = measureLine(cm, lineObj); + function get(ch, right) { + var m = measureChar(cm, lineObj, ch, measurement, right ? "right" : "left"); + if (right) m.left = m.right; else m.right = m.left; + return intoCoordSystem(cm, lineObj, m, context); + } + function getBidi(ch, partPos) { + var part = order[partPos], right = part.level % 2; + if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) { + part = order[--partPos]; + ch = bidiRight(part) - (part.level % 2 ? 0 : 1); + right = true; + } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) { + part = order[++partPos]; + ch = bidiLeft(part) - part.level % 2; + right = false; + } + if (right && ch == part.to && ch > part.from) return get(ch - 1); + return get(ch, right); + } + var order = getOrder(lineObj), ch = pos.ch; + if (!order) return get(ch); + var partPos = getBidiPartAt(order, ch); + var val = getBidi(ch, partPos); + if (bidiOther != null) val.other = getBidi(ch, bidiOther); + return val; + } + + function PosWithInfo(line, ch, outside, xRel) { + var pos = new Pos(line, ch); + pos.xRel = xRel; + if (outside) pos.outside = true; + return pos; + } + + // Coords must be lineSpace-local + function coordsChar(cm, x, y) { + var doc = cm.doc; + y += cm.display.viewOffset; + if (y < 0) return PosWithInfo(doc.first, 0, true, -1); + var lineNo = lineAtHeight(doc, y), last = doc.first + doc.size - 1; + if (lineNo > last) + return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1); + if (x < 0) x = 0; + + for (;;) { + var lineObj = getLine(doc, lineNo); + var found = coordsCharInner(cm, lineObj, lineNo, x, y); + var merged = collapsedSpanAtEnd(lineObj); + var mergedPos = merged && merged.find(); + if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0)) + lineNo = mergedPos.to.line; + else + return found; + } + } + + function coordsCharInner(cm, lineObj, lineNo, x, y) { + var innerOff = y - heightAtLine(cm, lineObj); + var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth; + var measurement = measureLine(cm, lineObj); + + function getX(ch) { + var sp = cursorCoords(cm, Pos(lineNo, ch), "line", + lineObj, measurement); + wrongLine = true; + if (innerOff > sp.bottom) return sp.left - adjust; + else if (innerOff < sp.top) return sp.left + adjust; + else wrongLine = false; + return sp.left; + } + + var bidi = getOrder(lineObj), dist = lineObj.text.length; + var from = lineLeft(lineObj), to = lineRight(lineObj); + var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine; + + if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1); + // Do a binary search between these bounds. + for (;;) { + if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) { + var ch = x < fromX || x - fromX <= toX - x ? from : to; + var xDiff = x - (ch == from ? fromX : toX); + while (isExtendingChar.test(lineObj.text.charAt(ch))) ++ch; + var pos = PosWithInfo(lineNo, ch, ch == from ? fromOutside : toOutside, + xDiff < 0 ? -1 : xDiff ? 1 : 0); + return pos; + } + var step = Math.ceil(dist / 2), middle = from + step; + if (bidi) { + middle = from; + for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1); + } + var middleX = getX(middle); + if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step;} + else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step;} + } + } + + var measureText; + function textHeight(display) { + if (display.cachedTextHeight != null) return display.cachedTextHeight; + if (measureText == null) { + measureText = elt("pre"); + // Measure a bunch of lines, for browsers that compute + // fractional heights. + for (var i = 0; i < 49; ++i) { + measureText.appendChild(document.createTextNode("x")); + measureText.appendChild(elt("br")); + } + measureText.appendChild(document.createTextNode("x")); + } + removeChildrenAndAdd(display.measure, measureText); + var height = measureText.offsetHeight / 50; + if (height > 3) display.cachedTextHeight = height; + removeChildren(display.measure); + return height || 1; + } + + function charWidth(display) { + if (display.cachedCharWidth != null) return display.cachedCharWidth; + var anchor = elt("span", "x"); + var pre = elt("pre", [anchor]); + removeChildrenAndAdd(display.measure, pre); + var width = anchor.offsetWidth; + if (width > 2) display.cachedCharWidth = width; + return width || 10; + } + + // OPERATIONS + + // Operations are used to wrap changes in such a way that each + // change won't have to update the cursor and display (which would + // be awkward, slow, and error-prone), but instead updates are + // batched and then all combined and executed at once. + + var nextOpId = 0; + function startOperation(cm) { + cm.curOp = { + // An array of ranges of lines that have to be updated. See + // updateDisplay. + changes: [], + forceUpdate: false, + updateInput: null, + userSelChange: null, + textChanged: null, + selectionChanged: false, + cursorActivity: false, + updateMaxLine: false, + updateScrollPos: false, + id: ++nextOpId + }; + if (!delayedCallbackDepth++) delayedCallbacks = []; + } + + function endOperation(cm) { + var op = cm.curOp, doc = cm.doc, display = cm.display; + cm.curOp = null; + + if (op.updateMaxLine) computeMaxLength(cm); + if (display.maxLineChanged && !cm.options.lineWrapping && display.maxLine) { + var width = measureLineWidth(cm, display.maxLine); + display.sizer.style.minWidth = Math.max(0, width + 3 + scrollerCutOff) + "px"; + display.maxLineChanged = false; + var maxScrollLeft = Math.max(0, display.sizer.offsetLeft + display.sizer.offsetWidth - display.scroller.clientWidth); + if (maxScrollLeft < doc.scrollLeft && !op.updateScrollPos) + setScrollLeft(cm, Math.min(display.scroller.scrollLeft, maxScrollLeft), true); + } + var newScrollPos, updated; + if (op.updateScrollPos) { + newScrollPos = op.updateScrollPos; + } else if (op.selectionChanged && display.scroller.clientHeight) { // don't rescroll if not visible + var coords = cursorCoords(cm, doc.sel.head); + newScrollPos = calculateScrollPos(cm, coords.left, coords.top, coords.left, coords.bottom); + } + if (op.changes.length || op.forceUpdate || newScrollPos && newScrollPos.scrollTop != null) { + updated = updateDisplay(cm, op.changes, newScrollPos && newScrollPos.scrollTop, op.forceUpdate); + if (cm.display.scroller.offsetHeight) cm.doc.scrollTop = cm.display.scroller.scrollTop; + } + if (!updated && op.selectionChanged) updateSelection(cm); + if (op.updateScrollPos) { + display.scroller.scrollTop = display.scrollbarV.scrollTop = doc.scrollTop = newScrollPos.scrollTop; + display.scroller.scrollLeft = display.scrollbarH.scrollLeft = doc.scrollLeft = newScrollPos.scrollLeft; + alignHorizontally(cm); + if (op.scrollToPos) + scrollPosIntoView(cm, clipPos(cm.doc, op.scrollToPos), op.scrollToPosMargin); + } else if (newScrollPos) { + scrollCursorIntoView(cm); + } + if (op.selectionChanged) restartBlink(cm); + + if (cm.state.focused && op.updateInput) + resetInput(cm, op.userSelChange); + + var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers; + if (hidden) for (var i = 0; i < hidden.length; ++i) + if (!hidden[i].lines.length) signal(hidden[i], "hide"); + if (unhidden) for (var i = 0; i < unhidden.length; ++i) + if (unhidden[i].lines.length) signal(unhidden[i], "unhide"); + + var delayed; + if (!--delayedCallbackDepth) { + delayed = delayedCallbacks; + delayedCallbacks = null; + } + if (op.textChanged) + signal(cm, "change", cm, op.textChanged); + if (op.cursorActivity) signal(cm, "cursorActivity", cm); + if (delayed) for (var i = 0; i < delayed.length; ++i) delayed[i](); + } + + // Wraps a function in an operation. Returns the wrapped function. + function operation(cm1, f) { + return function() { + var cm = cm1 || this, withOp = !cm.curOp; + if (withOp) startOperation(cm); + try { var result = f.apply(cm, arguments); } + finally { if (withOp) endOperation(cm); } + return result; + }; + } + function docOperation(f) { + return function() { + var withOp = this.cm && !this.cm.curOp, result; + if (withOp) startOperation(this.cm); + try { result = f.apply(this, arguments); } + finally { if (withOp) endOperation(this.cm); } + return result; + }; + } + function runInOp(cm, f) { + var withOp = !cm.curOp, result; + if (withOp) startOperation(cm); + try { result = f(); } + finally { if (withOp) endOperation(cm); } + return result; + } + + function regChange(cm, from, to, lendiff) { + if (from == null) from = cm.doc.first; + if (to == null) to = cm.doc.first + cm.doc.size; + cm.curOp.changes.push({from: from, to: to, diff: lendiff}); + } + + // INPUT HANDLING + + function slowPoll(cm) { + if (cm.display.pollingFast) return; + cm.display.poll.set(cm.options.pollInterval, function() { + readInput(cm); + if (cm.state.focused) slowPoll(cm); + }); + } + + function fastPoll(cm) { + var missed = false; + cm.display.pollingFast = true; + function p() { + var changed = readInput(cm); + if (!changed && !missed) {missed = true; cm.display.poll.set(60, p);} + else {cm.display.pollingFast = false; slowPoll(cm);} + } + cm.display.poll.set(20, p); + } + + // prevInput is a hack to work with IME. If we reset the textarea + // on every change, that breaks IME. So we look for changes + // compared to the previous content instead. (Modern browsers have + // events that indicate IME taking place, but these are not widely + // supported or compatible enough yet to rely on.) + function readInput(cm) { + var input = cm.display.input, prevInput = cm.display.prevInput, doc = cm.doc, sel = doc.sel; + if (!cm.state.focused || hasSelection(input) || isReadOnly(cm) || cm.state.disableInput) return false; + var text = input.value; + if (text == prevInput && posEq(sel.from, sel.to)) return false; + if (ie && !ie_lt9 && cm.display.inputHasSelection === text) { + resetInput(cm, true); + return false; + } + + var withOp = !cm.curOp; + if (withOp) startOperation(cm); + sel.shift = false; + var same = 0, l = Math.min(prevInput.length, text.length); + while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same; + var from = sel.from, to = sel.to; + if (same < prevInput.length) + from = Pos(from.line, from.ch - (prevInput.length - same)); + else if (cm.state.overwrite && posEq(from, to) && !cm.state.pasteIncoming) + to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + (text.length - same))); + + var updateInput = cm.curOp.updateInput; + var changeEvent = {from: from, to: to, text: splitLines(text.slice(same)), + origin: cm.state.pasteIncoming ? "paste" : "+input"}; + makeChange(cm.doc, changeEvent, "end"); + cm.curOp.updateInput = updateInput; + signalLater(cm, "inputRead", cm, changeEvent); + + if (text.length > 1000 || text.indexOf("\n") > -1) input.value = cm.display.prevInput = ""; + else cm.display.prevInput = text; + if (withOp) endOperation(cm); + cm.state.pasteIncoming = false; + return true; + } + + function resetInput(cm, user) { + var minimal, selected, doc = cm.doc; + if (!posEq(doc.sel.from, doc.sel.to)) { + cm.display.prevInput = ""; + minimal = hasCopyEvent && + (doc.sel.to.line - doc.sel.from.line > 100 || (selected = cm.getSelection()).length > 1000); + var content = minimal ? "-" : selected || cm.getSelection(); + cm.display.input.value = content; + if (cm.state.focused) selectInput(cm.display.input); + if (ie && !ie_lt9) cm.display.inputHasSelection = content; + } else if (user) { + cm.display.prevInput = cm.display.input.value = ""; + if (ie && !ie_lt9) cm.display.inputHasSelection = null; + } + cm.display.inaccurateSelection = minimal; + } + + function focusInput(cm) { + if (cm.options.readOnly != "nocursor" && (!mobile || document.activeElement != cm.display.input)) + cm.display.input.focus(); + } + + function isReadOnly(cm) { + return cm.options.readOnly || cm.doc.cantEdit; + } + + // EVENT HANDLERS + + function registerEventHandlers(cm) { + var d = cm.display; + on(d.scroller, "mousedown", operation(cm, onMouseDown)); + if (ie) + on(d.scroller, "dblclick", operation(cm, function(e) { + if (signalDOMEvent(cm, e)) return; + var pos = posFromMouse(cm, e); + if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return; + e_preventDefault(e); + var word = findWordAt(getLine(cm.doc, pos.line).text, pos); + extendSelection(cm.doc, word.from, word.to); + })); + else + on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preventDefault(e); }); + on(d.lineSpace, "selectstart", function(e) { + if (!eventInWidget(d, e)) e_preventDefault(e); + }); + // Gecko browsers fire contextmenu *after* opening the menu, at + // which point we can't mess with it anymore. Context menu is + // handled in onMouseDown for Gecko. + if (!captureMiddleClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);}); + + on(d.scroller, "scroll", function() { + if (d.scroller.clientHeight) { + setScrollTop(cm, d.scroller.scrollTop); + setScrollLeft(cm, d.scroller.scrollLeft, true); + signal(cm, "scroll", cm); + } + }); + on(d.scrollbarV, "scroll", function() { + if (d.scroller.clientHeight) setScrollTop(cm, d.scrollbarV.scrollTop); + }); + on(d.scrollbarH, "scroll", function() { + if (d.scroller.clientHeight) setScrollLeft(cm, d.scrollbarH.scrollLeft); + }); + + on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);}); + on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);}); + + function reFocus() { if (cm.state.focused) setTimeout(bind(focusInput, cm), 0); } + on(d.scrollbarH, "mousedown", reFocus); + on(d.scrollbarV, "mousedown", reFocus); + // Prevent wrapper from ever scrolling + on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; }); + + var resizeTimer; + function onResize() { + if (resizeTimer == null) resizeTimer = setTimeout(function() { + resizeTimer = null; + // Might be a text scaling operation, clear size caches. + d.cachedCharWidth = d.cachedTextHeight = knownScrollbarWidth = null; + clearCaches(cm); + runInOp(cm, bind(regChange, cm)); + }, 100); + } + on(window, "resize", onResize); + // Above handler holds on to the editor and its data structures. + // Here we poll to unregister it when the editor is no longer in + // the document, so that it can be garbage-collected. + function unregister() { + for (var p = d.wrapper.parentNode; p && p != document.body; p = p.parentNode) {} + if (p) setTimeout(unregister, 5000); + else off(window, "resize", onResize); + } + setTimeout(unregister, 5000); + + on(d.input, "keyup", operation(cm, function(e) { + if (signalDOMEvent(cm, e) || cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return; + if (e.keyCode == 16) cm.doc.sel.shift = false; + })); + on(d.input, "input", bind(fastPoll, cm)); + on(d.input, "keydown", operation(cm, onKeyDown)); + on(d.input, "keypress", operation(cm, onKeyPress)); + on(d.input, "focus", bind(onFocus, cm)); + on(d.input, "blur", bind(onBlur, cm)); + + function drag_(e) { + if (signalDOMEvent(cm, e) || cm.options.onDragEvent && cm.options.onDragEvent(cm, addStop(e))) return; + e_stop(e); + } + if (cm.options.dragDrop) { + on(d.scroller, "dragstart", function(e){onDragStart(cm, e);}); + on(d.scroller, "dragenter", drag_); + on(d.scroller, "dragover", drag_); + on(d.scroller, "drop", operation(cm, onDrop)); + } + on(d.scroller, "paste", function(e){ + if (eventInWidget(d, e)) return; + focusInput(cm); + fastPoll(cm); + }); + on(d.input, "paste", function() { + cm.state.pasteIncoming = true; + fastPoll(cm); + }); + + function prepareCopy() { + if (d.inaccurateSelection) { + d.prevInput = ""; + d.inaccurateSelection = false; + d.input.value = cm.getSelection(); + selectInput(d.input); + } + } + on(d.input, "cut", prepareCopy); + on(d.input, "copy", prepareCopy); + + // Needed to handle Tab key in KHTML + if (khtml) on(d.sizer, "mouseup", function() { + if (document.activeElement == d.input) d.input.blur(); + focusInput(cm); + }); + } + + function eventInWidget(display, e) { + for (var n = e_target(e); n != display.wrapper; n = n.parentNode) { + if (!n || n.ignoreEvents || n.parentNode == display.sizer && n != display.mover) return true; + } + } + + function posFromMouse(cm, e, liberal) { + var display = cm.display; + if (!liberal) { + var target = e_target(e); + if (target == display.scrollbarH || target == display.scrollbarH.firstChild || + target == display.scrollbarV || target == display.scrollbarV.firstChild || + target == display.scrollbarFiller || target == display.gutterFiller) return null; + } + var x, y, space = getRect(display.lineSpace); + // Fails unpredictably on IE[67] when mouse is dragged around quickly. + try { x = e.clientX; y = e.clientY; } catch (e) { return null; } + return coordsChar(cm, x - space.left, y - space.top); + } + + var lastClick, lastDoubleClick; + function onMouseDown(e) { + if (signalDOMEvent(this, e)) return; + var cm = this, display = cm.display, doc = cm.doc, sel = doc.sel; + sel.shift = e.shiftKey; + + if (eventInWidget(display, e)) { + if (!webkit) { + display.scroller.draggable = false; + setTimeout(function(){display.scroller.draggable = true;}, 100); + } + return; + } + if (clickInGutter(cm, e)) return; + var start = posFromMouse(cm, e); + + switch (e_button(e)) { + case 3: + if (captureMiddleClick) onContextMenu.call(cm, cm, e); + return; + case 2: + if (start) extendSelection(cm.doc, start); + setTimeout(bind(focusInput, cm), 20); + e_preventDefault(e); + return; + } + // For button 1, if it was clicked inside the editor + // (posFromMouse returning non-null), we have to adjust the + // selection. + if (!start) {if (e_target(e) == display.scroller) e_preventDefault(e); return;} + + if (!cm.state.focused) onFocus(cm); + + var now = +new Date, type = "single"; + if (lastDoubleClick && lastDoubleClick.time > now - 400 && posEq(lastDoubleClick.pos, start)) { + type = "triple"; + e_preventDefault(e); + setTimeout(bind(focusInput, cm), 20); + selectLine(cm, start.line); + } else if (lastClick && lastClick.time > now - 400 && posEq(lastClick.pos, start)) { + type = "double"; + lastDoubleClick = {time: now, pos: start}; + e_preventDefault(e); + var word = findWordAt(getLine(doc, start.line).text, start); + extendSelection(cm.doc, word.from, word.to); + } else { lastClick = {time: now, pos: start}; } + + var last = start; + if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) && !posEq(sel.from, sel.to) && + !posLess(start, sel.from) && !posLess(sel.to, start) && type == "single") { + var dragEnd = operation(cm, function(e2) { + if (webkit) display.scroller.draggable = false; + cm.state.draggingText = false; + off(document, "mouseup", dragEnd); + off(display.scroller, "drop", dragEnd); + if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) { + e_preventDefault(e2); + extendSelection(cm.doc, start); + focusInput(cm); + } + }); + // Let the drag handler handle this. + if (webkit) display.scroller.draggable = true; + cm.state.draggingText = dragEnd; + // IE's approach to draggable + if (display.scroller.dragDrop) display.scroller.dragDrop(); + on(document, "mouseup", dragEnd); + on(display.scroller, "drop", dragEnd); + return; + } + e_preventDefault(e); + if (type == "single") extendSelection(cm.doc, clipPos(doc, start)); + + var startstart = sel.from, startend = sel.to, lastPos = start; + + function doSelect(cur) { + if (posEq(lastPos, cur)) return; + lastPos = cur; + + if (type == "single") { + extendSelection(cm.doc, clipPos(doc, start), cur); + return; + } + + startstart = clipPos(doc, startstart); + startend = clipPos(doc, startend); + if (type == "double") { + var word = findWordAt(getLine(doc, cur.line).text, cur); + if (posLess(cur, startstart)) extendSelection(cm.doc, word.from, startend); + else extendSelection(cm.doc, startstart, word.to); + } else if (type == "triple") { + if (posLess(cur, startstart)) extendSelection(cm.doc, startend, clipPos(doc, Pos(cur.line, 0))); + else extendSelection(cm.doc, startstart, clipPos(doc, Pos(cur.line + 1, 0))); + } + } + + var editorSize = getRect(display.wrapper); + // Used to ensure timeout re-tries don't fire when another extend + // happened in the meantime (clearTimeout isn't reliable -- at + // least on Chrome, the timeouts still happen even when cleared, + // if the clear happens after their scheduled firing time). + var counter = 0; + + function extend(e) { + var curCount = ++counter; + var cur = posFromMouse(cm, e, true); + if (!cur) return; + if (!posEq(cur, last)) { + if (!cm.state.focused) onFocus(cm); + last = cur; + doSelect(cur); + var visible = visibleLines(display, doc); + if (cur.line >= visible.to || cur.line < visible.from) + setTimeout(operation(cm, function(){if (counter == curCount) extend(e);}), 150); + } else { + var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0; + if (outside) setTimeout(operation(cm, function() { + if (counter != curCount) return; + display.scroller.scrollTop += outside; + extend(e); + }), 50); + } + } + + function done(e) { + counter = Infinity; + e_preventDefault(e); + focusInput(cm); + off(document, "mousemove", move); + off(document, "mouseup", up); + } + + var move = operation(cm, function(e) { + if (!ie && !e_button(e)) done(e); + else extend(e); + }); + var up = operation(cm, done); + on(document, "mousemove", move); + on(document, "mouseup", up); + } + + function clickInGutter(cm, e) { + var display = cm.display; + try { var mX = e.clientX, mY = e.clientY; } + catch(e) { return false; } + + if (mX >= Math.floor(getRect(display.gutters).right)) return false; + e_preventDefault(e); + if (!hasHandler(cm, "gutterClick")) return true; + + var lineBox = getRect(display.lineDiv); + if (mY > lineBox.bottom) return true; + mY -= lineBox.top - display.viewOffset; + + for (var i = 0; i < cm.options.gutters.length; ++i) { + var g = display.gutters.childNodes[i]; + if (g && getRect(g).right >= mX) { + var line = lineAtHeight(cm.doc, mY); + var gutter = cm.options.gutters[i]; + signalLater(cm, "gutterClick", cm, line, gutter, e); + break; + } + } + return true; + } + + // Kludge to work around strange IE behavior where it'll sometimes + // re-fire a series of drag-related events right after the drop (#1551) + var lastDrop = 0; + + function onDrop(e) { + var cm = this; + if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e) || (cm.options.onDragEvent && cm.options.onDragEvent(cm, addStop(e)))) + return; + e_preventDefault(e); + if (ie) lastDrop = +new Date; + var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files; + if (!pos || isReadOnly(cm)) return; + if (files && files.length && window.FileReader && window.File) { + var n = files.length, text = Array(n), read = 0; + var loadFile = function(file, i) { + var reader = new FileReader; + reader.onload = function() { + text[i] = reader.result; + if (++read == n) { + pos = clipPos(cm.doc, pos); + makeChange(cm.doc, {from: pos, to: pos, text: splitLines(text.join("\n")), origin: "paste"}, "around"); + } + }; + reader.readAsText(file); + }; + for (var i = 0; i < n; ++i) loadFile(files[i], i); + } else { + // Don't do a replace if the drop happened inside of the selected text. + if (cm.state.draggingText && !(posLess(pos, cm.doc.sel.from) || posLess(cm.doc.sel.to, pos))) { + cm.state.draggingText(e); + // Ensure the editor is re-focused + setTimeout(bind(focusInput, cm), 20); + return; + } + try { + var text = e.dataTransfer.getData("Text"); + if (text) { + var curFrom = cm.doc.sel.from, curTo = cm.doc.sel.to; + setSelection(cm.doc, pos, pos); + if (cm.state.draggingText) replaceRange(cm.doc, "", curFrom, curTo, "paste"); + cm.replaceSelection(text, null, "paste"); + focusInput(cm); + onFocus(cm); + } + } + catch(e){} + } + } + + function onDragStart(cm, e) { + if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; } + if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return; + + var txt = cm.getSelection(); + e.dataTransfer.setData("Text", txt); + + // Use dummy image instead of default browsers image. + // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there. + if (e.dataTransfer.setDragImage && !safari) { + var img = elt("img", null, null, "position: fixed; left: 0; top: 0;"); + if (opera) { + img.width = img.height = 1; + cm.display.wrapper.appendChild(img); + // Force a relayout, or Opera won't use our image for some obscure reason + img._top = img.offsetTop; + } + e.dataTransfer.setDragImage(img, 0, 0); + if (opera) img.parentNode.removeChild(img); + } + } + + function setScrollTop(cm, val) { + if (Math.abs(cm.doc.scrollTop - val) < 2) return; + cm.doc.scrollTop = val; + if (!gecko) updateDisplay(cm, [], val); + if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val; + if (cm.display.scrollbarV.scrollTop != val) cm.display.scrollbarV.scrollTop = val; + if (gecko) updateDisplay(cm, []); + startWorker(cm, 100); + } + function setScrollLeft(cm, val, isScroller) { + if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return; + val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth); + cm.doc.scrollLeft = val; + alignHorizontally(cm); + if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val; + if (cm.display.scrollbarH.scrollLeft != val) cm.display.scrollbarH.scrollLeft = val; + } + + // Since the delta values reported on mouse wheel events are + // unstandardized between browsers and even browser versions, and + // generally horribly unpredictable, this code starts by measuring + // the scroll effect that the first few mouse wheel events have, + // and, from that, detects the way it can convert deltas to pixel + // offsets afterwards. + // + // The reason we want to know the amount a wheel event will scroll + // is that it gives us a chance to update the display before the + // actual scrolling happens, reducing flickering. + + var wheelSamples = 0, wheelPixelsPerUnit = null; + // Fill in a browser-detected starting value on browsers where we + // know one. These don't have to be accurate -- the result of them + // being wrong would just be a slight flicker on the first wheel + // scroll (if it is large enough). + if (ie) wheelPixelsPerUnit = -.53; + else if (gecko) wheelPixelsPerUnit = 15; + else if (chrome) wheelPixelsPerUnit = -.7; + else if (safari) wheelPixelsPerUnit = -1/3; + + function onScrollWheel(cm, e) { + var dx = e.wheelDeltaX, dy = e.wheelDeltaY; + if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail; + if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail; + else if (dy == null) dy = e.wheelDelta; + + var display = cm.display, scroll = display.scroller; + // Quit if there's nothing to scroll here + if (!(dx && scroll.scrollWidth > scroll.clientWidth || + dy && scroll.scrollHeight > scroll.clientHeight)) return; + + // Webkit browsers on OS X abort momentum scrolls when the target + // of the scroll event is removed from the scrollable element. + // This hack (see related code in patchDisplay) makes sure the + // element is kept around. + if (dy && mac && webkit) { + for (var cur = e.target; cur != scroll; cur = cur.parentNode) { + if (cur.lineObj) { + cm.display.currentWheelTarget = cur; + break; + } + } + } + + // On some browsers, horizontal scrolling will cause redraws to + // happen before the gutter has been realigned, causing it to + // wriggle around in a most unseemly way. When we have an + // estimated pixels/delta value, we just handle horizontal + // scrolling entirely here. It'll be slightly off from native, but + // better than glitching out. + if (dx && !gecko && !opera && wheelPixelsPerUnit != null) { + if (dy) + setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight))); + setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth))); + e_preventDefault(e); + display.wheelStartX = null; // Abort measurement, if in progress + return; + } + + if (dy && wheelPixelsPerUnit != null) { + var pixels = dy * wheelPixelsPerUnit; + var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight; + if (pixels < 0) top = Math.max(0, top + pixels - 50); + else bot = Math.min(cm.doc.height, bot + pixels + 50); + updateDisplay(cm, [], {top: top, bottom: bot}); + } + + if (wheelSamples < 20) { + if (display.wheelStartX == null) { + display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop; + display.wheelDX = dx; display.wheelDY = dy; + setTimeout(function() { + if (display.wheelStartX == null) return; + var movedX = scroll.scrollLeft - display.wheelStartX; + var movedY = scroll.scrollTop - display.wheelStartY; + var sample = (movedY && display.wheelDY && movedY / display.wheelDY) || + (movedX && display.wheelDX && movedX / display.wheelDX); + display.wheelStartX = display.wheelStartY = null; + if (!sample) return; + wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1); + ++wheelSamples; + }, 200); + } else { + display.wheelDX += dx; display.wheelDY += dy; + } + } + } + + function doHandleBinding(cm, bound, dropShift) { + if (typeof bound == "string") { + bound = commands[bound]; + if (!bound) return false; + } + // Ensure previous input has been read, so that the handler sees a + // consistent view of the document + if (cm.display.pollingFast && readInput(cm)) cm.display.pollingFast = false; + var doc = cm.doc, prevShift = doc.sel.shift, done = false; + try { + if (isReadOnly(cm)) cm.state.suppressEdits = true; + if (dropShift) doc.sel.shift = false; + done = bound(cm) != Pass; + } finally { + doc.sel.shift = prevShift; + cm.state.suppressEdits = false; + } + return done; + } + + function allKeyMaps(cm) { + var maps = cm.state.keyMaps.slice(0); + if (cm.options.extraKeys) maps.push(cm.options.extraKeys); + maps.push(cm.options.keyMap); + return maps; + } + + var maybeTransition; + function handleKeyBinding(cm, e) { + // Handle auto keymap transitions + var startMap = getKeyMap(cm.options.keyMap), next = startMap.auto; + clearTimeout(maybeTransition); + if (next && !isModifierKey(e)) maybeTransition = setTimeout(function() { + if (getKeyMap(cm.options.keyMap) == startMap) { + cm.options.keyMap = (next.call ? next.call(null, cm) : next); + keyMapChanged(cm); + } + }, 50); + + var name = keyName(e, true), handled = false; + if (!name) return false; + var keymaps = allKeyMaps(cm); + + if (e.shiftKey) { + // First try to resolve full name (including 'Shift-'). Failing + // that, see if there is a cursor-motion command (starting with + // 'go') bound to the keyname without 'Shift-'. + handled = lookupKey("Shift-" + name, keymaps, function(b) {return doHandleBinding(cm, b, true);}) + || lookupKey(name, keymaps, function(b) { + if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion) + return doHandleBinding(cm, b); + }); + } else { + handled = lookupKey(name, keymaps, function(b) { return doHandleBinding(cm, b); }); + } + + if (handled) { + e_preventDefault(e); + restartBlink(cm); + if (ie_lt9) { e.oldKeyCode = e.keyCode; e.keyCode = 0; } + signalLater(cm, "keyHandled", cm, name, e); + } + return handled; + } + + function handleCharBinding(cm, e, ch) { + var handled = lookupKey("'" + ch + "'", allKeyMaps(cm), + function(b) { return doHandleBinding(cm, b, true); }); + if (handled) { + e_preventDefault(e); + restartBlink(cm); + signalLater(cm, "keyHandled", cm, "'" + ch + "'", e); + } + return handled; + } + + var lastStoppedKey = null; + function onKeyDown(e) { + var cm = this; + if (!cm.state.focused) onFocus(cm); + if (ie && e.keyCode == 27) { e.returnValue = false; } + if (signalDOMEvent(cm, e) || cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return; + var code = e.keyCode; + // IE does strange things with escape. + cm.doc.sel.shift = code == 16 || e.shiftKey; + // First give onKeyEvent option a chance to handle this. + var handled = handleKeyBinding(cm, e); + if (opera) { + lastStoppedKey = handled ? code : null; + // Opera has no cut event... we try to at least catch the key combo + if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey)) + cm.replaceSelection(""); + } + } + + function onKeyPress(e) { + var cm = this; + if (signalDOMEvent(cm, e) || cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return; + var keyCode = e.keyCode, charCode = e.charCode; + if (opera && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;} + if (((opera && (!e.which || e.which < 10)) || khtml) && handleKeyBinding(cm, e)) return; + var ch = String.fromCharCode(charCode == null ? keyCode : charCode); + if (this.options.electricChars && this.doc.mode.electricChars && + this.options.smartIndent && !isReadOnly(this) && + this.doc.mode.electricChars.indexOf(ch) > -1) + setTimeout(operation(cm, function() {indentLine(cm, cm.doc.sel.to.line, "smart");}), 75); + if (handleCharBinding(cm, e, ch)) return; + if (ie && !ie_lt9) cm.display.inputHasSelection = null; + fastPoll(cm); + } + + function onFocus(cm) { + if (cm.options.readOnly == "nocursor") return; + if (!cm.state.focused) { + signal(cm, "focus", cm); + cm.state.focused = true; + if (cm.display.wrapper.className.search(/\bCodeMirror-focused\b/) == -1) + cm.display.wrapper.className += " CodeMirror-focused"; + resetInput(cm, true); + } + slowPoll(cm); + restartBlink(cm); + } + function onBlur(cm) { + if (cm.state.focused) { + signal(cm, "blur", cm); + cm.state.focused = false; + cm.display.wrapper.className = cm.display.wrapper.className.replace(" CodeMirror-focused", ""); + } + clearInterval(cm.display.blinker); + setTimeout(function() {if (!cm.state.focused) cm.doc.sel.shift = false;}, 150); + } + + var detectingSelectAll; + function onContextMenu(cm, e) { + if (signalDOMEvent(cm, e, "contextmenu")) return; + var display = cm.display, sel = cm.doc.sel; + if (eventInWidget(display, e)) return; + + var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop; + if (!pos || opera) return; // Opera is difficult. + if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.to)) + operation(cm, setSelection)(cm.doc, pos, pos); + + var oldCSS = display.input.style.cssText; + display.inputDiv.style.position = "absolute"; + display.input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) + + "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: white; outline: none;" + + "border-width: 0; outline: none; overflow: hidden; opacity: .05; -ms-opacity: .05; filter: alpha(opacity=5);"; + focusInput(cm); + resetInput(cm, true); + // Adds "Select all" to context menu in FF + if (posEq(sel.from, sel.to)) display.input.value = display.prevInput = " "; + + function prepareSelectAllHack() { + if (display.input.selectionStart != null) { + var extval = display.input.value = " " + (posEq(sel.from, sel.to) ? "" : display.input.value); + display.prevInput = " "; + display.input.selectionStart = 1; display.input.selectionEnd = extval.length; + } + } + function rehide() { + display.inputDiv.style.position = "relative"; + display.input.style.cssText = oldCSS; + if (ie_lt9) display.scrollbarV.scrollTop = display.scroller.scrollTop = scrollPos; + slowPoll(cm); + + // Try to detect the user choosing select-all + if (display.input.selectionStart != null) { + if (!ie || ie_lt9) prepareSelectAllHack(); + clearTimeout(detectingSelectAll); + var i = 0, poll = function(){ + if (display.prevInput == " " && display.input.selectionStart == 0) + operation(cm, commands.selectAll)(cm); + else if (i++ < 10) detectingSelectAll = setTimeout(poll, 500); + else resetInput(cm); + }; + detectingSelectAll = setTimeout(poll, 200); + } + } + + if (ie && !ie_lt9) prepareSelectAllHack(); + if (captureMiddleClick) { + e_stop(e); + var mouseup = function() { + off(window, "mouseup", mouseup); + setTimeout(rehide, 20); + }; + on(window, "mouseup", mouseup); + } else { + setTimeout(rehide, 50); + } + } + + // UPDATING + + var changeEnd = CodeMirror.changeEnd = function(change) { + if (!change.text) return change.to; + return Pos(change.from.line + change.text.length - 1, + lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0)); + }; + + // Make sure a position will be valid after the given change. + function clipPostChange(doc, change, pos) { + if (!posLess(change.from, pos)) return clipPos(doc, pos); + var diff = (change.text.length - 1) - (change.to.line - change.from.line); + if (pos.line > change.to.line + diff) { + var preLine = pos.line - diff, lastLine = doc.first + doc.size - 1; + if (preLine > lastLine) return Pos(lastLine, getLine(doc, lastLine).text.length); + return clipToLen(pos, getLine(doc, preLine).text.length); + } + if (pos.line == change.to.line + diff) + return clipToLen(pos, lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0) + + getLine(doc, change.to.line).text.length - change.to.ch); + var inside = pos.line - change.from.line; + return clipToLen(pos, change.text[inside].length + (inside ? 0 : change.from.ch)); + } + + // Hint can be null|"end"|"start"|"around"|{anchor,head} + function computeSelAfterChange(doc, change, hint) { + if (hint && typeof hint == "object") // Assumed to be {anchor, head} object + return {anchor: clipPostChange(doc, change, hint.anchor), + head: clipPostChange(doc, change, hint.head)}; + + if (hint == "start") return {anchor: change.from, head: change.from}; + + var end = changeEnd(change); + if (hint == "around") return {anchor: change.from, head: end}; + if (hint == "end") return {anchor: end, head: end}; + + // hint is null, leave the selection alone as much as possible + var adjustPos = function(pos) { + if (posLess(pos, change.from)) return pos; + if (!posLess(change.to, pos)) return end; + + var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch; + if (pos.line == change.to.line) ch += end.ch - change.to.ch; + return Pos(line, ch); + }; + return {anchor: adjustPos(doc.sel.anchor), head: adjustPos(doc.sel.head)}; + } + + function filterChange(doc, change, update) { + var obj = { + canceled: false, + from: change.from, + to: change.to, + text: change.text, + origin: change.origin, + cancel: function() { this.canceled = true; } + }; + if (update) obj.update = function(from, to, text, origin) { + if (from) this.from = clipPos(doc, from); + if (to) this.to = clipPos(doc, to); + if (text) this.text = text; + if (origin !== undefined) this.origin = origin; + }; + signal(doc, "beforeChange", doc, obj); + if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj); + + if (obj.canceled) return null; + return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}; + } + + // Replace the range from from to to by the strings in replacement. + // change is a {from, to, text [, origin]} object + function makeChange(doc, change, selUpdate, ignoreReadOnly) { + if (doc.cm) { + if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, selUpdate, ignoreReadOnly); + if (doc.cm.state.suppressEdits) return; + } + + if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) { + change = filterChange(doc, change, true); + if (!change) return; + } + + // Possibly split or suppress the update based on the presence + // of read-only spans in its range. + var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to); + if (split) { + for (var i = split.length - 1; i >= 1; --i) + makeChangeNoReadonly(doc, {from: split[i].from, to: split[i].to, text: [""]}); + if (split.length) + makeChangeNoReadonly(doc, {from: split[0].from, to: split[0].to, text: change.text}, selUpdate); + } else { + makeChangeNoReadonly(doc, change, selUpdate); + } + } + + function makeChangeNoReadonly(doc, change, selUpdate) { + var selAfter = computeSelAfterChange(doc, change, selUpdate); + addToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN); + + makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change)); + var rebased = []; + + linkedDocs(doc, function(doc, sharedHist) { + if (!sharedHist && indexOf(rebased, doc.history) == -1) { + rebaseHist(doc.history, change); + rebased.push(doc.history); + } + makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change)); + }); + } + + function makeChangeFromHistory(doc, type) { + if (doc.cm && doc.cm.state.suppressEdits) return; + + var hist = doc.history; + var event = (type == "undo" ? hist.done : hist.undone).pop(); + if (!event) return; + + var anti = {changes: [], anchorBefore: event.anchorAfter, headBefore: event.headAfter, + anchorAfter: event.anchorBefore, headAfter: event.headBefore, + generation: hist.generation}; + (type == "undo" ? hist.undone : hist.done).push(anti); + hist.generation = event.generation || ++hist.maxGeneration; + + var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange"); + + for (var i = event.changes.length - 1; i >= 0; --i) { + var change = event.changes[i]; + change.origin = type; + if (filter && !filterChange(doc, change, false)) { + (type == "undo" ? hist.done : hist.undone).length = 0; + return; + } + + anti.changes.push(historyChangeFromChange(doc, change)); + + var after = i ? computeSelAfterChange(doc, change, null) + : {anchor: event.anchorBefore, head: event.headBefore}; + makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change)); + var rebased = []; + + linkedDocs(doc, function(doc, sharedHist) { + if (!sharedHist && indexOf(rebased, doc.history) == -1) { + rebaseHist(doc.history, change); + rebased.push(doc.history); + } + makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change)); + }); + } + } + + function shiftDoc(doc, distance) { + function shiftPos(pos) {return Pos(pos.line + distance, pos.ch);} + doc.first += distance; + if (doc.cm) regChange(doc.cm, doc.first, doc.first, distance); + doc.sel.head = shiftPos(doc.sel.head); doc.sel.anchor = shiftPos(doc.sel.anchor); + doc.sel.from = shiftPos(doc.sel.from); doc.sel.to = shiftPos(doc.sel.to); + } + + function makeChangeSingleDoc(doc, change, selAfter, spans) { + if (doc.cm && !doc.cm.curOp) + return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans); + + if (change.to.line < doc.first) { + shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line)); + return; + } + if (change.from.line > doc.lastLine()) return; + + // Clip the change to the size of this doc + if (change.from.line < doc.first) { + var shift = change.text.length - 1 - (doc.first - change.from.line); + shiftDoc(doc, shift); + change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch), + text: [lst(change.text)], origin: change.origin}; + } + var last = doc.lastLine(); + if (change.to.line > last) { + change = {from: change.from, to: Pos(last, getLine(doc, last).text.length), + text: [change.text[0]], origin: change.origin}; + } + + change.removed = getBetween(doc, change.from, change.to); + + if (!selAfter) selAfter = computeSelAfterChange(doc, change, null); + if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans, selAfter); + else updateDoc(doc, change, spans, selAfter); + } + + function makeChangeSingleDocInEditor(cm, change, spans, selAfter) { + var doc = cm.doc, display = cm.display, from = change.from, to = change.to; + + var recomputeMaxLength = false, checkWidthStart = from.line; + if (!cm.options.lineWrapping) { + checkWidthStart = lineNo(visualLine(doc, getLine(doc, from.line))); + doc.iter(checkWidthStart, to.line + 1, function(line) { + if (line == display.maxLine) { + recomputeMaxLength = true; + return true; + } + }); + } + + if (!posLess(doc.sel.head, change.from) && !posLess(change.to, doc.sel.head)) + cm.curOp.cursorActivity = true; + + updateDoc(doc, change, spans, selAfter, estimateHeight(cm)); + + if (!cm.options.lineWrapping) { + doc.iter(checkWidthStart, from.line + change.text.length, function(line) { + var len = lineLength(doc, line); + if (len > display.maxLineLength) { + display.maxLine = line; + display.maxLineLength = len; + display.maxLineChanged = true; + recomputeMaxLength = false; + } + }); + if (recomputeMaxLength) cm.curOp.updateMaxLine = true; + } + + // Adjust frontier, schedule worker + doc.frontier = Math.min(doc.frontier, from.line); + startWorker(cm, 400); + + var lendiff = change.text.length - (to.line - from.line) - 1; + // Remember that these lines changed, for updating the display + regChange(cm, from.line, to.line + 1, lendiff); + + if (hasHandler(cm, "change")) { + var changeObj = {from: from, to: to, + text: change.text, + removed: change.removed, + origin: change.origin}; + if (cm.curOp.textChanged) { + for (var cur = cm.curOp.textChanged; cur.next; cur = cur.next) {} + cur.next = changeObj; + } else cm.curOp.textChanged = changeObj; + } + } + + function replaceRange(doc, code, from, to, origin) { + if (!to) to = from; + if (posLess(to, from)) { var tmp = to; to = from; from = tmp; } + if (typeof code == "string") code = splitLines(code); + makeChange(doc, {from: from, to: to, text: code, origin: origin}, null); + } + + // POSITION OBJECT + + function Pos(line, ch) { + if (!(this instanceof Pos)) return new Pos(line, ch); + this.line = line; this.ch = ch; + } + CodeMirror.Pos = Pos; + + function posEq(a, b) {return a.line == b.line && a.ch == b.ch;} + function posLess(a, b) {return a.line < b.line || (a.line == b.line && a.ch < b.ch);} + function copyPos(x) {return Pos(x.line, x.ch);} + + // SELECTION + + function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1));} + function clipPos(doc, pos) { + if (pos.line < doc.first) return Pos(doc.first, 0); + var last = doc.first + doc.size - 1; + if (pos.line > last) return Pos(last, getLine(doc, last).text.length); + return clipToLen(pos, getLine(doc, pos.line).text.length); + } + function clipToLen(pos, linelen) { + var ch = pos.ch; + if (ch == null || ch > linelen) return Pos(pos.line, linelen); + else if (ch < 0) return Pos(pos.line, 0); + else return pos; + } + function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size;} + + // If shift is held, this will move the selection anchor. Otherwise, + // it'll set the whole selection. + function extendSelection(doc, pos, other, bias) { + if (doc.sel.shift || doc.sel.extend) { + var anchor = doc.sel.anchor; + if (other) { + var posBefore = posLess(pos, anchor); + if (posBefore != posLess(other, anchor)) { + anchor = pos; + pos = other; + } else if (posBefore != posLess(pos, other)) { + pos = other; + } + } + setSelection(doc, anchor, pos, bias); + } else { + setSelection(doc, pos, other || pos, bias); + } + if (doc.cm) doc.cm.curOp.userSelChange = true; + } + + function filterSelectionChange(doc, anchor, head) { + var obj = {anchor: anchor, head: head}; + signal(doc, "beforeSelectionChange", doc, obj); + if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj); + obj.anchor = clipPos(doc, obj.anchor); obj.head = clipPos(doc, obj.head); + return obj; + } + + // Update the selection. Last two args are only used by + // updateDoc, since they have to be expressed in the line + // numbers before the update. + function setSelection(doc, anchor, head, bias, checkAtomic) { + if (!checkAtomic && hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange")) { + var filtered = filterSelectionChange(doc, anchor, head); + head = filtered.head; + anchor = filtered.anchor; + } + + var sel = doc.sel; + sel.goalColumn = null; + // Skip over atomic spans. + if (checkAtomic || !posEq(anchor, sel.anchor)) + anchor = skipAtomic(doc, anchor, bias, checkAtomic != "push"); + if (checkAtomic || !posEq(head, sel.head)) + head = skipAtomic(doc, head, bias, checkAtomic != "push"); + + if (posEq(sel.anchor, anchor) && posEq(sel.head, head)) return; + + sel.anchor = anchor; sel.head = head; + var inv = posLess(head, anchor); + sel.from = inv ? head : anchor; + sel.to = inv ? anchor : head; + + if (doc.cm) + doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = + doc.cm.curOp.cursorActivity = true; + + signalLater(doc, "cursorActivity", doc); + } + + function reCheckSelection(cm) { + setSelection(cm.doc, cm.doc.sel.from, cm.doc.sel.to, null, "push"); + } + + function skipAtomic(doc, pos, bias, mayClear) { + var flipped = false, curPos = pos; + var dir = bias || 1; + doc.cantEdit = false; + search: for (;;) { + var line = getLine(doc, curPos.line); + if (line.markedSpans) { + for (var i = 0; i < line.markedSpans.length; ++i) { + var sp = line.markedSpans[i], m = sp.marker; + if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) && + (sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) { + if (mayClear) { + signal(m, "beforeCursorEnter"); + if (m.explicitlyCleared) { + if (!line.markedSpans) break; + else {--i; continue;} + } + } + if (!m.atomic) continue; + var newPos = m.find()[dir < 0 ? "from" : "to"]; + if (posEq(newPos, curPos)) { + newPos.ch += dir; + if (newPos.ch < 0) { + if (newPos.line > doc.first) newPos = clipPos(doc, Pos(newPos.line - 1)); + else newPos = null; + } else if (newPos.ch > line.text.length) { + if (newPos.line < doc.first + doc.size - 1) newPos = Pos(newPos.line + 1, 0); + else newPos = null; + } + if (!newPos) { + if (flipped) { + // Driven in a corner -- no valid cursor position found at all + // -- try again *with* clearing, if we didn't already + if (!mayClear) return skipAtomic(doc, pos, bias, true); + // Otherwise, turn off editing until further notice, and return the start of the doc + doc.cantEdit = true; + return Pos(doc.first, 0); + } + flipped = true; newPos = pos; dir = -dir; + } + } + curPos = newPos; + continue search; + } + } + } + return curPos; + } + } + + // SCROLLING + + function scrollCursorIntoView(cm) { + var coords = scrollPosIntoView(cm, cm.doc.sel.head, cm.options.cursorScrollMargin); + if (!cm.state.focused) return; + var display = cm.display, box = getRect(display.sizer), doScroll = null; + if (coords.top + box.top < 0) doScroll = true; + else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false; + if (doScroll != null && !phantom) { + var hidden = display.cursor.style.display == "none"; + if (hidden) { + display.cursor.style.display = ""; + display.cursor.style.left = coords.left + "px"; + display.cursor.style.top = (coords.top - display.viewOffset) + "px"; + } + display.cursor.scrollIntoView(doScroll); + if (hidden) display.cursor.style.display = "none"; + } + } + + function scrollPosIntoView(cm, pos, margin) { + if (margin == null) margin = 0; + for (;;) { + var changed = false, coords = cursorCoords(cm, pos); + var scrollPos = calculateScrollPos(cm, coords.left, coords.top - margin, coords.left, coords.bottom + margin); + var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft; + if (scrollPos.scrollTop != null) { + setScrollTop(cm, scrollPos.scrollTop); + if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true; + } + if (scrollPos.scrollLeft != null) { + setScrollLeft(cm, scrollPos.scrollLeft); + if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true; + } + if (!changed) return coords; + } + } + + function scrollIntoView(cm, x1, y1, x2, y2) { + var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2); + if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop); + if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft); + } + + function calculateScrollPos(cm, x1, y1, x2, y2) { + var display = cm.display, snapMargin = textHeight(cm.display); + if (y1 < 0) y1 = 0; + var screen = display.scroller.clientHeight - scrollerCutOff, screentop = display.scroller.scrollTop, result = {}; + var docBottom = cm.doc.height + paddingVert(display); + var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin; + if (y1 < screentop) { + result.scrollTop = atTop ? 0 : y1; + } else if (y2 > screentop + screen) { + var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen); + if (newTop != screentop) result.scrollTop = newTop; + } + + var screenw = display.scroller.clientWidth - scrollerCutOff, screenleft = display.scroller.scrollLeft; + x1 += display.gutters.offsetWidth; x2 += display.gutters.offsetWidth; + var gutterw = display.gutters.offsetWidth; + var atLeft = x1 < gutterw + 10; + if (x1 < screenleft + gutterw || atLeft) { + if (atLeft) x1 = 0; + result.scrollLeft = Math.max(0, x1 - 10 - gutterw); + } else if (x2 > screenw + screenleft - 3) { + result.scrollLeft = x2 + 10 - screenw; + } + return result; + } + + function updateScrollPos(cm, left, top) { + cm.curOp.updateScrollPos = {scrollLeft: left == null ? cm.doc.scrollLeft : left, + scrollTop: top == null ? cm.doc.scrollTop : top}; + } + + function addToScrollPos(cm, left, top) { + var pos = cm.curOp.updateScrollPos || (cm.curOp.updateScrollPos = {scrollLeft: cm.doc.scrollLeft, scrollTop: cm.doc.scrollTop}); + var scroll = cm.display.scroller; + pos.scrollTop = Math.max(0, Math.min(scroll.scrollHeight - scroll.clientHeight, pos.scrollTop + top)); + pos.scrollLeft = Math.max(0, Math.min(scroll.scrollWidth - scroll.clientWidth, pos.scrollLeft + left)); + } + + // API UTILITIES + + function indentLine(cm, n, how, aggressive) { + var doc = cm.doc; + if (how == null) how = "add"; + if (how == "smart") { + if (!cm.doc.mode.indent) how = "prev"; + else var state = getStateBefore(cm, n); + } + + var tabSize = cm.options.tabSize; + var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize); + var curSpaceString = line.text.match(/^\s*/)[0], indentation; + if (how == "smart") { + indentation = cm.doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text); + if (indentation == Pass) { + if (!aggressive) return; + how = "prev"; + } + } + if (how == "prev") { + if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize); + else indentation = 0; + } else if (how == "add") { + indentation = curSpace + cm.options.indentUnit; + } else if (how == "subtract") { + indentation = curSpace - cm.options.indentUnit; + } else if (typeof how == "number") { + indentation = curSpace + how; + } + indentation = Math.max(0, indentation); + + var indentString = "", pos = 0; + if (cm.options.indentWithTabs) + for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";} + if (pos < indentation) indentString += spaceStr(indentation - pos); + + if (indentString != curSpaceString) + replaceRange(cm.doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input"); + line.stateAfter = null; + } + + function changeLine(cm, handle, op) { + var no = handle, line = handle, doc = cm.doc; + if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle)); + else no = lineNo(handle); + if (no == null) return null; + if (op(line, no)) regChange(cm, no, no + 1); + else return null; + return line; + } + + function findPosH(doc, pos, dir, unit, visually) { + var line = pos.line, ch = pos.ch, origDir = dir; + var lineObj = getLine(doc, line); + var possible = true; + function findNextLine() { + var l = line + dir; + if (l < doc.first || l >= doc.first + doc.size) return (possible = false); + line = l; + return lineObj = getLine(doc, l); + } + function moveOnce(boundToLine) { + var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true); + if (next == null) { + if (!boundToLine && findNextLine()) { + if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj); + else ch = dir < 0 ? lineObj.text.length : 0; + } else return (possible = false); + } else ch = next; + return true; + } + + if (unit == "char") moveOnce(); + else if (unit == "column") moveOnce(true); + else if (unit == "word" || unit == "group") { + var sawType = null, group = unit == "group"; + for (var first = true;; first = false) { + if (dir < 0 && !moveOnce(!first)) break; + var cur = lineObj.text.charAt(ch) || "\n"; + var type = isWordChar(cur) ? "w" + : !group ? null + : /\s/.test(cur) ? null + : "p"; + if (sawType && sawType != type) { + if (dir < 0) {dir = 1; moveOnce();} + break; + } + if (type) sawType = type; + if (dir > 0 && !moveOnce(!first)) break; + } + } + var result = skipAtomic(doc, Pos(line, ch), origDir, true); + if (!possible) result.hitSide = true; + return result; + } + + function findPosV(cm, pos, dir, unit) { + var doc = cm.doc, x = pos.left, y; + if (unit == "page") { + var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight); + y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display)); + } else if (unit == "line") { + y = dir > 0 ? pos.bottom + 3 : pos.top - 3; + } + for (;;) { + var target = coordsChar(cm, x, y); + if (!target.outside) break; + if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; } + y += dir * 5; + } + return target; + } + + function findWordAt(line, pos) { + var start = pos.ch, end = pos.ch; + if (line) { + if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end; + var startChar = line.charAt(start); + var check = isWordChar(startChar) ? isWordChar + : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);} + : function(ch) {return !/\s/.test(ch) && !isWordChar(ch);}; + while (start > 0 && check(line.charAt(start - 1))) --start; + while (end < line.length && check(line.charAt(end))) ++end; + } + return {from: Pos(pos.line, start), to: Pos(pos.line, end)}; + } + + function selectLine(cm, line) { + extendSelection(cm.doc, Pos(line, 0), clipPos(cm.doc, Pos(line + 1, 0))); + } + + // PROTOTYPE + + // The publicly visible API. Note that operation(null, f) means + // 'wrap f in an operation, performed on its `this` parameter' + + CodeMirror.prototype = { + constructor: CodeMirror, + focus: function(){window.focus(); focusInput(this); onFocus(this); fastPoll(this);}, + + setOption: function(option, value) { + var options = this.options, old = options[option]; + if (options[option] == value && option != "mode") return; + options[option] = value; + if (optionHandlers.hasOwnProperty(option)) + operation(this, optionHandlers[option])(this, value, old); + }, + + getOption: function(option) {return this.options[option];}, + getDoc: function() {return this.doc;}, + + addKeyMap: function(map, bottom) { + this.state.keyMaps[bottom ? "push" : "unshift"](map); + }, + removeKeyMap: function(map) { + var maps = this.state.keyMaps; + for (var i = 0; i < maps.length; ++i) + if (maps[i] == map || (typeof maps[i] != "string" && maps[i].name == map)) { + maps.splice(i, 1); + return true; + } + }, + + addOverlay: operation(null, function(spec, options) { + var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec); + if (mode.startState) throw new Error("Overlays may not be stateful."); + this.state.overlays.push({mode: mode, modeSpec: spec, opaque: options && options.opaque}); + this.state.modeGen++; + regChange(this); + }), + removeOverlay: operation(null, function(spec) { + var overlays = this.state.overlays; + for (var i = 0; i < overlays.length; ++i) { + var cur = overlays[i].modeSpec; + if (cur == spec || typeof spec == "string" && cur.name == spec) { + overlays.splice(i, 1); + this.state.modeGen++; + regChange(this); + return; + } + } + }), + + indentLine: operation(null, function(n, dir, aggressive) { + if (typeof dir != "string" && typeof dir != "number") { + if (dir == null) dir = this.options.smartIndent ? "smart" : "prev"; + else dir = dir ? "add" : "subtract"; + } + if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive); + }), + indentSelection: operation(null, function(how) { + var sel = this.doc.sel; + if (posEq(sel.from, sel.to)) return indentLine(this, sel.from.line, how); + var e = sel.to.line - (sel.to.ch ? 0 : 1); + for (var i = sel.from.line; i <= e; ++i) indentLine(this, i, how); + }), + + // Fetch the parser token for a given character. Useful for hacks + // that want to inspect the mode state (say, for completion). + getTokenAt: function(pos, precise) { + var doc = this.doc; + pos = clipPos(doc, pos); + var state = getStateBefore(this, pos.line, precise), mode = this.doc.mode; + var line = getLine(doc, pos.line); + var stream = new StringStream(line.text, this.options.tabSize); + while (stream.pos < pos.ch && !stream.eol()) { + stream.start = stream.pos; + var style = mode.token(stream, state); + } + return {start: stream.start, + end: stream.pos, + string: stream.current(), + className: style || null, // Deprecated, use 'type' instead + type: style || null, + state: state}; + }, + + getTokenTypeAt: function(pos) { + pos = clipPos(this.doc, pos); + var styles = getLineStyles(this, getLine(this.doc, pos.line)); + var before = 0, after = (styles.length - 1) / 2, ch = pos.ch; + if (ch == 0) return styles[2]; + for (;;) { + var mid = (before + after) >> 1; + if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid; + else if (styles[mid * 2 + 1] < ch) before = mid + 1; + else return styles[mid * 2 + 2]; + } + }, + + getModeAt: function(pos) { + var mode = this.doc.mode; + if (!mode.innerMode) return mode; + return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode; + }, + + getHelper: function(pos, type) { + if (!helpers.hasOwnProperty(type)) return; + var help = helpers[type], mode = this.getModeAt(pos); + return mode[type] && help[mode[type]] || + mode.helperType && help[mode.helperType] || + help[mode.name]; + }, + + getStateAfter: function(line, precise) { + var doc = this.doc; + line = clipLine(doc, line == null ? doc.first + doc.size - 1: line); + return getStateBefore(this, line + 1, precise); + }, + + cursorCoords: function(start, mode) { + var pos, sel = this.doc.sel; + if (start == null) pos = sel.head; + else if (typeof start == "object") pos = clipPos(this.doc, start); + else pos = start ? sel.from : sel.to; + return cursorCoords(this, pos, mode || "page"); + }, + + charCoords: function(pos, mode) { + return charCoords(this, clipPos(this.doc, pos), mode || "page"); + }, + + coordsChar: function(coords, mode) { + coords = fromCoordSystem(this, coords, mode || "page"); + return coordsChar(this, coords.left, coords.top); + }, + + lineAtHeight: function(height, mode) { + height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top; + return lineAtHeight(this.doc, height + this.display.viewOffset); + }, + heightAtLine: function(line, mode) { + var end = false, last = this.doc.first + this.doc.size - 1; + if (line < this.doc.first) line = this.doc.first; + else if (line > last) { line = last; end = true; } + var lineObj = getLine(this.doc, line); + return intoCoordSystem(this, getLine(this.doc, line), {top: 0, left: 0}, mode || "page").top + + (end ? lineObj.height : 0); + }, + + defaultTextHeight: function() { return textHeight(this.display); }, + defaultCharWidth: function() { return charWidth(this.display); }, + + setGutterMarker: operation(null, function(line, gutterID, value) { + return changeLine(this, line, function(line) { + var markers = line.gutterMarkers || (line.gutterMarkers = {}); + markers[gutterID] = value; + if (!value && isEmpty(markers)) line.gutterMarkers = null; + return true; + }); + }), + + clearGutter: operation(null, function(gutterID) { + var cm = this, doc = cm.doc, i = doc.first; + doc.iter(function(line) { + if (line.gutterMarkers && line.gutterMarkers[gutterID]) { + line.gutterMarkers[gutterID] = null; + regChange(cm, i, i + 1); + if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null; + } + ++i; + }); + }), + + addLineClass: operation(null, function(handle, where, cls) { + return changeLine(this, handle, function(line) { + var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : "wrapClass"; + if (!line[prop]) line[prop] = cls; + else if (new RegExp("(?:^|\\s)" + cls + "(?:$|\\s)").test(line[prop])) return false; + else line[prop] += " " + cls; + return true; + }); + }), + + removeLineClass: operation(null, function(handle, where, cls) { + return changeLine(this, handle, function(line) { + var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : "wrapClass"; + var cur = line[prop]; + if (!cur) return false; + else if (cls == null) line[prop] = null; + else { + var found = cur.match(new RegExp("(?:^|\\s+)" + cls + "(?:$|\\s+)")); + if (!found) return false; + var end = found.index + found[0].length; + line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null; + } + return true; + }); + }), + + addLineWidget: operation(null, function(handle, node, options) { + return addLineWidget(this, handle, node, options); + }), + + removeLineWidget: function(widget) { widget.clear(); }, + + lineInfo: function(line) { + if (typeof line == "number") { + if (!isLine(this.doc, line)) return null; + var n = line; + line = getLine(this.doc, line); + if (!line) return null; + } else { + var n = lineNo(line); + if (n == null) return null; + } + return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers, + textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass, + widgets: line.widgets}; + }, + + getViewport: function() { return {from: this.display.showingFrom, to: this.display.showingTo};}, + + addWidget: function(pos, node, scroll, vert, horiz) { + var display = this.display; + pos = cursorCoords(this, clipPos(this.doc, pos)); + var top = pos.bottom, left = pos.left; + node.style.position = "absolute"; + display.sizer.appendChild(node); + if (vert == "over") { + top = pos.top; + } else if (vert == "above" || vert == "near") { + var vspace = Math.max(display.wrapper.clientHeight, this.doc.height), + hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth); + // Default to positioning above (if specified and possible); otherwise default to positioning below + if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight) + top = pos.top - node.offsetHeight; + else if (pos.bottom + node.offsetHeight <= vspace) + top = pos.bottom; + if (left + node.offsetWidth > hspace) + left = hspace - node.offsetWidth; + } + node.style.top = top + "px"; + node.style.left = node.style.right = ""; + if (horiz == "right") { + left = display.sizer.clientWidth - node.offsetWidth; + node.style.right = "0px"; + } else { + if (horiz == "left") left = 0; + else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2; + node.style.left = left + "px"; + } + if (scroll) + scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight); + }, + + triggerOnKeyDown: operation(null, onKeyDown), + + execCommand: function(cmd) {return commands[cmd](this);}, + + findPosH: function(from, amount, unit, visually) { + var dir = 1; + if (amount < 0) { dir = -1; amount = -amount; } + for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) { + cur = findPosH(this.doc, cur, dir, unit, visually); + if (cur.hitSide) break; + } + return cur; + }, + + moveH: operation(null, function(dir, unit) { + var sel = this.doc.sel, pos; + if (sel.shift || sel.extend || posEq(sel.from, sel.to)) + pos = findPosH(this.doc, sel.head, dir, unit, this.options.rtlMoveVisually); + else + pos = dir < 0 ? sel.from : sel.to; + extendSelection(this.doc, pos, pos, dir); + }), + + deleteH: operation(null, function(dir, unit) { + var sel = this.doc.sel; + if (!posEq(sel.from, sel.to)) replaceRange(this.doc, "", sel.from, sel.to, "+delete"); + else replaceRange(this.doc, "", sel.from, findPosH(this.doc, sel.head, dir, unit, false), "+delete"); + this.curOp.userSelChange = true; + }), + + findPosV: function(from, amount, unit, goalColumn) { + var dir = 1, x = goalColumn; + if (amount < 0) { dir = -1; amount = -amount; } + for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) { + var coords = cursorCoords(this, cur, "div"); + if (x == null) x = coords.left; + else coords.left = x; + cur = findPosV(this, coords, dir, unit); + if (cur.hitSide) break; + } + return cur; + }, + + moveV: operation(null, function(dir, unit) { + var sel = this.doc.sel; + var pos = cursorCoords(this, sel.head, "div"); + if (sel.goalColumn != null) pos.left = sel.goalColumn; + var target = findPosV(this, pos, dir, unit); + + if (unit == "page") addToScrollPos(this, 0, charCoords(this, target, "div").top - pos.top); + extendSelection(this.doc, target, target, dir); + sel.goalColumn = pos.left; + }), + + toggleOverwrite: function(value) { + if (value != null && value == this.state.overwrite) return; + if (this.state.overwrite = !this.state.overwrite) + this.display.cursor.className += " CodeMirror-overwrite"; + else + this.display.cursor.className = this.display.cursor.className.replace(" CodeMirror-overwrite", ""); + }, + hasFocus: function() { return this.state.focused; }, + + scrollTo: operation(null, function(x, y) { + updateScrollPos(this, x, y); + }), + getScrollInfo: function() { + var scroller = this.display.scroller, co = scrollerCutOff; + return {left: scroller.scrollLeft, top: scroller.scrollTop, + height: scroller.scrollHeight - co, width: scroller.scrollWidth - co, + clientHeight: scroller.clientHeight - co, clientWidth: scroller.clientWidth - co}; + }, + + scrollIntoView: operation(null, function(pos, margin) { + if (typeof pos == "number") pos = Pos(pos, 0); + if (!margin) margin = 0; + var coords = pos; + + if (!pos || pos.line != null) { + this.curOp.scrollToPos = pos ? clipPos(this.doc, pos) : this.doc.sel.head; + this.curOp.scrollToPosMargin = margin; + coords = cursorCoords(this, this.curOp.scrollToPos); + } + var sPos = calculateScrollPos(this, coords.left, coords.top - margin, coords.right, coords.bottom + margin); + updateScrollPos(this, sPos.scrollLeft, sPos.scrollTop); + }), + + setSize: operation(null, function(width, height) { + function interpret(val) { + return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; + } + if (width != null) this.display.wrapper.style.width = interpret(width); + if (height != null) this.display.wrapper.style.height = interpret(height); + if (this.options.lineWrapping) + this.display.measureLineCache.length = this.display.measureLineCachePos = 0; + this.curOp.forceUpdate = true; + }), + + operation: function(f){return runInOp(this, f);}, + + refresh: operation(null, function() { + clearCaches(this); + updateScrollPos(this, this.doc.scrollLeft, this.doc.scrollTop); + regChange(this); + }), + + swapDoc: operation(null, function(doc) { + var old = this.doc; + old.cm = null; + attachDoc(this, doc); + clearCaches(this); + resetInput(this, true); + updateScrollPos(this, doc.scrollLeft, doc.scrollTop); + return old; + }), + + getInputField: function(){return this.display.input;}, + getWrapperElement: function(){return this.display.wrapper;}, + getScrollerElement: function(){return this.display.scroller;}, + getGutterElement: function(){return this.display.gutters;} + }; + eventMixin(CodeMirror); + + // OPTION DEFAULTS + + var optionHandlers = CodeMirror.optionHandlers = {}; + + // The default configuration options. + var defaults = CodeMirror.defaults = {}; + + function option(name, deflt, handle, notOnInit) { + CodeMirror.defaults[name] = deflt; + if (handle) optionHandlers[name] = + notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old);} : handle; + } + + var Init = CodeMirror.Init = {toString: function(){return "CodeMirror.Init";}}; + + // These two are, on init, called from the constructor because they + // have to be initialized before the editor can start at all. + option("value", "", function(cm, val) { + cm.setValue(val); + }, true); + option("mode", null, function(cm, val) { + cm.doc.modeOption = val; + loadMode(cm); + }, true); + + option("indentUnit", 2, loadMode, true); + option("indentWithTabs", false); + option("smartIndent", true); + option("tabSize", 4, function(cm) { + loadMode(cm); + clearCaches(cm); + regChange(cm); + }, true); + option("electricChars", true); + option("rtlMoveVisually", !windows); + + option("theme", "default", function(cm) { + themeChanged(cm); + guttersChanged(cm); + }, true); + option("keyMap", "default", keyMapChanged); + option("extraKeys", null); + + option("onKeyEvent", null); + option("onDragEvent", null); + + option("lineWrapping", false, wrappingChanged, true); + option("gutters", [], function(cm) { + setGuttersForLineNumbers(cm.options); + guttersChanged(cm); + }, true); + option("fixedGutter", true, function(cm, val) { + cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0"; + cm.refresh(); + }, true); + option("coverGutterNextToScrollbar", false, updateScrollbars, true); + option("lineNumbers", false, function(cm) { + setGuttersForLineNumbers(cm.options); + guttersChanged(cm); + }, true); + option("firstLineNumber", 1, guttersChanged, true); + option("lineNumberFormatter", function(integer) {return integer;}, guttersChanged, true); + option("showCursorWhenSelecting", false, updateSelection, true); + + option("readOnly", false, function(cm, val) { + if (val == "nocursor") {onBlur(cm); cm.display.input.blur();} + else if (!val) resetInput(cm, true); + }); + option("dragDrop", true); + + option("cursorBlinkRate", 530); + option("cursorScrollMargin", 0); + option("cursorHeight", 1); + option("workTime", 100); + option("workDelay", 100); + option("flattenSpans", true); + option("pollInterval", 100); + option("undoDepth", 40, function(cm, val){cm.doc.history.undoDepth = val;}); + option("historyEventDelay", 500); + option("viewportMargin", 10, function(cm){cm.refresh();}, true); + option("maxHighlightLength", 10000, function(cm){loadMode(cm); cm.refresh();}, true); + option("moveInputWithCursor", true, function(cm, val) { + if (!val) cm.display.inputDiv.style.top = cm.display.inputDiv.style.left = 0; + }); + + option("tabindex", null, function(cm, val) { + cm.display.input.tabIndex = val || ""; + }); + option("autofocus", null); + + // MODE DEFINITION AND QUERYING + + // Known modes, by name and by MIME + var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {}; + + CodeMirror.defineMode = function(name, mode) { + if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name; + if (arguments.length > 2) { + mode.dependencies = []; + for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(arguments[i]); + } + modes[name] = mode; + }; + + CodeMirror.defineMIME = function(mime, spec) { + mimeModes[mime] = spec; + }; + + CodeMirror.resolveMode = function(spec) { + if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { + spec = mimeModes[spec]; + } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { + var found = mimeModes[spec.name]; + spec = createObj(found, spec); + spec.name = found.name; + } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) { + return CodeMirror.resolveMode("application/xml"); + } + if (typeof spec == "string") return {name: spec}; + else return spec || {name: "null"}; + }; + + CodeMirror.getMode = function(options, spec) { + var spec = CodeMirror.resolveMode(spec); + var mfactory = modes[spec.name]; + if (!mfactory) return CodeMirror.getMode(options, "text/plain"); + var modeObj = mfactory(options, spec); + if (modeExtensions.hasOwnProperty(spec.name)) { + var exts = modeExtensions[spec.name]; + for (var prop in exts) { + if (!exts.hasOwnProperty(prop)) continue; + if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop]; + modeObj[prop] = exts[prop]; + } + } + modeObj.name = spec.name; + + return modeObj; + }; + + CodeMirror.defineMode("null", function() { + return {token: function(stream) {stream.skipToEnd();}}; + }); + CodeMirror.defineMIME("text/plain", "null"); + + var modeExtensions = CodeMirror.modeExtensions = {}; + CodeMirror.extendMode = function(mode, properties) { + var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}); + copyObj(properties, exts); + }; + + // EXTENSIONS + + CodeMirror.defineExtension = function(name, func) { + CodeMirror.prototype[name] = func; + }; + CodeMirror.defineDocExtension = function(name, func) { + Doc.prototype[name] = func; + }; + CodeMirror.defineOption = option; + + var initHooks = []; + CodeMirror.defineInitHook = function(f) {initHooks.push(f);}; + + var helpers = CodeMirror.helpers = {}; + CodeMirror.registerHelper = function(type, name, value) { + if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {}; + helpers[type][name] = value; + }; + + // UTILITIES + + CodeMirror.isWordChar = isWordChar; + + // MODE STATE HANDLING + + // Utility functions for working with state. Exported because modes + // sometimes need to do this. + function copyState(mode, state) { + if (state === true) return state; + if (mode.copyState) return mode.copyState(state); + var nstate = {}; + for (var n in state) { + var val = state[n]; + if (val instanceof Array) val = val.concat([]); + nstate[n] = val; + } + return nstate; + } + CodeMirror.copyState = copyState; + + function startState(mode, a1, a2) { + return mode.startState ? mode.startState(a1, a2) : true; + } + CodeMirror.startState = startState; + + CodeMirror.innerMode = function(mode, state) { + while (mode.innerMode) { + var info = mode.innerMode(state); + if (!info || info.mode == mode) break; + state = info.state; + mode = info.mode; + } + return info || {mode: mode, state: state}; + }; + + // STANDARD COMMANDS + + var commands = CodeMirror.commands = { + selectAll: function(cm) {cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()));}, + killLine: function(cm) { + var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to); + if (!sel && cm.getLine(from.line).length == from.ch) + cm.replaceRange("", from, Pos(from.line + 1, 0), "+delete"); + else cm.replaceRange("", from, sel ? to : Pos(from.line), "+delete"); + }, + deleteLine: function(cm) { + var l = cm.getCursor().line; + cm.replaceRange("", Pos(l, 0), Pos(l), "+delete"); + }, + delLineLeft: function(cm) { + var cur = cm.getCursor(); + cm.replaceRange("", Pos(cur.line, 0), cur, "+delete"); + }, + undo: function(cm) {cm.undo();}, + redo: function(cm) {cm.redo();}, + goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));}, + goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));}, + goLineStart: function(cm) { + cm.extendSelection(lineStart(cm, cm.getCursor().line)); + }, + goLineStartSmart: function(cm) { + var cur = cm.getCursor(), start = lineStart(cm, cur.line); + var line = cm.getLineHandle(start.line); + var order = getOrder(line); + if (!order || order[0].level == 0) { + var firstNonWS = Math.max(0, line.text.search(/\S/)); + var inWS = cur.line == start.line && cur.ch <= firstNonWS && cur.ch; + cm.extendSelection(Pos(start.line, inWS ? 0 : firstNonWS)); + } else cm.extendSelection(start); + }, + goLineEnd: function(cm) { + cm.extendSelection(lineEnd(cm, cm.getCursor().line)); + }, + goLineRight: function(cm) { + var top = cm.charCoords(cm.getCursor(), "div").top + 5; + cm.extendSelection(cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div")); + }, + goLineLeft: function(cm) { + var top = cm.charCoords(cm.getCursor(), "div").top + 5; + cm.extendSelection(cm.coordsChar({left: 0, top: top}, "div")); + }, + goLineUp: function(cm) {cm.moveV(-1, "line");}, + goLineDown: function(cm) {cm.moveV(1, "line");}, + goPageUp: function(cm) {cm.moveV(-1, "page");}, + goPageDown: function(cm) {cm.moveV(1, "page");}, + goCharLeft: function(cm) {cm.moveH(-1, "char");}, + goCharRight: function(cm) {cm.moveH(1, "char");}, + goColumnLeft: function(cm) {cm.moveH(-1, "column");}, + goColumnRight: function(cm) {cm.moveH(1, "column");}, + goWordLeft: function(cm) {cm.moveH(-1, "word");}, + goGroupRight: function(cm) {cm.moveH(1, "group");}, + goGroupLeft: function(cm) {cm.moveH(-1, "group");}, + goWordRight: function(cm) {cm.moveH(1, "word");}, + delCharBefore: function(cm) {cm.deleteH(-1, "char");}, + delCharAfter: function(cm) {cm.deleteH(1, "char");}, + delWordBefore: function(cm) {cm.deleteH(-1, "word");}, + delWordAfter: function(cm) {cm.deleteH(1, "word");}, + delGroupBefore: function(cm) {cm.deleteH(-1, "group");}, + delGroupAfter: function(cm) {cm.deleteH(1, "group");}, + indentAuto: function(cm) {cm.indentSelection("smart");}, + indentMore: function(cm) {cm.indentSelection("add");}, + indentLess: function(cm) {cm.indentSelection("subtract");}, + insertTab: function(cm) {cm.replaceSelection("\t", "end", "+input");}, + defaultTab: function(cm) { + if (cm.somethingSelected()) cm.indentSelection("add"); + else cm.replaceSelection("\t", "end", "+input"); + }, + transposeChars: function(cm) { + var cur = cm.getCursor(), line = cm.getLine(cur.line); + if (cur.ch > 0 && cur.ch < line.length - 1) + cm.replaceRange(line.charAt(cur.ch) + line.charAt(cur.ch - 1), + Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1)); + }, + newlineAndIndent: function(cm) { + operation(cm, function() { + cm.replaceSelection("\n", "end", "+input"); + cm.indentLine(cm.getCursor().line, null, true); + })(); + }, + toggleOverwrite: function(cm) {cm.toggleOverwrite();} + }; + + // STANDARD KEYMAPS + + var keyMap = CodeMirror.keyMap = {}; + keyMap.basic = { + "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown", + "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown", + "Delete": "delCharAfter", "Backspace": "delCharBefore", "Tab": "defaultTab", "Shift-Tab": "indentAuto", + "Enter": "newlineAndIndent", "Insert": "toggleOverwrite" + }; + // Note that the save and find-related commands aren't defined by + // default. Unknown commands are simply ignored. + keyMap.pcDefault = { + "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo", + "Ctrl-Home": "goDocStart", "Alt-Up": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Down": "goDocEnd", + "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd", + "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find", + "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll", + "Ctrl-[": "indentLess", "Ctrl-]": "indentMore", + fallthrough: "basic" + }; + keyMap.macDefault = { + "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo", + "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft", + "Alt-Right": "goGroupRight", "Cmd-Left": "goLineStart", "Cmd-Right": "goLineEnd", "Alt-Backspace": "delGroupBefore", + "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find", + "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll", + "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delLineLeft", + fallthrough: ["basic", "emacsy"] + }; + keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault; + keyMap.emacsy = { + "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown", + "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd", + "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore", + "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars" + }; + + // KEYMAP DISPATCH + + function getKeyMap(val) { + if (typeof val == "string") return keyMap[val]; + else return val; + } + + function lookupKey(name, maps, handle) { + function lookup(map) { + map = getKeyMap(map); + var found = map[name]; + if (found === false) return "stop"; + if (found != null && handle(found)) return true; + if (map.nofallthrough) return "stop"; + + var fallthrough = map.fallthrough; + if (fallthrough == null) return false; + if (Object.prototype.toString.call(fallthrough) != "[object Array]") + return lookup(fallthrough); + for (var i = 0, e = fallthrough.length; i < e; ++i) { + var done = lookup(fallthrough[i]); + if (done) return done; + } + return false; + } + + for (var i = 0; i < maps.length; ++i) { + var done = lookup(maps[i]); + if (done) return done != "stop"; + } + } + function isModifierKey(event) { + var name = keyNames[event.keyCode]; + return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"; + } + function keyName(event, noShift) { + if (opera && event.keyCode == 34 && event["char"]) return false; + var name = keyNames[event.keyCode]; + if (name == null || event.altGraphKey) return false; + if (event.altKey) name = "Alt-" + name; + if (flipCtrlCmd ? event.metaKey : event.ctrlKey) name = "Ctrl-" + name; + if (flipCtrlCmd ? event.ctrlKey : event.metaKey) name = "Cmd-" + name; + if (!noShift && event.shiftKey) name = "Shift-" + name; + return name; + } + CodeMirror.lookupKey = lookupKey; + CodeMirror.isModifierKey = isModifierKey; + CodeMirror.keyName = keyName; + + // FROMTEXTAREA + + CodeMirror.fromTextArea = function(textarea, options) { + if (!options) options = {}; + options.value = textarea.value; + if (!options.tabindex && textarea.tabindex) + options.tabindex = textarea.tabindex; + if (!options.placeholder && textarea.placeholder) + options.placeholder = textarea.placeholder; + // Set autofocus to true if this textarea is focused, or if it has + // autofocus and no other element is focused. + if (options.autofocus == null) { + var hasFocus = document.body; + // doc.activeElement occasionally throws on IE + try { hasFocus = document.activeElement; } catch(e) {} + options.autofocus = hasFocus == textarea || + textarea.getAttribute("autofocus") != null && hasFocus == document.body; + } + + function save() {textarea.value = cm.getValue();} + if (textarea.form) { + on(textarea.form, "submit", save); + // Deplorable hack to make the submit method do the right thing. + if (!options.leaveSubmitMethodAlone) { + var form = textarea.form, realSubmit = form.submit; + try { + var wrappedSubmit = form.submit = function() { + save(); + form.submit = realSubmit; + form.submit(); + form.submit = wrappedSubmit; + }; + } catch(e) {} + } + } + + textarea.style.display = "none"; + var cm = CodeMirror(function(node) { + textarea.parentNode.insertBefore(node, textarea.nextSibling); + }, options); + cm.save = save; + cm.getTextArea = function() { return textarea; }; + cm.toTextArea = function() { + save(); + textarea.parentNode.removeChild(cm.getWrapperElement()); + textarea.style.display = ""; + if (textarea.form) { + off(textarea.form, "submit", save); + if (typeof textarea.form.submit == "function") + textarea.form.submit = realSubmit; + } + }; + return cm; + }; + + // STRING STREAM + + // Fed to the mode parsers, provides helper functions to make + // parsers more succinct. + + // The character stream used by a mode's parser. + function StringStream(string, tabSize) { + this.pos = this.start = 0; + this.string = string; + this.tabSize = tabSize || 8; + this.lastColumnPos = this.lastColumnValue = 0; + } + + StringStream.prototype = { + eol: function() {return this.pos >= this.string.length;}, + sol: function() {return this.pos == 0;}, + peek: function() {return this.string.charAt(this.pos) || undefined;}, + next: function() { + if (this.pos < this.string.length) + return this.string.charAt(this.pos++); + }, + eat: function(match) { + var ch = this.string.charAt(this.pos); + if (typeof match == "string") var ok = ch == match; + else var ok = ch && (match.test ? match.test(ch) : match(ch)); + if (ok) {++this.pos; return ch;} + }, + eatWhile: function(match) { + var start = this.pos; + while (this.eat(match)){} + return this.pos > start; + }, + eatSpace: function() { + var start = this.pos; + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; + return this.pos > start; + }, + skipToEnd: function() {this.pos = this.string.length;}, + skipTo: function(ch) { + var found = this.string.indexOf(ch, this.pos); + if (found > -1) {this.pos = found; return true;} + }, + backUp: function(n) {this.pos -= n;}, + column: function() { + if (this.lastColumnPos < this.start) { + this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue); + this.lastColumnPos = this.start; + } + return this.lastColumnValue; + }, + indentation: function() {return countColumn(this.string, null, this.tabSize);}, + match: function(pattern, consume, caseInsensitive) { + if (typeof pattern == "string") { + var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;}; + var substr = this.string.substr(this.pos, pattern.length); + if (cased(substr) == cased(pattern)) { + if (consume !== false) this.pos += pattern.length; + return true; + } + } else { + var match = this.string.slice(this.pos).match(pattern); + if (match && match.index > 0) return null; + if (match && consume !== false) this.pos += match[0].length; + return match; + } + }, + current: function(){return this.string.slice(this.start, this.pos);} + }; + CodeMirror.StringStream = StringStream; + + // TEXTMARKERS + + function TextMarker(doc, type) { + this.lines = []; + this.type = type; + this.doc = doc; + } + CodeMirror.TextMarker = TextMarker; + eventMixin(TextMarker); + + TextMarker.prototype.clear = function() { + if (this.explicitlyCleared) return; + var cm = this.doc.cm, withOp = cm && !cm.curOp; + if (withOp) startOperation(cm); + if (hasHandler(this, "clear")) { + var found = this.find(); + if (found) signalLater(this, "clear", found.from, found.to); + } + var min = null, max = null; + for (var i = 0; i < this.lines.length; ++i) { + var line = this.lines[i]; + var span = getMarkedSpanFor(line.markedSpans, this); + if (span.to != null) max = lineNo(line); + line.markedSpans = removeMarkedSpan(line.markedSpans, span); + if (span.from != null) + min = lineNo(line); + else if (this.collapsed && !lineIsHidden(this.doc, line) && cm) + updateLineHeight(line, textHeight(cm.display)); + } + if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) { + var visual = visualLine(cm.doc, this.lines[i]), len = lineLength(cm.doc, visual); + if (len > cm.display.maxLineLength) { + cm.display.maxLine = visual; + cm.display.maxLineLength = len; + cm.display.maxLineChanged = true; + } + } + + if (min != null && cm) regChange(cm, min, max + 1); + this.lines.length = 0; + this.explicitlyCleared = true; + if (this.atomic && this.doc.cantEdit) { + this.doc.cantEdit = false; + if (cm) reCheckSelection(cm); + } + if (withOp) endOperation(cm); + }; + + TextMarker.prototype.find = function() { + var from, to; + for (var i = 0; i < this.lines.length; ++i) { + var line = this.lines[i]; + var span = getMarkedSpanFor(line.markedSpans, this); + if (span.from != null || span.to != null) { + var found = lineNo(line); + if (span.from != null) from = Pos(found, span.from); + if (span.to != null) to = Pos(found, span.to); + } + } + if (this.type == "bookmark") return from; + return from && {from: from, to: to}; + }; + + TextMarker.prototype.changed = function() { + var pos = this.find(), cm = this.doc.cm; + if (!pos || !cm) return; + var line = getLine(this.doc, pos.from.line); + clearCachedMeasurement(cm, line); + if (pos.from.line >= cm.display.showingFrom && pos.from.line < cm.display.showingTo) { + for (var node = cm.display.lineDiv.firstChild; node; node = node.nextSibling) if (node.lineObj == line) { + if (node.offsetHeight != line.height) updateLineHeight(line, node.offsetHeight); + break; + } + runInOp(cm, function() { + cm.curOp.selectionChanged = cm.curOp.forceUpdate = cm.curOp.updateMaxLine = true; + }); + } + }; + + TextMarker.prototype.attachLine = function(line) { + if (!this.lines.length && this.doc.cm) { + var op = this.doc.cm.curOp; + if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1) + (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); + } + this.lines.push(line); + }; + TextMarker.prototype.detachLine = function(line) { + this.lines.splice(indexOf(this.lines, line), 1); + if (!this.lines.length && this.doc.cm) { + var op = this.doc.cm.curOp; + (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this); + } + }; + + function markText(doc, from, to, options, type) { + if (options && options.shared) return markTextShared(doc, from, to, options, type); + if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type); + + var marker = new TextMarker(doc, type); + if (type == "range" && !posLess(from, to)) return marker; + if (options) copyObj(options, marker); + if (marker.replacedWith) { + marker.collapsed = true; + marker.replacedWith = elt("span", [marker.replacedWith], "CodeMirror-widget"); + if (!options.handleMouseEvents) marker.replacedWith.ignoreEvents = true; + } + if (marker.collapsed) sawCollapsedSpans = true; + + if (marker.addToHistory) + addToHistory(doc, {from: from, to: to, origin: "markText"}, + {head: doc.sel.head, anchor: doc.sel.anchor}, NaN); + + var curLine = from.line, size = 0, collapsedAtStart, collapsedAtEnd, cm = doc.cm, updateMaxLine; + doc.iter(curLine, to.line + 1, function(line) { + if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(doc, line) == cm.display.maxLine) + updateMaxLine = true; + var span = {from: null, to: null, marker: marker}; + size += line.text.length; + if (curLine == from.line) {span.from = from.ch; size -= from.ch;} + if (curLine == to.line) {span.to = to.ch; size -= line.text.length - to.ch;} + if (marker.collapsed) { + if (curLine == to.line) collapsedAtEnd = collapsedSpanAt(line, to.ch); + if (curLine == from.line) collapsedAtStart = collapsedSpanAt(line, from.ch); + else updateLineHeight(line, 0); + } + addMarkedSpan(line, span); + ++curLine; + }); + if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) { + if (lineIsHidden(doc, line)) updateLineHeight(line, 0); + }); + + if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function() { marker.clear(); }); + + if (marker.readOnly) { + sawReadOnlySpans = true; + if (doc.history.done.length || doc.history.undone.length) + doc.clearHistory(); + } + if (marker.collapsed) { + if (collapsedAtStart != collapsedAtEnd) + throw new Error("Inserting collapsed marker overlapping an existing one"); + marker.size = size; + marker.atomic = true; + } + if (cm) { + if (updateMaxLine) cm.curOp.updateMaxLine = true; + if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.collapsed) + regChange(cm, from.line, to.line + 1); + if (marker.atomic) reCheckSelection(cm); + } + return marker; + } + + // SHARED TEXTMARKERS + + function SharedTextMarker(markers, primary) { + this.markers = markers; + this.primary = primary; + for (var i = 0, me = this; i < markers.length; ++i) { + markers[i].parent = this; + on(markers[i], "clear", function(){me.clear();}); + } + } + CodeMirror.SharedTextMarker = SharedTextMarker; + eventMixin(SharedTextMarker); + + SharedTextMarker.prototype.clear = function() { + if (this.explicitlyCleared) return; + this.explicitlyCleared = true; + for (var i = 0; i < this.markers.length; ++i) + this.markers[i].clear(); + signalLater(this, "clear"); + }; + SharedTextMarker.prototype.find = function() { + return this.primary.find(); + }; + + function markTextShared(doc, from, to, options, type) { + options = copyObj(options); + options.shared = false; + var markers = [markText(doc, from, to, options, type)], primary = markers[0]; + var widget = options.replacedWith; + linkedDocs(doc, function(doc) { + if (widget) options.replacedWith = widget.cloneNode(true); + markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type)); + for (var i = 0; i < doc.linked.length; ++i) + if (doc.linked[i].isParent) return; + primary = lst(markers); + }); + return new SharedTextMarker(markers, primary); + } + + // TEXTMARKER SPANS + + function getMarkedSpanFor(spans, marker) { + if (spans) for (var i = 0; i < spans.length; ++i) { + var span = spans[i]; + if (span.marker == marker) return span; + } + } + function removeMarkedSpan(spans, span) { + for (var r, i = 0; i < spans.length; ++i) + if (spans[i] != span) (r || (r = [])).push(spans[i]); + return r; + } + function addMarkedSpan(line, span) { + line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span]; + span.marker.attachLine(line); + } + + function markedSpansBefore(old, startCh, isInsert) { + if (old) for (var i = 0, nw; i < old.length; ++i) { + var span = old[i], marker = span.marker; + var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh); + if (startsBefore || marker.type == "bookmark" && span.from == startCh && (!isInsert || !span.marker.insertLeft)) { + var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh); + (nw || (nw = [])).push({from: span.from, + to: endsAfter ? null : span.to, + marker: marker}); + } + } + return nw; + } + + function markedSpansAfter(old, endCh, isInsert) { + if (old) for (var i = 0, nw; i < old.length; ++i) { + var span = old[i], marker = span.marker; + var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh); + if (endsAfter || marker.type == "bookmark" && span.from == endCh && (!isInsert || span.marker.insertLeft)) { + var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh); + (nw || (nw = [])).push({from: startsBefore ? null : span.from - endCh, + to: span.to == null ? null : span.to - endCh, + marker: marker}); + } + } + return nw; + } + + function stretchSpansOverChange(doc, change) { + var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans; + var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans; + if (!oldFirst && !oldLast) return null; + + var startCh = change.from.ch, endCh = change.to.ch, isInsert = posEq(change.from, change.to); + // Get the spans that 'stick out' on both sides + var first = markedSpansBefore(oldFirst, startCh, isInsert); + var last = markedSpansAfter(oldLast, endCh, isInsert); + + // Next, merge those two ends + var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0); + if (first) { + // Fix up .to properties of first + for (var i = 0; i < first.length; ++i) { + var span = first[i]; + if (span.to == null) { + var found = getMarkedSpanFor(last, span.marker); + if (!found) span.to = startCh; + else if (sameLine) span.to = found.to == null ? null : found.to + offset; + } + } + } + if (last) { + // Fix up .from in last (or move them into first in case of sameLine) + for (var i = 0; i < last.length; ++i) { + var span = last[i]; + if (span.to != null) span.to += offset; + if (span.from == null) { + var found = getMarkedSpanFor(first, span.marker); + if (!found) { + span.from = offset; + if (sameLine) (first || (first = [])).push(span); + } + } else { + span.from += offset; + if (sameLine) (first || (first = [])).push(span); + } + } + } + if (sameLine && first) { + // Make sure we didn't create any zero-length spans + for (var i = 0; i < first.length; ++i) + if (first[i].from != null && first[i].from == first[i].to && first[i].marker.type != "bookmark") + first.splice(i--, 1); + if (!first.length) first = null; + } + + var newMarkers = [first]; + if (!sameLine) { + // Fill gap with whole-line-spans + var gap = change.text.length - 2, gapMarkers; + if (gap > 0 && first) + for (var i = 0; i < first.length; ++i) + if (first[i].to == null) + (gapMarkers || (gapMarkers = [])).push({from: null, to: null, marker: first[i].marker}); + for (var i = 0; i < gap; ++i) + newMarkers.push(gapMarkers); + newMarkers.push(last); + } + return newMarkers; + } + + function mergeOldSpans(doc, change) { + var old = getOldSpans(doc, change); + var stretched = stretchSpansOverChange(doc, change); + if (!old) return stretched; + if (!stretched) return old; + + for (var i = 0; i < old.length; ++i) { + var oldCur = old[i], stretchCur = stretched[i]; + if (oldCur && stretchCur) { + spans: for (var j = 0; j < stretchCur.length; ++j) { + var span = stretchCur[j]; + for (var k = 0; k < oldCur.length; ++k) + if (oldCur[k].marker == span.marker) continue spans; + oldCur.push(span); + } + } else if (stretchCur) { + old[i] = stretchCur; + } + } + return old; + } + + function removeReadOnlyRanges(doc, from, to) { + var markers = null; + doc.iter(from.line, to.line + 1, function(line) { + if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) { + var mark = line.markedSpans[i].marker; + if (mark.readOnly && (!markers || indexOf(markers, mark) == -1)) + (markers || (markers = [])).push(mark); + } + }); + if (!markers) return null; + var parts = [{from: from, to: to}]; + for (var i = 0; i < markers.length; ++i) { + var mk = markers[i], m = mk.find(); + for (var j = 0; j < parts.length; ++j) { + var p = parts[j]; + if (posLess(p.to, m.from) || posLess(m.to, p.from)) continue; + var newParts = [j, 1]; + if (posLess(p.from, m.from) || !mk.inclusiveLeft && posEq(p.from, m.from)) + newParts.push({from: p.from, to: m.from}); + if (posLess(m.to, p.to) || !mk.inclusiveRight && posEq(p.to, m.to)) + newParts.push({from: m.to, to: p.to}); + parts.splice.apply(parts, newParts); + j += newParts.length - 1; + } + } + return parts; + } + + function collapsedSpanAt(line, ch) { + var sps = sawCollapsedSpans && line.markedSpans, found; + if (sps) for (var sp, i = 0; i < sps.length; ++i) { + sp = sps[i]; + if (!sp.marker.collapsed) continue; + if ((sp.from == null || sp.from < ch) && + (sp.to == null || sp.to > ch) && + (!found || found.width < sp.marker.width)) + found = sp.marker; + } + return found; + } + function collapsedSpanAtStart(line) { return collapsedSpanAt(line, -1); } + function collapsedSpanAtEnd(line) { return collapsedSpanAt(line, line.text.length + 1); } + + function visualLine(doc, line) { + var merged; + while (merged = collapsedSpanAtStart(line)) + line = getLine(doc, merged.find().from.line); + return line; + } + + function lineIsHidden(doc, line) { + var sps = sawCollapsedSpans && line.markedSpans; + if (sps) for (var sp, i = 0; i < sps.length; ++i) { + sp = sps[i]; + if (!sp.marker.collapsed) continue; + if (sp.from == null) return true; + if (sp.marker.replacedWith) continue; + if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp)) + return true; + } + } + function lineIsHiddenInner(doc, line, span) { + if (span.to == null) { + var end = span.marker.find().to, endLine = getLine(doc, end.line); + return lineIsHiddenInner(doc, endLine, getMarkedSpanFor(endLine.markedSpans, span.marker)); + } + if (span.marker.inclusiveRight && span.to == line.text.length) + return true; + for (var sp, i = 0; i < line.markedSpans.length; ++i) { + sp = line.markedSpans[i]; + if (sp.marker.collapsed && !sp.marker.replacedWith && sp.from == span.to && + (sp.marker.inclusiveLeft || span.marker.inclusiveRight) && + lineIsHiddenInner(doc, line, sp)) return true; + } + } + + function detachMarkedSpans(line) { + var spans = line.markedSpans; + if (!spans) return; + for (var i = 0; i < spans.length; ++i) + spans[i].marker.detachLine(line); + line.markedSpans = null; + } + + function attachMarkedSpans(line, spans) { + if (!spans) return; + for (var i = 0; i < spans.length; ++i) + spans[i].marker.attachLine(line); + line.markedSpans = spans; + } + + // LINE WIDGETS + + var LineWidget = CodeMirror.LineWidget = function(cm, node, options) { + if (options) for (var opt in options) if (options.hasOwnProperty(opt)) + this[opt] = options[opt]; + this.cm = cm; + this.node = node; + }; + eventMixin(LineWidget); + function widgetOperation(f) { + return function() { + var withOp = !this.cm.curOp; + if (withOp) startOperation(this.cm); + try {var result = f.apply(this, arguments);} + finally {if (withOp) endOperation(this.cm);} + return result; + }; + } + LineWidget.prototype.clear = widgetOperation(function() { + var ws = this.line.widgets, no = lineNo(this.line); + if (no == null || !ws) return; + for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1); + if (!ws.length) this.line.widgets = null; + var aboveVisible = heightAtLine(this.cm, this.line) < this.cm.doc.scrollTop; + updateLineHeight(this.line, Math.max(0, this.line.height - widgetHeight(this))); + if (aboveVisible) addToScrollPos(this.cm, 0, -this.height); + regChange(this.cm, no, no + 1); + }); + LineWidget.prototype.changed = widgetOperation(function() { + var oldH = this.height; + this.height = null; + var diff = widgetHeight(this) - oldH; + if (!diff) return; + updateLineHeight(this.line, this.line.height + diff); + var no = lineNo(this.line); + regChange(this.cm, no, no + 1); + }); + + function widgetHeight(widget) { + if (widget.height != null) return widget.height; + if (!widget.node.parentNode || widget.node.parentNode.nodeType != 1) + removeChildrenAndAdd(widget.cm.display.measure, elt("div", [widget.node], null, "position: relative")); + return widget.height = widget.node.offsetHeight; + } + + function addLineWidget(cm, handle, node, options) { + var widget = new LineWidget(cm, node, options); + if (widget.noHScroll) cm.display.alignWidgets = true; + changeLine(cm, handle, function(line) { + var widgets = line.widgets || (line.widgets = []); + if (widget.insertAt == null) widgets.push(widget); + else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); + widget.line = line; + if (!lineIsHidden(cm.doc, line) || widget.showIfHidden) { + var aboveVisible = heightAtLine(cm, line) < cm.doc.scrollTop; + updateLineHeight(line, line.height + widgetHeight(widget)); + if (aboveVisible) addToScrollPos(cm, 0, widget.height); + } + return true; + }); + return widget; + } + + // LINE DATA STRUCTURE + + // Line objects. These hold state related to a line, including + // highlighting info (the styles array). + var Line = CodeMirror.Line = function(text, markedSpans, estimateHeight) { + this.text = text; + attachMarkedSpans(this, markedSpans); + this.height = estimateHeight ? estimateHeight(this) : 1; + }; + eventMixin(Line); + + function updateLine(line, text, markedSpans, estimateHeight) { + line.text = text; + if (line.stateAfter) line.stateAfter = null; + if (line.styles) line.styles = null; + if (line.order != null) line.order = null; + detachMarkedSpans(line); + attachMarkedSpans(line, markedSpans); + var estHeight = estimateHeight ? estimateHeight(line) : 1; + if (estHeight != line.height) updateLineHeight(line, estHeight); + } + + function cleanUpLine(line) { + line.parent = null; + detachMarkedSpans(line); + } + + // Run the given mode's parser over a line, update the styles + // array, which contains alternating fragments of text and CSS + // classes. + function runMode(cm, text, mode, state, f) { + var flattenSpans = mode.flattenSpans; + if (flattenSpans == null) flattenSpans = cm.options.flattenSpans; + var curStart = 0, curStyle = null; + var stream = new StringStream(text, cm.options.tabSize), style; + if (text == "" && mode.blankLine) mode.blankLine(state); + while (!stream.eol()) { + if (stream.pos > cm.options.maxHighlightLength) { + flattenSpans = false; + // Webkit seems to refuse to render text nodes longer than 57444 characters + stream.pos = Math.min(text.length, stream.start + 50000); + style = null; + } else { + style = mode.token(stream, state); + } + if (!flattenSpans || curStyle != style) { + if (curStart < stream.start) f(stream.start, curStyle); + curStart = stream.start; curStyle = style; + } + stream.start = stream.pos; + } + if (curStart < stream.pos) f(stream.pos, curStyle); + } + + function highlightLine(cm, line, state) { + // A styles array always starts with a number identifying the + // mode/overlays that it is based on (for easy invalidation). + var st = [cm.state.modeGen]; + // Compute the base array of styles + runMode(cm, line.text, cm.doc.mode, state, function(end, style) {st.push(end, style);}); + + // Run overlays, adjust style array. + for (var o = 0; o < cm.state.overlays.length; ++o) { + var overlay = cm.state.overlays[o], i = 1, at = 0; + runMode(cm, line.text, overlay.mode, true, function(end, style) { + var start = i; + // Ensure there's a token end at the current position, and that i points at it + while (at < end) { + var i_end = st[i]; + if (i_end > end) + st.splice(i, 1, end, st[i+1], i_end); + i += 2; + at = Math.min(end, i_end); + } + if (!style) return; + if (overlay.opaque) { + st.splice(start, i - start, end, style); + i = start + 2; + } else { + for (; start < i; start += 2) { + var cur = st[start+1]; + st[start+1] = cur ? cur + " " + style : style; + } + } + }); + } + + return st; + } + + function getLineStyles(cm, line) { + if (!line.styles || line.styles[0] != cm.state.modeGen) + line.styles = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line))); + return line.styles; + } + + // Lightweight form of highlight -- proceed over this line and + // update state, but don't save a style array. + function processLine(cm, line, state) { + var mode = cm.doc.mode; + var stream = new StringStream(line.text, cm.options.tabSize); + if (line.text == "" && mode.blankLine) mode.blankLine(state); + while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) { + mode.token(stream, state); + stream.start = stream.pos; + } + } + + var styleToClassCache = {}; + function styleToClass(style) { + if (!style) return null; + return styleToClassCache[style] || + (styleToClassCache[style] = "cm-" + style.replace(/ +/g, " cm-")); + } + + function lineContent(cm, realLine, measure, copyWidgets) { + var merged, line = realLine, empty = true; + while (merged = collapsedSpanAtStart(line)) + line = getLine(cm.doc, merged.find().from.line); + + var builder = {pre: elt("pre"), col: 0, pos: 0, + measure: null, measuredSomething: false, cm: cm, + copyWidgets: copyWidgets}; + if (line.textClass) builder.pre.className = line.textClass; + + do { + if (line.text) empty = false; + builder.measure = line == realLine && measure; + builder.pos = 0; + builder.addToken = builder.measure ? buildTokenMeasure : buildToken; + if ((ie || webkit) && cm.getOption("lineWrapping")) + builder.addToken = buildTokenSplitSpaces(builder.addToken); + var next = insertLineContent(line, builder, getLineStyles(cm, line)); + if (measure && line == realLine && !builder.measuredSomething) { + measure[0] = builder.pre.appendChild(zeroWidthElement(cm.display.measure)); + builder.measuredSomething = true; + } + if (next) line = getLine(cm.doc, next.to.line); + } while (next); + + if (measure && !builder.measuredSomething && !measure[0]) + measure[0] = builder.pre.appendChild(empty ? elt("span", "\u00a0") : zeroWidthElement(cm.display.measure)); + if (!builder.pre.firstChild && !lineIsHidden(cm.doc, realLine)) + builder.pre.appendChild(document.createTextNode("\u00a0")); + + var order; + // Work around problem with the reported dimensions of single-char + // direction spans on IE (issue #1129). See also the comment in + // cursorCoords. + if (measure && ie && (order = getOrder(line))) { + var l = order.length - 1; + if (order[l].from == order[l].to) --l; + var last = order[l], prev = order[l - 1]; + if (last.from + 1 == last.to && prev && last.level < prev.level) { + var span = measure[builder.pos - 1]; + if (span) span.parentNode.insertBefore(span.measureRight = zeroWidthElement(cm.display.measure), + span.nextSibling); + } + } + + signal(cm, "renderLine", cm, realLine, builder.pre); + return builder.pre; + } + + var tokenSpecialChars = /[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\uFEFF]/g; + function buildToken(builder, text, style, startStyle, endStyle, title) { + if (!text) return; + if (!tokenSpecialChars.test(text)) { + builder.col += text.length; + var content = document.createTextNode(text); + } else { + var content = document.createDocumentFragment(), pos = 0; + while (true) { + tokenSpecialChars.lastIndex = pos; + var m = tokenSpecialChars.exec(text); + var skipped = m ? m.index - pos : text.length - pos; + if (skipped) { + content.appendChild(document.createTextNode(text.slice(pos, pos + skipped))); + builder.col += skipped; + } + if (!m) break; + pos += skipped + 1; + if (m[0] == "\t") { + var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize; + content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab")); + builder.col += tabWidth; + } else { + var token = elt("span", "\u2022", "cm-invalidchar"); + token.title = "\\u" + m[0].charCodeAt(0).toString(16); + content.appendChild(token); + builder.col += 1; + } + } + } + if (style || startStyle || endStyle || builder.measure) { + var fullStyle = style || ""; + if (startStyle) fullStyle += startStyle; + if (endStyle) fullStyle += endStyle; + var token = elt("span", [content], fullStyle); + if (title) token.title = title; + return builder.pre.appendChild(token); + } + builder.pre.appendChild(content); + } + + function buildTokenMeasure(builder, text, style, startStyle, endStyle) { + var wrapping = builder.cm.options.lineWrapping; + for (var i = 0; i < text.length; ++i) { + var ch = text.charAt(i), start = i == 0; + if (ch >= "\ud800" && ch < "\udbff" && i < text.length - 1) { + ch = text.slice(i, i + 2); + ++i; + } else if (i && wrapping && spanAffectsWrapping(text, i)) { + builder.pre.appendChild(elt("wbr")); + } + var old = builder.measure[builder.pos]; + var span = builder.measure[builder.pos] = + buildToken(builder, ch, style, + start && startStyle, i == text.length - 1 && endStyle); + if (old) span.leftSide = old.leftSide || old; + // In IE single-space nodes wrap differently than spaces + // embedded in larger text nodes, except when set to + // white-space: normal (issue #1268). + if (ie && wrapping && ch == " " && i && !/\s/.test(text.charAt(i - 1)) && + i < text.length - 1 && !/\s/.test(text.charAt(i + 1))) + span.style.whiteSpace = "normal"; + builder.pos += ch.length; + } + if (text.length) builder.measuredSomething = true; + } + + function buildTokenSplitSpaces(inner) { + function split(old) { + var out = " "; + for (var i = 0; i < old.length - 2; ++i) out += i % 2 ? " " : "\u00a0"; + out += " "; + return out; + } + return function(builder, text, style, startStyle, endStyle, title) { + return inner(builder, text.replace(/ {3,}/, split), style, startStyle, endStyle, title); + }; + } + + function buildCollapsedSpan(builder, size, marker, ignoreWidget) { + var widget = !ignoreWidget && marker.replacedWith; + if (widget) { + if (builder.copyWidgets) widget = widget.cloneNode(true); + builder.pre.appendChild(widget); + if (builder.measure) { + if (size) { + builder.measure[builder.pos] = widget; + } else { + var elt = builder.measure[builder.pos] = zeroWidthElement(builder.cm.display.measure); + if (marker.type != "bookmark" || marker.insertLeft) + builder.pre.insertBefore(elt, widget); + else + builder.pre.appendChild(elt); + } + builder.measuredSomething = true; + } + } + builder.pos += size; + } + + // Outputs a number of spans to make up a line, taking highlighting + // and marked text into account. + function insertLineContent(line, builder, styles) { + var spans = line.markedSpans, allText = line.text, at = 0; + if (!spans) { + for (var i = 1; i < styles.length; i+=2) + builder.addToken(builder, allText.slice(at, at = styles[i]), styleToClass(styles[i+1])); + return; + } + + var len = allText.length, pos = 0, i = 1, text = "", style; + var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed; + for (;;) { + if (nextChange == pos) { // Update current marker set + spanStyle = spanEndStyle = spanStartStyle = title = ""; + collapsed = null; nextChange = Infinity; + var foundBookmark = null; + for (var j = 0; j < spans.length; ++j) { + var sp = spans[j], m = sp.marker; + if (sp.from <= pos && (sp.to == null || sp.to > pos)) { + if (sp.to != null && nextChange > sp.to) { nextChange = sp.to; spanEndStyle = ""; } + if (m.className) spanStyle += " " + m.className; + if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle; + if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle; + if (m.title && !title) title = m.title; + if (m.collapsed && (!collapsed || collapsed.marker.size < m.size)) + collapsed = sp; + } else if (sp.from > pos && nextChange > sp.from) { + nextChange = sp.from; + } + if (m.type == "bookmark" && sp.from == pos && m.replacedWith) foundBookmark = m; + } + if (collapsed && (collapsed.from || 0) == pos) { + buildCollapsedSpan(builder, (collapsed.to == null ? len : collapsed.to) - pos, + collapsed.marker, collapsed.from == null); + if (collapsed.to == null) return collapsed.marker.find(); + } + if (foundBookmark && !collapsed) buildCollapsedSpan(builder, 0, foundBookmark); + } + if (pos >= len) break; + + var upto = Math.min(len, nextChange); + while (true) { + if (text) { + var end = pos + text.length; + if (!collapsed) { + var tokenText = end > upto ? text.slice(0, upto - pos) : text; + builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle, + spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title); + } + if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;} + pos = end; + spanStartStyle = ""; + } + text = allText.slice(at, at = styles[i++]); + style = styleToClass(styles[i++]); + } + } + } + + // DOCUMENT DATA STRUCTURE + + function updateDoc(doc, change, markedSpans, selAfter, estimateHeight) { + function spansFor(n) {return markedSpans ? markedSpans[n] : null;} + function update(line, text, spans) { + updateLine(line, text, spans, estimateHeight); + signalLater(line, "change", line, change); + } + + var from = change.from, to = change.to, text = change.text; + var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line); + var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line; + + // First adjust the line structure + if (from.ch == 0 && to.ch == 0 && lastText == "") { + // This is a whole-line replace. Treated specially to make + // sure line objects move the way they are supposed to. + for (var i = 0, e = text.length - 1, added = []; i < e; ++i) + added.push(new Line(text[i], spansFor(i), estimateHeight)); + update(lastLine, lastLine.text, lastSpans); + if (nlines) doc.remove(from.line, nlines); + if (added.length) doc.insert(from.line, added); + } else if (firstLine == lastLine) { + if (text.length == 1) { + update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans); + } else { + for (var added = [], i = 1, e = text.length - 1; i < e; ++i) + added.push(new Line(text[i], spansFor(i), estimateHeight)); + added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight)); + update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); + doc.insert(from.line + 1, added); + } + } else if (text.length == 1) { + update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0)); + doc.remove(from.line + 1, nlines); + } else { + update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); + update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans); + for (var i = 1, e = text.length - 1, added = []; i < e; ++i) + added.push(new Line(text[i], spansFor(i), estimateHeight)); + if (nlines > 1) doc.remove(from.line + 1, nlines - 1); + doc.insert(from.line + 1, added); + } + + signalLater(doc, "change", doc, change); + setSelection(doc, selAfter.anchor, selAfter.head, null, true); + } + + function LeafChunk(lines) { + this.lines = lines; + this.parent = null; + for (var i = 0, e = lines.length, height = 0; i < e; ++i) { + lines[i].parent = this; + height += lines[i].height; + } + this.height = height; + } + + LeafChunk.prototype = { + chunkSize: function() { return this.lines.length; }, + removeInner: function(at, n) { + for (var i = at, e = at + n; i < e; ++i) { + var line = this.lines[i]; + this.height -= line.height; + cleanUpLine(line); + signalLater(line, "delete"); + } + this.lines.splice(at, n); + }, + collapse: function(lines) { + lines.splice.apply(lines, [lines.length, 0].concat(this.lines)); + }, + insertInner: function(at, lines, height) { + this.height += height; + this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at)); + for (var i = 0, e = lines.length; i < e; ++i) lines[i].parent = this; + }, + iterN: function(at, n, op) { + for (var e = at + n; at < e; ++at) + if (op(this.lines[at])) return true; + } + }; + + function BranchChunk(children) { + this.children = children; + var size = 0, height = 0; + for (var i = 0, e = children.length; i < e; ++i) { + var ch = children[i]; + size += ch.chunkSize(); height += ch.height; + ch.parent = this; + } + this.size = size; + this.height = height; + this.parent = null; + } + + BranchChunk.prototype = { + chunkSize: function() { return this.size; }, + removeInner: function(at, n) { + this.size -= n; + for (var i = 0; i < this.children.length; ++i) { + var child = this.children[i], sz = child.chunkSize(); + if (at < sz) { + var rm = Math.min(n, sz - at), oldHeight = child.height; + child.removeInner(at, rm); + this.height -= oldHeight - child.height; + if (sz == rm) { this.children.splice(i--, 1); child.parent = null; } + if ((n -= rm) == 0) break; + at = 0; + } else at -= sz; + } + if (this.size - n < 25) { + var lines = []; + this.collapse(lines); + this.children = [new LeafChunk(lines)]; + this.children[0].parent = this; + } + }, + collapse: function(lines) { + for (var i = 0, e = this.children.length; i < e; ++i) this.children[i].collapse(lines); + }, + insertInner: function(at, lines, height) { + this.size += lines.length; + this.height += height; + for (var i = 0, e = this.children.length; i < e; ++i) { + var child = this.children[i], sz = child.chunkSize(); + if (at <= sz) { + child.insertInner(at, lines, height); + if (child.lines && child.lines.length > 50) { + while (child.lines.length > 50) { + var spilled = child.lines.splice(child.lines.length - 25, 25); + var newleaf = new LeafChunk(spilled); + child.height -= newleaf.height; + this.children.splice(i + 1, 0, newleaf); + newleaf.parent = this; + } + this.maybeSpill(); + } + break; + } + at -= sz; + } + }, + maybeSpill: function() { + if (this.children.length <= 10) return; + var me = this; + do { + var spilled = me.children.splice(me.children.length - 5, 5); + var sibling = new BranchChunk(spilled); + if (!me.parent) { // Become the parent node + var copy = new BranchChunk(me.children); + copy.parent = me; + me.children = [copy, sibling]; + me = copy; + } else { + me.size -= sibling.size; + me.height -= sibling.height; + var myIndex = indexOf(me.parent.children, me); + me.parent.children.splice(myIndex + 1, 0, sibling); + } + sibling.parent = me.parent; + } while (me.children.length > 10); + me.parent.maybeSpill(); + }, + iterN: function(at, n, op) { + for (var i = 0, e = this.children.length; i < e; ++i) { + var child = this.children[i], sz = child.chunkSize(); + if (at < sz) { + var used = Math.min(n, sz - at); + if (child.iterN(at, used, op)) return true; + if ((n -= used) == 0) break; + at = 0; + } else at -= sz; + } + } + }; + + var nextDocId = 0; + var Doc = CodeMirror.Doc = function(text, mode, firstLine) { + if (!(this instanceof Doc)) return new Doc(text, mode, firstLine); + if (firstLine == null) firstLine = 0; + + BranchChunk.call(this, [new LeafChunk([new Line("", null)])]); + this.first = firstLine; + this.scrollTop = this.scrollLeft = 0; + this.cantEdit = false; + this.history = makeHistory(); + this.cleanGeneration = 1; + this.frontier = firstLine; + var start = Pos(firstLine, 0); + this.sel = {from: start, to: start, head: start, anchor: start, shift: false, extend: false, goalColumn: null}; + this.id = ++nextDocId; + this.modeOption = mode; + + if (typeof text == "string") text = splitLines(text); + updateDoc(this, {from: start, to: start, text: text}, null, {head: start, anchor: start}); + }; + + Doc.prototype = createObj(BranchChunk.prototype, { + constructor: Doc, + iter: function(from, to, op) { + if (op) this.iterN(from - this.first, to - from, op); + else this.iterN(this.first, this.first + this.size, from); + }, + + insert: function(at, lines) { + var height = 0; + for (var i = 0, e = lines.length; i < e; ++i) height += lines[i].height; + this.insertInner(at - this.first, lines, height); + }, + remove: function(at, n) { this.removeInner(at - this.first, n); }, + + getValue: function(lineSep) { + var lines = getLines(this, this.first, this.first + this.size); + if (lineSep === false) return lines; + return lines.join(lineSep || "\n"); + }, + setValue: function(code) { + var top = Pos(this.first, 0), last = this.first + this.size - 1; + makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length), + text: splitLines(code), origin: "setValue"}, + {head: top, anchor: top}, true); + }, + replaceRange: function(code, from, to, origin) { + from = clipPos(this, from); + to = to ? clipPos(this, to) : from; + replaceRange(this, code, from, to, origin); + }, + getRange: function(from, to, lineSep) { + var lines = getBetween(this, clipPos(this, from), clipPos(this, to)); + if (lineSep === false) return lines; + return lines.join(lineSep || "\n"); + }, + + getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;}, + setLine: function(line, text) { + if (isLine(this, line)) + replaceRange(this, text, Pos(line, 0), clipPos(this, Pos(line))); + }, + removeLine: function(line) { + if (line) replaceRange(this, "", clipPos(this, Pos(line - 1)), clipPos(this, Pos(line))); + else replaceRange(this, "", Pos(0, 0), clipPos(this, Pos(1, 0))); + }, + + getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);}, + getLineNumber: function(line) {return lineNo(line);}, + + getLineHandleVisualStart: function(line) { + if (typeof line == "number") line = getLine(this, line); + return visualLine(this, line); + }, + + lineCount: function() {return this.size;}, + firstLine: function() {return this.first;}, + lastLine: function() {return this.first + this.size - 1;}, + + clipPos: function(pos) {return clipPos(this, pos);}, + + getCursor: function(start) { + var sel = this.sel, pos; + if (start == null || start == "head") pos = sel.head; + else if (start == "anchor") pos = sel.anchor; + else if (start == "end" || start === false) pos = sel.to; + else pos = sel.from; + return copyPos(pos); + }, + somethingSelected: function() {return !posEq(this.sel.head, this.sel.anchor);}, + + setCursor: docOperation(function(line, ch, extend) { + var pos = clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line); + if (extend) extendSelection(this, pos); + else setSelection(this, pos, pos); + }), + setSelection: docOperation(function(anchor, head) { + setSelection(this, clipPos(this, anchor), clipPos(this, head || anchor)); + }), + extendSelection: docOperation(function(from, to) { + extendSelection(this, clipPos(this, from), to && clipPos(this, to)); + }), + + getSelection: function(lineSep) {return this.getRange(this.sel.from, this.sel.to, lineSep);}, + replaceSelection: function(code, collapse, origin) { + makeChange(this, {from: this.sel.from, to: this.sel.to, text: splitLines(code), origin: origin}, collapse || "around"); + }, + undo: docOperation(function() {makeChangeFromHistory(this, "undo");}), + redo: docOperation(function() {makeChangeFromHistory(this, "redo");}), + + setExtending: function(val) {this.sel.extend = val;}, + + historySize: function() { + var hist = this.history; + return {undo: hist.done.length, redo: hist.undone.length}; + }, + clearHistory: function() {this.history = makeHistory(this.history.maxGeneration);}, + + markClean: function() { + this.cleanGeneration = this.changeGeneration(); + }, + changeGeneration: function() { + this.history.lastOp = this.history.lastOrigin = null; + return this.history.generation; + }, + isClean: function (gen) { + return this.history.generation == (gen || this.cleanGeneration); + }, + + getHistory: function() { + return {done: copyHistoryArray(this.history.done), + undone: copyHistoryArray(this.history.undone)}; + }, + setHistory: function(histData) { + var hist = this.history = makeHistory(this.history.maxGeneration); + hist.done = histData.done.slice(0); + hist.undone = histData.undone.slice(0); + }, + + markText: function(from, to, options) { + return markText(this, clipPos(this, from), clipPos(this, to), options, "range"); + }, + setBookmark: function(pos, options) { + var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options), + insertLeft: options && options.insertLeft}; + pos = clipPos(this, pos); + return markText(this, pos, pos, realOpts, "bookmark"); + }, + findMarksAt: function(pos) { + pos = clipPos(this, pos); + var markers = [], spans = getLine(this, pos.line).markedSpans; + if (spans) for (var i = 0; i < spans.length; ++i) { + var span = spans[i]; + if ((span.from == null || span.from <= pos.ch) && + (span.to == null || span.to >= pos.ch)) + markers.push(span.marker.parent || span.marker); + } + return markers; + }, + getAllMarks: function() { + var markers = []; + this.iter(function(line) { + var sps = line.markedSpans; + if (sps) for (var i = 0; i < sps.length; ++i) + if (sps[i].from != null) markers.push(sps[i].marker); + }); + return markers; + }, + + posFromIndex: function(off) { + var ch, lineNo = this.first; + this.iter(function(line) { + var sz = line.text.length + 1; + if (sz > off) { ch = off; return true; } + off -= sz; + ++lineNo; + }); + return clipPos(this, Pos(lineNo, ch)); + }, + indexFromPos: function (coords) { + coords = clipPos(this, coords); + var index = coords.ch; + if (coords.line < this.first || coords.ch < 0) return 0; + this.iter(this.first, coords.line, function (line) { + index += line.text.length + 1; + }); + return index; + }, + + copy: function(copyHistory) { + var doc = new Doc(getLines(this, this.first, this.first + this.size), this.modeOption, this.first); + doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft; + doc.sel = {from: this.sel.from, to: this.sel.to, head: this.sel.head, anchor: this.sel.anchor, + shift: this.sel.shift, extend: false, goalColumn: this.sel.goalColumn}; + if (copyHistory) { + doc.history.undoDepth = this.history.undoDepth; + doc.setHistory(this.getHistory()); + } + return doc; + }, + + linkedDoc: function(options) { + if (!options) options = {}; + var from = this.first, to = this.first + this.size; + if (options.from != null && options.from > from) from = options.from; + if (options.to != null && options.to < to) to = options.to; + var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from); + if (options.sharedHist) copy.history = this.history; + (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist}); + copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}]; + return copy; + }, + unlinkDoc: function(other) { + if (other instanceof CodeMirror) other = other.doc; + if (this.linked) for (var i = 0; i < this.linked.length; ++i) { + var link = this.linked[i]; + if (link.doc != other) continue; + this.linked.splice(i, 1); + other.unlinkDoc(this); + break; + } + // If the histories were shared, split them again + if (other.history == this.history) { + var splitIds = [other.id]; + linkedDocs(other, function(doc) {splitIds.push(doc.id);}, true); + other.history = makeHistory(); + other.history.done = copyHistoryArray(this.history.done, splitIds); + other.history.undone = copyHistoryArray(this.history.undone, splitIds); + } + }, + iterLinkedDocs: function(f) {linkedDocs(this, f);}, + + getMode: function() {return this.mode;}, + getEditor: function() {return this.cm;} + }); + + Doc.prototype.eachLine = Doc.prototype.iter; + + // The Doc methods that should be available on CodeMirror instances + var dontDelegate = "iter insert remove copy getEditor".split(" "); + for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0) + CodeMirror.prototype[prop] = (function(method) { + return function() {return method.apply(this.doc, arguments);}; + })(Doc.prototype[prop]); + + eventMixin(Doc); + + function linkedDocs(doc, f, sharedHistOnly) { + function propagate(doc, skip, sharedHist) { + if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) { + var rel = doc.linked[i]; + if (rel.doc == skip) continue; + var shared = sharedHist && rel.sharedHist; + if (sharedHistOnly && !shared) continue; + f(rel.doc, shared); + propagate(rel.doc, doc, shared); + } + } + propagate(doc, null, true); + } + + function attachDoc(cm, doc) { + if (doc.cm) throw new Error("This document is already in use."); + cm.doc = doc; + doc.cm = cm; + estimateLineHeights(cm); + loadMode(cm); + if (!cm.options.lineWrapping) computeMaxLength(cm); + cm.options.mode = doc.modeOption; + regChange(cm); + } + + // LINE UTILITIES + + function getLine(chunk, n) { + n -= chunk.first; + while (!chunk.lines) { + for (var i = 0;; ++i) { + var child = chunk.children[i], sz = child.chunkSize(); + if (n < sz) { chunk = child; break; } + n -= sz; + } + } + return chunk.lines[n]; + } + + function getBetween(doc, start, end) { + var out = [], n = start.line; + doc.iter(start.line, end.line + 1, function(line) { + var text = line.text; + if (n == end.line) text = text.slice(0, end.ch); + if (n == start.line) text = text.slice(start.ch); + out.push(text); + ++n; + }); + return out; + } + function getLines(doc, from, to) { + var out = []; + doc.iter(from, to, function(line) { out.push(line.text); }); + return out; + } + + function updateLineHeight(line, height) { + var diff = height - line.height; + for (var n = line; n; n = n.parent) n.height += diff; + } + + function lineNo(line) { + if (line.parent == null) return null; + var cur = line.parent, no = indexOf(cur.lines, line); + for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) { + for (var i = 0;; ++i) { + if (chunk.children[i] == cur) break; + no += chunk.children[i].chunkSize(); + } + } + return no + cur.first; + } + + function lineAtHeight(chunk, h) { + var n = chunk.first; + outer: do { + for (var i = 0, e = chunk.children.length; i < e; ++i) { + var child = chunk.children[i], ch = child.height; + if (h < ch) { chunk = child; continue outer; } + h -= ch; + n += child.chunkSize(); + } + return n; + } while (!chunk.lines); + for (var i = 0, e = chunk.lines.length; i < e; ++i) { + var line = chunk.lines[i], lh = line.height; + if (h < lh) break; + h -= lh; + } + return n + i; + } + + function heightAtLine(cm, lineObj) { + lineObj = visualLine(cm.doc, lineObj); + + var h = 0, chunk = lineObj.parent; + for (var i = 0; i < chunk.lines.length; ++i) { + var line = chunk.lines[i]; + if (line == lineObj) break; + else h += line.height; + } + for (var p = chunk.parent; p; chunk = p, p = chunk.parent) { + for (var i = 0; i < p.children.length; ++i) { + var cur = p.children[i]; + if (cur == chunk) break; + else h += cur.height; + } + } + return h; + } + + function getOrder(line) { + var order = line.order; + if (order == null) order = line.order = bidiOrdering(line.text); + return order; + } + + // HISTORY + + function makeHistory(startGen) { + return { + // Arrays of history events. Doing something adds an event to + // done and clears undo. Undoing moves events from done to + // undone, redoing moves them in the other direction. + done: [], undone: [], undoDepth: Infinity, + // Used to track when changes can be merged into a single undo + // event + lastTime: 0, lastOp: null, lastOrigin: null, + // Used by the isClean() method + generation: startGen || 1, maxGeneration: startGen || 1 + }; + } + + function attachLocalSpans(doc, change, from, to) { + var existing = change["spans_" + doc.id], n = 0; + doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) { + if (line.markedSpans) + (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans; + ++n; + }); + } + + function historyChangeFromChange(doc, change) { + var from = { line: change.from.line, ch: change.from.ch }; + var histChange = {from: from, to: changeEnd(change), text: getBetween(doc, change.from, change.to)}; + attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); + linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);}, true); + return histChange; + } + + function addToHistory(doc, change, selAfter, opId) { + var hist = doc.history; + hist.undone.length = 0; + var time = +new Date, cur = lst(hist.done); + + if (cur && + (hist.lastOp == opId || + hist.lastOrigin == change.origin && change.origin && + ((change.origin.charAt(0) == "+" && doc.cm && hist.lastTime > time - doc.cm.options.historyEventDelay) || + change.origin.charAt(0) == "*"))) { + // Merge this change into the last event + var last = lst(cur.changes); + if (posEq(change.from, change.to) && posEq(change.from, last.to)) { + // Optimized case for simple insertion -- don't want to add + // new changesets for every character typed + last.to = changeEnd(change); + } else { + // Add new sub-event + cur.changes.push(historyChangeFromChange(doc, change)); + } + cur.anchorAfter = selAfter.anchor; cur.headAfter = selAfter.head; + } else { + // Can not be merged, start a new event. + cur = {changes: [historyChangeFromChange(doc, change)], + generation: hist.generation, + anchorBefore: doc.sel.anchor, headBefore: doc.sel.head, + anchorAfter: selAfter.anchor, headAfter: selAfter.head}; + hist.done.push(cur); + hist.generation = ++hist.maxGeneration; + while (hist.done.length > hist.undoDepth) + hist.done.shift(); + } + hist.lastTime = time; + hist.lastOp = opId; + hist.lastOrigin = change.origin; + } + + function removeClearedSpans(spans) { + if (!spans) return null; + for (var i = 0, out; i < spans.length; ++i) { + if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); } + else if (out) out.push(spans[i]); + } + return !out ? spans : out.length ? out : null; + } + + function getOldSpans(doc, change) { + var found = change["spans_" + doc.id]; + if (!found) return null; + for (var i = 0, nw = []; i < change.text.length; ++i) + nw.push(removeClearedSpans(found[i])); + return nw; + } + + // Used both to provide a JSON-safe object in .getHistory, and, when + // detaching a document, to split the history in two + function copyHistoryArray(events, newGroup) { + for (var i = 0, copy = []; i < events.length; ++i) { + var event = events[i], changes = event.changes, newChanges = []; + copy.push({changes: newChanges, anchorBefore: event.anchorBefore, headBefore: event.headBefore, + anchorAfter: event.anchorAfter, headAfter: event.headAfter}); + for (var j = 0; j < changes.length; ++j) { + var change = changes[j], m; + newChanges.push({from: change.from, to: change.to, text: change.text}); + if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) { + if (indexOf(newGroup, Number(m[1])) > -1) { + lst(newChanges)[prop] = change[prop]; + delete change[prop]; + } + } + } + } + return copy; + } + + // Rebasing/resetting history to deal with externally-sourced changes + + function rebaseHistSel(pos, from, to, diff) { + if (to < pos.line) { + pos.line += diff; + } else if (from < pos.line) { + pos.line = from; + pos.ch = 0; + } + } + + // Tries to rebase an array of history events given a change in the + // document. If the change touches the same lines as the event, the + // event, and everything 'behind' it, is discarded. If the change is + // before the event, the event's positions are updated. Uses a + // copy-on-write scheme for the positions, to avoid having to + // reallocate them all on every rebase, but also avoid problems with + // shared position objects being unsafely updated. + function rebaseHistArray(array, from, to, diff) { + for (var i = 0; i < array.length; ++i) { + var sub = array[i], ok = true; + for (var j = 0; j < sub.changes.length; ++j) { + var cur = sub.changes[j]; + if (!sub.copied) { cur.from = copyPos(cur.from); cur.to = copyPos(cur.to); } + if (to < cur.from.line) { + cur.from.line += diff; + cur.to.line += diff; + } else if (from <= cur.to.line) { + ok = false; + break; + } + } + if (!sub.copied) { + sub.anchorBefore = copyPos(sub.anchorBefore); sub.headBefore = copyPos(sub.headBefore); + sub.anchorAfter = copyPos(sub.anchorAfter); sub.readAfter = copyPos(sub.headAfter); + sub.copied = true; + } + if (!ok) { + array.splice(0, i + 1); + i = 0; + } else { + rebaseHistSel(sub.anchorBefore); rebaseHistSel(sub.headBefore); + rebaseHistSel(sub.anchorAfter); rebaseHistSel(sub.headAfter); + } + } + } + + function rebaseHist(hist, change) { + var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1; + rebaseHistArray(hist.done, from, to, diff); + rebaseHistArray(hist.undone, from, to, diff); + } + + // EVENT OPERATORS + + function stopMethod() {e_stop(this);} + // Ensure an event has a stop method. + function addStop(event) { + if (!event.stop) event.stop = stopMethod; + return event; + } + + function e_preventDefault(e) { + if (e.preventDefault) e.preventDefault(); + else e.returnValue = false; + } + function e_stopPropagation(e) { + if (e.stopPropagation) e.stopPropagation(); + else e.cancelBubble = true; + } + function e_defaultPrevented(e) { + return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false; + } + function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);} + CodeMirror.e_stop = e_stop; + CodeMirror.e_preventDefault = e_preventDefault; + CodeMirror.e_stopPropagation = e_stopPropagation; + + function e_target(e) {return e.target || e.srcElement;} + function e_button(e) { + var b = e.which; + if (b == null) { + if (e.button & 1) b = 1; + else if (e.button & 2) b = 3; + else if (e.button & 4) b = 2; + } + if (mac && e.ctrlKey && b == 1) b = 3; + return b; + } + + // EVENT HANDLING + + function on(emitter, type, f) { + if (emitter.addEventListener) + emitter.addEventListener(type, f, false); + else if (emitter.attachEvent) + emitter.attachEvent("on" + type, f); + else { + var map = emitter._handlers || (emitter._handlers = {}); + var arr = map[type] || (map[type] = []); + arr.push(f); + } + } + + function off(emitter, type, f) { + if (emitter.removeEventListener) + emitter.removeEventListener(type, f, false); + else if (emitter.detachEvent) + emitter.detachEvent("on" + type, f); + else { + var arr = emitter._handlers && emitter._handlers[type]; + if (!arr) return; + for (var i = 0; i < arr.length; ++i) + if (arr[i] == f) { arr.splice(i, 1); break; } + } + } + + function signal(emitter, type /*, values...*/) { + var arr = emitter._handlers && emitter._handlers[type]; + if (!arr) return; + var args = Array.prototype.slice.call(arguments, 2); + for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args); + } + + var delayedCallbacks, delayedCallbackDepth = 0; + function signalLater(emitter, type /*, values...*/) { + var arr = emitter._handlers && emitter._handlers[type]; + if (!arr) return; + var args = Array.prototype.slice.call(arguments, 2); + if (!delayedCallbacks) { + ++delayedCallbackDepth; + delayedCallbacks = []; + setTimeout(fireDelayed, 0); + } + function bnd(f) {return function(){f.apply(null, args);};}; + for (var i = 0; i < arr.length; ++i) + delayedCallbacks.push(bnd(arr[i])); + } + + function signalDOMEvent(cm, e, override) { + signal(cm, override || e.type, cm, e); + return e_defaultPrevented(e) || e.codemirrorIgnore; + } + + function fireDelayed() { + --delayedCallbackDepth; + var delayed = delayedCallbacks; + delayedCallbacks = null; + for (var i = 0; i < delayed.length; ++i) delayed[i](); + } + + function hasHandler(emitter, type) { + var arr = emitter._handlers && emitter._handlers[type]; + return arr && arr.length > 0; + } + + CodeMirror.on = on; CodeMirror.off = off; CodeMirror.signal = signal; + + function eventMixin(ctor) { + ctor.prototype.on = function(type, f) {on(this, type, f);}; + ctor.prototype.off = function(type, f) {off(this, type, f);}; + } + + // MISC UTILITIES + + // Number of pixels added to scroller and sizer to hide scrollbar + var scrollerCutOff = 30; + + // Returned or thrown by various protocols to signal 'I'm not + // handling this'. + var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}}; + + function Delayed() {this.id = null;} + Delayed.prototype = {set: function(ms, f) {clearTimeout(this.id); this.id = setTimeout(f, ms);}}; + + // Counts the column offset in a string, taking tabs into account. + // Used mostly to find indentation. + function countColumn(string, end, tabSize, startIndex, startValue) { + if (end == null) { + end = string.search(/[^\s\u00a0]/); + if (end == -1) end = string.length; + } + for (var i = startIndex || 0, n = startValue || 0; i < end; ++i) { + if (string.charAt(i) == "\t") n += tabSize - (n % tabSize); + else ++n; + } + return n; + } + CodeMirror.countColumn = countColumn; + + var spaceStrs = [""]; + function spaceStr(n) { + while (spaceStrs.length <= n) + spaceStrs.push(lst(spaceStrs) + " "); + return spaceStrs[n]; + } + + function lst(arr) { return arr[arr.length-1]; } + + function selectInput(node) { + if (ios) { // Mobile Safari apparently has a bug where select() is broken. + node.selectionStart = 0; + node.selectionEnd = node.value.length; + } else { + // Suppress mysterious IE10 errors + try { node.select(); } + catch(_e) {} + } + } + + function indexOf(collection, elt) { + if (collection.indexOf) return collection.indexOf(elt); + for (var i = 0, e = collection.length; i < e; ++i) + if (collection[i] == elt) return i; + return -1; + } + + function createObj(base, props) { + function Obj() {} + Obj.prototype = base; + var inst = new Obj(); + if (props) copyObj(props, inst); + return inst; + } + + function copyObj(obj, target) { + if (!target) target = {}; + for (var prop in obj) if (obj.hasOwnProperty(prop)) target[prop] = obj[prop]; + return target; + } + + function emptyArray(size) { + for (var a = [], i = 0; i < size; ++i) a.push(undefined); + return a; + } + + function bind(f) { + var args = Array.prototype.slice.call(arguments, 1); + return function(){return f.apply(null, args);}; + } + + var nonASCIISingleCaseWordChar = /[\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; + function isWordChar(ch) { + return /\w/.test(ch) || ch > "\x80" && + (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)); + } + + function isEmpty(obj) { + for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false; + return true; + } + + var isExtendingChar = /[\u0300-\u036F\u0483-\u0487\u0488-\u0489\u0591-\u05BD\u05BF\u05C1-\u05C2\u05C4-\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7-\u06E8\u06EA-\u06ED\uA66F\uA670-\uA672\uA674-\uA67D\uA69F\udc00-\udfff]/; + + // DOM UTILITIES + + function elt(tag, content, className, style) { + var e = document.createElement(tag); + if (className) e.className = className; + if (style) e.style.cssText = style; + if (typeof content == "string") setTextContent(e, content); + else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]); + return e; + } + + function removeChildren(e) { + for (var count = e.childNodes.length; count > 0; --count) + e.removeChild(e.firstChild); + return e; + } + + function removeChildrenAndAdd(parent, e) { + return removeChildren(parent).appendChild(e); + } + + function setTextContent(e, str) { + if (ie_lt9) { + e.innerHTML = ""; + e.appendChild(document.createTextNode(str)); + } else e.textContent = str; + } + + function getRect(node) { + return node.getBoundingClientRect(); + } + CodeMirror.replaceGetRect = function(f) { getRect = f; }; + + // FEATURE DETECTION + + // Detect drag-and-drop + var dragAndDrop = function() { + // There is *some* kind of drag-and-drop support in IE6-8, but I + // couldn't get it to work yet. + if (ie_lt9) return false; + var div = elt('div'); + return "draggable" in div || "dragDrop" in div; + }(); + + // For a reason I have yet to figure out, some browsers disallow + // word wrapping between certain characters *only* if a new inline + // element is started between them. This makes it hard to reliably + // measure the position of things, since that requires inserting an + // extra span. This terribly fragile set of tests matches the + // character combinations that suffer from this phenomenon on the + // various browsers. + function spanAffectsWrapping() { return false; } + if (gecko) // Only for "$'" + spanAffectsWrapping = function(str, i) { + return str.charCodeAt(i - 1) == 36 && str.charCodeAt(i) == 39; + }; + else if (safari && !/Version\/([6-9]|\d\d)\b/.test(navigator.userAgent)) + spanAffectsWrapping = function(str, i) { + return /\-[^ \-?]|\?[^ !\'\"\),.\-\/:;\?\]\}]/.test(str.slice(i - 1, i + 1)); + }; + else if (webkit && !/Chrome\/(?:29|[3-9]\d|\d\d\d)\./.test(navigator.userAgent)) + spanAffectsWrapping = function(str, i) { + if (i > 1 && str.charCodeAt(i - 1) == 45) { + if (/\w/.test(str.charAt(i - 2)) && /[^\-?\.]/.test(str.charAt(i))) return true; + if (i > 2 && /[\d\.,]/.test(str.charAt(i - 2)) && /[\d\.,]/.test(str.charAt(i))) return false; + } + return /[~!#%&*)=+}\]|\"\.>,:;][({[<]|-[^\-?\.\u2010-\u201f\u2026]|\?[\w~`@#$%\^&*(_=+{[|><]|…[\w~`@#$%\^&*(_=+{[><]/.test(str.slice(i - 1, i + 1)); + }; + + var knownScrollbarWidth; + function scrollbarWidth(measure) { + if (knownScrollbarWidth != null) return knownScrollbarWidth; + var test = elt("div", null, null, "width: 50px; height: 50px; overflow-x: scroll"); + removeChildrenAndAdd(measure, test); + if (test.offsetWidth) + knownScrollbarWidth = test.offsetHeight - test.clientHeight; + return knownScrollbarWidth || 0; + } + + var zwspSupported; + function zeroWidthElement(measure) { + if (zwspSupported == null) { + var test = elt("span", "\u200b"); + removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")])); + if (measure.firstChild.offsetHeight != 0) + zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !ie_lt8; + } + if (zwspSupported) return elt("span", "\u200b"); + else return elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px"); + } + + // See if "".split is the broken IE version, if so, provide an + // alternative way to split lines. + var splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) { + var pos = 0, result = [], l = string.length; + while (pos <= l) { + var nl = string.indexOf("\n", pos); + if (nl == -1) nl = string.length; + var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl); + var rt = line.indexOf("\r"); + if (rt != -1) { + result.push(line.slice(0, rt)); + pos += rt + 1; + } else { + result.push(line); + pos = nl + 1; + } + } + return result; + } : function(string){return string.split(/\r\n?|\n/);}; + CodeMirror.splitLines = splitLines; + + var hasSelection = window.getSelection ? function(te) { + try { return te.selectionStart != te.selectionEnd; } + catch(e) { return false; } + } : function(te) { + try {var range = te.ownerDocument.selection.createRange();} + catch(e) {} + if (!range || range.parentElement() != te) return false; + return range.compareEndPoints("StartToEnd", range) != 0; + }; + + var hasCopyEvent = (function() { + var e = elt("div"); + if ("oncopy" in e) return true; + e.setAttribute("oncopy", "return;"); + return typeof e.oncopy == 'function'; + })(); + + // KEY NAMING + + var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt", + 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End", + 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert", + 46: "Delete", 59: ";", 91: "Mod", 92: "Mod", 93: "Mod", 109: "-", 107: "=", 127: "Delete", + 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", + 221: "]", 222: "'", 63276: "PageUp", 63277: "PageDown", 63275: "End", 63273: "Home", + 63234: "Left", 63232: "Up", 63235: "Right", 63233: "Down", 63302: "Insert", 63272: "Delete"}; + CodeMirror.keyNames = keyNames; + (function() { + // Number keys + for (var i = 0; i < 10; i++) keyNames[i + 48] = String(i); + // Alphabetic keys + for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i); + // Function keys + for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i; + })(); + + // BIDI HELPERS + + function iterateBidiSections(order, from, to, f) { + if (!order) return f(from, to, "ltr"); + var found = false; + for (var i = 0; i < order.length; ++i) { + var part = order[i]; + if (part.from < to && part.to > from || from == to && part.to == from) { + f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr"); + found = true; + } + } + if (!found) f(from, to, "ltr"); + } + + function bidiLeft(part) { return part.level % 2 ? part.to : part.from; } + function bidiRight(part) { return part.level % 2 ? part.from : part.to; } + + function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; } + function lineRight(line) { + var order = getOrder(line); + if (!order) return line.text.length; + return bidiRight(lst(order)); + } + + function lineStart(cm, lineN) { + var line = getLine(cm.doc, lineN); + var visual = visualLine(cm.doc, line); + if (visual != line) lineN = lineNo(visual); + var order = getOrder(visual); + var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual); + return Pos(lineN, ch); + } + function lineEnd(cm, lineN) { + var merged, line; + while (merged = collapsedSpanAtEnd(line = getLine(cm.doc, lineN))) + lineN = merged.find().to.line; + var order = getOrder(line); + var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line); + return Pos(lineN, ch); + } + + function compareBidiLevel(order, a, b) { + var linedir = order[0].level; + if (a == linedir) return true; + if (b == linedir) return false; + return a < b; + } + var bidiOther; + function getBidiPartAt(order, pos) { + for (var i = 0, found; i < order.length; ++i) { + var cur = order[i]; + if (cur.from < pos && cur.to > pos) { bidiOther = null; return i; } + if (cur.from == pos || cur.to == pos) { + if (found == null) { + found = i; + } else if (compareBidiLevel(order, cur.level, order[found].level)) { + bidiOther = found; + return i; + } else { + bidiOther = i; + return found; + } + } + } + bidiOther = null; + return found; + } + + function moveInLine(line, pos, dir, byUnit) { + if (!byUnit) return pos + dir; + do pos += dir; + while (pos > 0 && isExtendingChar.test(line.text.charAt(pos))); + return pos; + } + + // This is somewhat involved. It is needed in order to move + // 'visually' through bi-directional text -- i.e., pressing left + // should make the cursor go left, even when in RTL text. The + // tricky part is the 'jumps', where RTL and LTR text touch each + // other. This often requires the cursor offset to move more than + // one unit, in order to visually move one unit. + function moveVisually(line, start, dir, byUnit) { + var bidi = getOrder(line); + if (!bidi) return moveLogically(line, start, dir, byUnit); + var pos = getBidiPartAt(bidi, start), part = bidi[pos]; + var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit); + + for (;;) { + if (target > part.from && target < part.to) return target; + if (target == part.from || target == part.to) { + if (getBidiPartAt(bidi, target) == pos) return target; + part = bidi[pos += dir]; + return (dir > 0) == part.level % 2 ? part.to : part.from; + } else { + part = bidi[pos += dir]; + if (!part) return null; + if ((dir > 0) == part.level % 2) + target = moveInLine(line, part.to, -1, byUnit); + else + target = moveInLine(line, part.from, 1, byUnit); + } + } + } + + function moveLogically(line, start, dir, byUnit) { + var target = start + dir; + if (byUnit) while (target > 0 && isExtendingChar.test(line.text.charAt(target))) target += dir; + return target < 0 || target > line.text.length ? null : target; + } + + // Bidirectional ordering algorithm + // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm + // that this (partially) implements. + + // One-char codes used for character types: + // L (L): Left-to-Right + // R (R): Right-to-Left + // r (AL): Right-to-Left Arabic + // 1 (EN): European Number + // + (ES): European Number Separator + // % (ET): European Number Terminator + // n (AN): Arabic Number + // , (CS): Common Number Separator + // m (NSM): Non-Spacing Mark + // b (BN): Boundary Neutral + // s (B): Paragraph Separator + // t (S): Segment Separator + // w (WS): Whitespace + // N (ON): Other Neutrals + + // Returns null if characters are ordered as they appear + // (left-to-right), or an array of sections ({from, to, level} + // objects) in the order in which they occur visually. + var bidiOrdering = (function() { + // Character types for codepoints 0 to 0xff + var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLL"; + // Character types for codepoints 0x600 to 0x6ff + var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmmrrrrrrrrrrrrrrrrrr"; + function charType(code) { + if (code <= 0xff) return lowTypes.charAt(code); + else if (0x590 <= code && code <= 0x5f4) return "R"; + else if (0x600 <= code && code <= 0x6ff) return arabicTypes.charAt(code - 0x600); + else if (0x700 <= code && code <= 0x8ac) return "r"; + else return "L"; + } + + var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/; + var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/; + // Browsers seem to always treat the boundaries of block elements as being L. + var outerType = "L"; + + return function(str) { + if (!bidiRE.test(str)) return false; + var len = str.length, types = []; + for (var i = 0, type; i < len; ++i) + types.push(type = charType(str.charCodeAt(i))); + + // W1. Examine each non-spacing mark (NSM) in the level run, and + // change the type of the NSM to the type of the previous + // character. If the NSM is at the start of the level run, it will + // get the type of sor. + for (var i = 0, prev = outerType; i < len; ++i) { + var type = types[i]; + if (type == "m") types[i] = prev; + else prev = type; + } + + // W2. Search backwards from each instance of a European number + // until the first strong type (R, L, AL, or sor) is found. If an + // AL is found, change the type of the European number to Arabic + // number. + // W3. Change all ALs to R. + for (var i = 0, cur = outerType; i < len; ++i) { + var type = types[i]; + if (type == "1" && cur == "r") types[i] = "n"; + else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R"; } + } + + // W4. A single European separator between two European numbers + // changes to a European number. A single common separator between + // two numbers of the same type changes to that type. + for (var i = 1, prev = types[0]; i < len - 1; ++i) { + var type = types[i]; + if (type == "+" && prev == "1" && types[i+1] == "1") types[i] = "1"; + else if (type == "," && prev == types[i+1] && + (prev == "1" || prev == "n")) types[i] = prev; + prev = type; + } + + // W5. A sequence of European terminators adjacent to European + // numbers changes to all European numbers. + // W6. Otherwise, separators and terminators change to Other + // Neutral. + for (var i = 0; i < len; ++i) { + var type = types[i]; + if (type == ",") types[i] = "N"; + else if (type == "%") { + for (var end = i + 1; end < len && types[end] == "%"; ++end) {} + var replace = (i && types[i-1] == "!") || (end < len - 1 && types[end] == "1") ? "1" : "N"; + for (var j = i; j < end; ++j) types[j] = replace; + i = end - 1; + } + } + + // W7. Search backwards from each instance of a European number + // until the first strong type (R, L, or sor) is found. If an L is + // found, then change the type of the European number to L. + for (var i = 0, cur = outerType; i < len; ++i) { + var type = types[i]; + if (cur == "L" && type == "1") types[i] = "L"; + else if (isStrong.test(type)) cur = type; + } + + // N1. A sequence of neutrals takes the direction of the + // surrounding strong text if the text on both sides has the same + // direction. European and Arabic numbers act as if they were R in + // terms of their influence on neutrals. Start-of-level-run (sor) + // and end-of-level-run (eor) are used at level run boundaries. + // N2. Any remaining neutrals take the embedding direction. + for (var i = 0; i < len; ++i) { + if (isNeutral.test(types[i])) { + for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {} + var before = (i ? types[i-1] : outerType) == "L"; + var after = (end < len - 1 ? types[end] : outerType) == "L"; + var replace = before || after ? "L" : "R"; + for (var j = i; j < end; ++j) types[j] = replace; + i = end - 1; + } + } + + // Here we depart from the documented algorithm, in order to avoid + // building up an actual levels array. Since there are only three + // levels (0, 1, 2) in an implementation that doesn't take + // explicit embedding into account, we can build up the order on + // the fly, without following the level-based algorithm. + var order = [], m; + for (var i = 0; i < len;) { + if (countsAsLeft.test(types[i])) { + var start = i; + for (++i; i < len && countsAsLeft.test(types[i]); ++i) {} + order.push({from: start, to: i, level: 0}); + } else { + var pos = i, at = order.length; + for (++i; i < len && types[i] != "L"; ++i) {} + for (var j = pos; j < i;) { + if (countsAsNum.test(types[j])) { + if (pos < j) order.splice(at, 0, {from: pos, to: j, level: 1}); + var nstart = j; + for (++j; j < i && countsAsNum.test(types[j]); ++j) {} + order.splice(at, 0, {from: nstart, to: j, level: 2}); + pos = j; + } else ++j; + } + if (pos < i) order.splice(at, 0, {from: pos, to: i, level: 1}); + } + } + if (order[0].level == 1 && (m = str.match(/^\s+/))) { + order[0].from = m[0].length; + order.unshift({from: 0, to: m[0].length, level: 0}); + } + if (lst(order).level == 1 && (m = str.match(/\s+$/))) { + lst(order).to -= m[0].length; + order.push({from: len - m[0].length, to: len, level: 0}); + } + if (order[0].level != lst(order).level) + order.push({from: len, to: len, level: order[0].level}); + + return order; + }; + })(); + + // THE END + + CodeMirror.version = "3.15.0"; + + return CodeMirror; +})(); diff --git a/phpMyAdmin/js/codemirror/mode/mysql/mysql.js b/phpMyAdmin/js/codemirror/mode/mysql/mysql.js deleted file mode 100644 index 79d38cf..0000000 --- a/phpMyAdmin/js/codemirror/mode/mysql/mysql.js +++ /dev/null @@ -1,7 +0,0 @@ -CodeMirror.defineMode("mysql",function(f,d){function g(a,e){var b=a.next();if(b=='"'||b=="'"||b=="`"){b=h(b);e.tokenize=b;return b(a,e)}else if(/[\[\]{}\(\),;\.]/.test(b))return"separator";else if(/\d/.test(b)){a.eatWhile(/[\w\.]/);return"number"}else if(b=="/")if(a.eat("*")){b=r;e.tokenize=b;return b(a,e)}else{a.eatWhile(i);return"operator"}else if(b=="-")if(a.eat("-")){a.skipToEnd();return"comment"}else{a.eatWhile(i);return"operator"}else if(b=="@"||b=="$"){a.eatWhile(/[\w\d\$_]/);return"variable"}else if(i.test(b)){a.eatWhile(i); -return"operator"}else{a.eatWhile(/[\w\$_]/);var c=a.current().toLowerCase();b=a.pos;if(k&&k.propertyIsEnumerable(c))return"statement-verb";if(l&&l.propertyIsEnumerable(c))return"keyword";if(m&&m.propertyIsEnumerable(c)){a.eatSpace();if(a.peek()=="(")return"builtin";a.pos=b}if(n&&n.propertyIsEnumerable(c))return"variable-2";if(o&&o.propertyIsEnumerable(c))return"variable-3";a.eatSpace();a.eatWhile(/[\w\$_]/);c=a.current().toLowerCase();if(p&&p.propertyIsEnumerable(c))return"keyword";a.pos=b;return"mysql-word"}} -function h(a){return function(e,b){for(var c=false,j,q=false;(j=e.next())!=null;){if(j==a&&!c){q=true;break}c=!c&&j=="\\"}if(q||!(c||s))b.tokenize=g;return"mysql-string"}}function r(a,e){for(var b=false,c;c=a.next();){if(c=="/"&&b){e.tokenize=g;break}b=c=="*"}return"mysql-comment"}var l=d.keywords,k=d.verbs,m=d.functions,n=d.types,o=d.attributes,s=d.multiLineStrings,p=d.multiPartKeywords,i=/[+\-*&%=<>!?:\/|]/;return{startState:function(){return{tokenize:g,startOfLine:true}},token:function(a,e){if(a.eatSpace())return null; -return e.tokenize(a,e)}}}); -(function(){function f(d){var g={},h=d;if(typeof d=="string")h=d.split(" ");for(d=0;d!=&|~^]/, + support = parserConfig.support || {}, + hooks = parserConfig.hooks || {}, + dateSQL = parserConfig.dateSQL || {"date" : true, "time" : true, "timestamp" : true}; + + function tokenBase(stream, state) { + var ch = stream.next(); + + // call hooks from the mime type + if (hooks[ch]) { + var result = hooks[ch](stream, state); + if (result !== false) return result; + } + + if (support.hexNumber == true && + ((ch == "0" && stream.match(/^[xX][0-9a-fA-F]+/)) + || (ch == "x" || ch == "X") && stream.match(/^'[0-9a-fA-F]+'/))) { + // hex + // ref: http://dev.mysql.com/doc/refman/5.5/en/hexadecimal-literals.html + return "number"; + } else if (support.binaryNumber == true && + (((ch == "b" || ch == "B") && stream.match(/^'[01]+'/)) + || (ch == "0" && stream.match(/^b[01]+/)))) { + // bitstring + // ref: http://dev.mysql.com/doc/refman/5.5/en/bit-field-literals.html + return "number"; + } else if (ch.charCodeAt(0) > 47 && ch.charCodeAt(0) < 58) { + // numbers + // ref: http://dev.mysql.com/doc/refman/5.5/en/number-literals.html + stream.match(/^[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/); + support.decimallessFloat == true && stream.eat('.'); + return "number"; + } else if (ch == "?" && (stream.eatSpace() || stream.eol() || stream.eat(";"))) { + // placeholders + return "variable-3"; + } else if (ch == "'" || (ch == '"' && support.doubleQuote)) { + // strings + // ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html + state.tokenize = tokenLiteral(ch); + return state.tokenize(stream, state); + } else if ((((support.nCharCast == true && (ch == "n" || ch == "N")) + || (support.charsetCast == true && ch == "_" && stream.match(/[a-z][a-z0-9]*/i))) + && (stream.peek() == "'" || stream.peek() == '"'))) { + // charset casting: _utf8'str', N'str', n'str' + // ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html + return "keyword"; + } else if (/^[\(\),\;\[\]]/.test(ch)) { + // no highlightning + return null; + } else if (support.commentSlashSlash && ch == "/" && stream.eat("/")) { + // 1-line comment + stream.skipToEnd(); + return "comment"; + } else if ((support.commentHash && ch == "#") + || (ch == "-" && stream.eat("-") && (!support.commentSpaceRequired || stream.eat(" ")))) { + // 1-line comments + // ref: https://kb.askmonty.org/en/comment-syntax/ + stream.skipToEnd(); + return "comment"; + } else if (ch == "/" && stream.eat("*")) { + // multi-line comments + // ref: https://kb.askmonty.org/en/comment-syntax/ + state.tokenize = tokenComment; + return state.tokenize(stream, state); + } else if (ch == ".") { + // .1 for 0.1 + if (support.zerolessFloat == true && stream.match(/^(?:\d+(?:e[+-]?\d+)?)/i)) { + return "number"; + } + // .table_name (ODBC) + // // ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html + if (support.ODBCdotTable == true && stream.match(/^[a-zA-Z_]+/)) { + return "variable-2"; + } + } else if (operatorChars.test(ch)) { + // operators + stream.eatWhile(operatorChars); + return null; + } else if (ch == '{' && + (stream.match(/^( )*(d|D|t|T|ts|TS)( )*'[^']*'( )*}/) || stream.match(/^( )*(d|D|t|T|ts|TS)( )*"[^"]*"( )*}/))) { + // dates (weird ODBC syntax) + // ref: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-literals.html + return "number"; + } else { + stream.eatWhile(/^[_\w\d]/); + var word = stream.current().toLowerCase(); + // dates (standard SQL syntax) + // ref: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-literals.html + if (dateSQL.hasOwnProperty(word) && (stream.match(/^( )+'[^']*'/) || stream.match(/^( )+"[^"]*"/))) + return "number"; + if (atoms.hasOwnProperty(word)) return "atom"; + if (builtin.hasOwnProperty(word)) return "builtin"; + if (keywords.hasOwnProperty(word)) return "keyword"; + if (client.hasOwnProperty(word)) return "string-2"; + return null; + } + } + + // 'string', with char specified in quote escaped by '\' + function tokenLiteral(quote) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) { + state.tokenize = tokenBase; + break; + } + escaped = !escaped && ch == "\\"; + } + return "string"; + }; + } + function tokenComment(stream, state) { + while (true) { + if (stream.skipTo("*")) { + stream.next(); + if (stream.eat("/")) { + state.tokenize = tokenBase; + break; + } + } else { + stream.skipToEnd(); + break; + } + } + return "comment"; + } + + function pushContext(stream, state, type) { + state.context = { + prev: state.context, + indent: stream.indentation(), + col: stream.column(), + type: type + }; + } + + function popContext(state) { + state.indent = state.context.indent; + state.context = state.context.prev; + } + + return { + startState: function() { + return {tokenize: tokenBase, context: null}; + }, + + token: function(stream, state) { + if (stream.sol()) { + if (state.context && state.context.align == null) + state.context.align = false; + } + if (stream.eatSpace()) return null; + + var style = state.tokenize(stream, state); + if (style == "comment") return style; + + if (state.context && state.context.align == null) + state.context.align = true; + + var tok = stream.current(); + if (tok == "(") + pushContext(stream, state, ")"); + else if (tok == "[") + pushContext(stream, state, "]"); + else if (state.context && state.context.type == tok) + popContext(state); + return style; + }, + + indent: function(state, textAfter) { + var cx = state.context; + if (!cx) return CodeMirror.Pass; + if (cx.align) return cx.col + (textAfter.charAt(0) == cx.type ? 0 : 1); + else return cx.indent + config.indentUnit; + } + }; +}); + +(function() { + "use strict"; + + // `identifier` + function hookIdentifier(stream) { + // MySQL/MariaDB identifiers + // ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html + var ch; + while ((ch = stream.next()) != null) { + if (ch == "`" && !stream.eat("`")) return "variable-2"; + } + return null; + } + + // variable token + function hookVar(stream) { + // variables + // @@prefix.varName @varName + // varName can be quoted with ` or ' or " + // ref: http://dev.mysql.com/doc/refman/5.5/en/user-variables.html + if (stream.eat("@")) { + stream.match(/^session\./); + stream.match(/^local\./); + stream.match(/^global\./); + } + + if (stream.eat("'")) { + stream.match(/^.*'/); + return "variable-2"; + } else if (stream.eat('"')) { + stream.match(/^.*"/); + return "variable-2"; + } else if (stream.eat("`")) { + stream.match(/^.*`/); + return "variable-2"; + } else if (stream.match(/^[0-9a-zA-Z$\.\_]+/)) { + return "variable-2"; + } + return null; + }; + + // short client keyword token + function hookClient(stream) { + // \N means NULL + // ref: http://dev.mysql.com/doc/refman/5.5/en/null-values.html + if (stream.eat("N")) { + return "atom"; + } + // \g, etc + // ref: http://dev.mysql.com/doc/refman/5.5/en/mysql-commands.html + return stream.match(/^[a-zA-Z.#!?]/) ? "variable-2" : null; + } + + // these keywords are used by all SQL dialects (however, a mode can still overwrite it) + var sqlKeywords = "alter and as asc between by count create delete desc distinct drop from having in insert into is join like not on or order select set table union update values where "; + + // turn a space-separated list into an array + function set(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + // A generic SQL Mode. It's not a standard, it just try to support what is generally supported + CodeMirror.defineMIME("text/x-sql", { + name: "sql", + keywords: set(sqlKeywords + "begin"), + builtin: set("bool boolean bit blob enum long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision real date datetime year unsigned signed decimal numeric"), + atoms: set("false true null unknown"), + operatorChars: /^[*+\-%<>!=]/, + dateSQL: set("date time timestamp"), + support: set("ODBCdotTable doubleQuote binaryNumber hexNumber") + }); + + CodeMirror.defineMIME("text/x-mysql", { + name: "sql", + client: set("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"), + keywords: set(sqlKeywords + "accessible action add after algorithm all analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general global grant grants group groupby_concat handler hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"), + builtin: set("bool boolean bit blob decimal double enum float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"), + atoms: set("false true null unknown"), + operatorChars: /^[*+\-%<>!=&|^]/, + dateSQL: set("date time timestamp"), + support: set("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber doubleQuote nCharCast charsetCast commentHash commentSpaceRequired"), + hooks: { + "@": hookVar, + "`": hookIdentifier, + "\\": hookClient + } + }); + + CodeMirror.defineMIME("text/x-mariadb", { + name: "sql", + client: set("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"), + keywords: set(sqlKeywords + "accessible action add after algorithm all always analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general generated global grant grants group groupby_concat handler hard hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password persistent phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot soft soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views virtual warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"), + builtin: set("bool boolean bit blob decimal double enum float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"), + atoms: set("false true null unknown"), + operatorChars: /^[*+\-%<>!=&|^]/, + dateSQL: set("date time timestamp"), + support: set("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber doubleQuote nCharCast charsetCast commentHash commentSpaceRequired"), + hooks: { + "@": hookVar, + "`": hookIdentifier, + "\\": hookClient + } + }); + + // the query language used by Apache Cassandra is called CQL, but this mime type + // is called Cassandra to avoid confusion with Contextual Query Language + CodeMirror.defineMIME("text/x-cassandra", { + name: "sql", + client: { }, + keywords: set("use select from using consistency where limit first reversed first and in insert into values using consistency ttl update set delete truncate begin batch apply create keyspace with columnfamily primary key index on drop alter type add any one quorum all local_quorum each_quorum"), + builtin: set("ascii bigint blob boolean counter decimal double float int text timestamp uuid varchar varint"), + atoms: set("false true"), + operatorChars: /^[<>=]/, + dateSQL: { }, + support: set("commentSlashSlash decimallessFloat"), + hooks: { } + }); + + // this is based on Peter Raganitsch's 'plsql' mode + CodeMirror.defineMIME("text/x-plsql", { + name: "sql", + client: set("appinfo arraysize autocommit autoprint autorecovery autotrace blockterminator break btitle cmdsep colsep compatibility compute concat copycommit copytypecheck define describe echo editfile embedded escape exec execute feedback flagger flush heading headsep instance linesize lno loboffset logsource long longchunksize markup native newpage numformat numwidth pagesize pause pno recsep recsepchar release repfooter repheader serveroutput shiftinout show showmode size spool sqlblanklines sqlcase sqlcode sqlcontinue sqlnumber sqlpluscompatibility sqlprefix sqlprompt sqlterminator suffix tab term termout time timing trimout trimspool ttitle underline verify version wrap"), + keywords: set("abort accept access add all alter and any array arraylen as asc assert assign at attributes audit authorization avg base_table begin between binary_integer body boolean by case cast char char_base check close cluster clusters colauth column comment commit compress connect connected constant constraint crash create current currval cursor data_base database date dba deallocate debugoff debugon decimal declare default definition delay delete desc digits dispose distinct do drop else elsif enable end entry escape exception exception_init exchange exclusive exists exit external fast fetch file for force form from function generic goto grant group having identified if immediate in increment index indexes indicator initial initrans insert interface intersect into is key level library like limited local lock log logging long loop master maxextents maxtrans member minextents minus mislabel mode modify multiset new next no noaudit nocompress nologging noparallel not nowait number_base object of off offline on online only open option or order out package parallel partition pctfree pctincrease pctused pls_integer positive positiven pragma primary prior private privileges procedure public raise range raw read rebuild record ref references refresh release rename replace resource restrict return returning reverse revoke rollback row rowid rowlabel rownum rows run savepoint schema segment select separate session set share snapshot some space split sql start statement storage subtype successful synonym tabauth table tables tablespace task terminate then to trigger truncate type union unique unlimited unrecoverable unusable update use using validate value values variable view views when whenever where while with work"), + functions: set("abs acos add_months ascii asin atan atan2 average bfilename ceil chartorowid chr concat convert cos cosh count decode deref dual dump dup_val_on_index empty error exp false floor found glb greatest hextoraw initcap instr instrb isopen last_day least lenght lenghtb ln lower lpad ltrim lub make_ref max min mod months_between new_time next_day nextval nls_charset_decl_len nls_charset_id nls_charset_name nls_initcap nls_lower nls_sort nls_upper nlssort no_data_found notfound null nvl others power rawtohex reftohex round rowcount rowidtochar rpad rtrim sign sin sinh soundex sqlcode sqlerrm sqrt stddev substr substrb sum sysdate tan tanh to_char to_date to_label to_multi_byte to_number to_single_byte translate true trunc uid upper user userenv variance vsize"), + builtin: set("bfile blob character clob dec float int integer mlslabel natural naturaln nchar nclob number numeric nvarchar2 real rowtype signtype smallint string varchar varchar2"), + operatorChars: /^[*+\-%<>!=~]/, + dateSQL: set("date time timestamp"), + support: set("doubleQuote nCharCast zerolessFloat binaryNumber hexNumber") + }); +}()); + +/* + How Properties of Mime Types are used by SQL Mode + ================================================= + + keywords: + A list of keywords you want to be highlighted. + functions: + A list of function names you want to be highlighted. + builtin: + A list of builtin types you want to be highlighted (if you want types to be of class "builtin" instead of "keyword"). + operatorChars: + All characters that must be handled as operators. + client: + Commands parsed and executed by the client (not the server). + support: + A list of supported syntaxes which are not common, but are supported by more than 1 DBMS. + * ODBCdotTable: .tableName + * zerolessFloat: .1 + * doubleQuote + * nCharCast: N'string' + * charsetCast: _utf8'string' + * commentHash: use # char for comments + * commentSlashSlash: use // for comments + * commentSpaceRequired: require a space after -- for comments + atoms: + Keywords that must be highlighted as atoms,. Some DBMS's support more atoms than others: + UNKNOWN, INFINITY, UNDERFLOW, NaN... + dateSQL: + Used for date/time SQL standard syntax, because not all DBMS's support same temporal types. +*/ diff --git a/phpMyAdmin/js/common.js b/phpMyAdmin/js/common.js index 4591ab8..468036d 100644 --- a/phpMyAdmin/js/common.js +++ b/phpMyAdmin/js/common.js @@ -1,12 +1,300 @@ -var querywindow="",query_to_load="";function setDb(a){if(a!=db){var b=db;db=a;if(window.frame_navigation.document.getElementById(db)==null)refreshNavigation();else{unmarkDbTable(b);markDbTable(db)}refreshQuerywindow()}}function setTable(a){if(a!=table){table=a;window.frame_navigation.document.getElementById(db+"."+table)==null&&table!=""&&refreshNavigation();refreshQuerywindow()}} -function refreshMain(a){a||(a=db?opendb_url:"main.php");goTo(a+"?server="+encodeURIComponent(server)+"&token="+encodeURIComponent(token)+"&db="+encodeURIComponent(db)+"&table="+encodeURIComponent(table)+"&lang="+encodeURIComponent(lang)+"&collation_connection="+encodeURIComponent(collation_connection),"main")} -function refreshNavigation(a){typeof a!=undefined&&a&&window.parent&&window.parent.frame_navigation?window.parent.frame_navigation.location.reload():goTo("navigation.php?server="+encodeURIComponent(server)+"&token="+encodeURIComponent(token)+"&db="+encodeURIComponent(db)+"&table="+encodeURIComponent(table)+"&lang="+encodeURIComponent(lang)+"&collation_connection="+encodeURIComponent(collation_connection))} -function unmarkDbTable(a,b){var c=window.frame_navigation.document.getElementById(a);c!=null&&$(c).parent().removeClass("marked");c=window.frame_navigation.document.getElementById(a+"."+b);c!=null&&$(c).parent().removeClass("marked")} -function markDbTable(a,b){var c=window.frame_navigation.document.getElementById(a);if(c!=null){$(c).parent().addClass("marked");c.focus();c.blur()}c=window.frame_navigation.document.getElementById(a+"."+b);if(c!=null){$(c).parent().addClass("marked");c.focus();c.blur()}window.frame_content.focus()} -function setAll(a,b,c,d,e,f){if(c!=server||a!=lang||b!=collation_connection){server=c;db=d;table=e;collation_connection=b;lang=a;token=f;refreshNavigation()}else if(d!=db||e!=table){a=db;b=table;db=d;table=e;if(window.frame_navigation.document.getElementById(db)==null&&window.frame_navigation.document.getElementById(db+"."+table)==null)refreshNavigation();else{unmarkDbTable(a,b);markDbTable(db,table)}refreshQuerywindow()}} -function reload_querywindow(a,b,c){if(!querywindow.closed&&querywindow.location)if(!querywindow.document.sqlform.LockFromUpdate||!querywindow.document.sqlform.LockFromUpdate.checked){querywindow.document.getElementById("hiddenqueryform").db.value=a;querywindow.document.getElementById("hiddenqueryform").table.value=b;if(c)querywindow.document.getElementById("hiddenqueryform").sql_query.value=c;querywindow.document.getElementById("hiddenqueryform").submit()}} -function focus_querywindow(a){if(!querywindow||querywindow.closed||!querywindow.location){query_to_load=a;open_querywindow();insertQuery(0)}else{if(querywindow.document.getElementById("hiddenqueryform").querydisplay_tab!="sql"){querywindow.document.getElementById("hiddenqueryform").querydisplay_tab.value="sql";querywindow.document.getElementById("hiddenqueryform").sql_query.value=a;querywindow.document.getElementById("hiddenqueryform").submit()}querywindow.focus()}return true} -function insertQuery(){if(query_to_load!=""&&querywindow.document&&querywindow.document.getElementById&&querywindow.document.getElementById("sqlquery")){querywindow.document.getElementById("sqlquery").value=query_to_load;query_to_load="";return true}return false} -function open_querywindow(a){a||(a="querywindow.php?"+common_query+"&db="+encodeURIComponent(db)+"&table="+encodeURIComponent(table));if(!querywindow.closed&&querywindow.location){goTo(a,"query");querywindow.focus()}else querywindow=window.open(a+"&init=1","","toolbar=0,location=0,directories=0,status=1,menubar=0,scrollbars=yes,resizable=yes,width="+querywindow_width+",height="+querywindow_height);if(!querywindow.opener)querywindow.opener=window.window;window.focus&&querywindow.focus();return true} -function refreshQuerywindow(a){if(!querywindow.closed&&querywindow.location)if(!querywindow.document.sqlform.LockFromUpdate||!querywindow.document.sqlform.LockFromUpdate.checked)open_querywindow(a)}function goTo(a,b){if(b=="main")b=window.frame_content;else if(b=="query")b=querywindow;else if(!b)b=window.frame_navigation;if(b){if(b.location.href==a)return true;else if(b.location.href==pma_absolute_uri+a)return true;if(safari_browser)b.location.href=a;else b.location.replace(a)}return true} -function openDb(a){setDb(a);setTable("");refreshMain(opendb_url);return true}function updateTableTitle(a,b){if(window.parent.frame_navigation.document&&window.parent.frame_navigation.document.getElementById(a)){var c=window.parent.frame_navigation.document,d=c.getElementById(a);d.title=window.parent.pma_text_default_tab+": "+b;d=c.getElementById("quick_"+a);d.title=window.parent.pma_text_left_default_tab+": "+b;return true}return false}; +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Functionality for communicating with the querywindow + */ +$(function () { + /** + * Event handler for click on the open query window link + * in the top menu of the navigation panel + */ + $('#pma_open_querywindow').click(function (event) { + event.preventDefault(); + PMA_querywindow.focus(); + }); +}); + +/** + * Holds common parameters such as server, db, table, etc + * + * The content for this is normally loaded from Header.class.php or + * Response.class.php and executed by ajax.js + */ +var PMA_commonParams = (function () { + /** + * @var hash params An associative array of key value pairs + * @access private + */ + var params = {}; + // The returned object is the public part of the module + return { + /** + * Saves all the key value pair that + * are provided in the input array + * + * @param hash obj The input array + * + * @return void + */ + setAll: function (obj) { + var reload = false; + var updateNavigation = false; + for (var i in obj) { + if (params[i] !== undefined && params[i] !== obj[i]) { + reload = true; + if (i == 'db' || i == 'table') { + updateNavigation = true; + } + } + params[i] = obj[i]; + } + if (updateNavigation) { + PMA_showCurrentNavigation(); + } + if (reload) { + PMA_querywindow.refresh(); + } + }, + /** + * Retrieves a value given its key + * Returns empty string for undefined values + * + * @param string name The key + * + * @return string + */ + get: function (name) { + return params[name] || ''; + }, + /** + * Saves a single key value pair + * + * @param string name The key + * @param string value The value + * + * @return self For chainability + */ + set: function (name, value) { + var updateNavigation = false; + if (params[name] !== undefined && params[name] !== value) { + PMA_querywindow.refresh(); + if (name == 'db' || name == 'table') { + updateNavigation = true; + } + } + params[name] = value; + if (updateNavigation) { + PMA_showCurrentNavigation(); + } + return this; + }, + /** + * Returns the url query string using the saved parameters + * + * @return string + */ + getUrlQuery: function () { + return $.sprintf( + '?%s&server=%s&db=%s&table=%s', + this.get('common_query'), + encodeURIComponent(this.get('server')), + encodeURIComponent(this.get('db')), + encodeURIComponent(this.get('table')) + ); + } + }; +})(); + +/** + * Holds common parameters such as server, db, table, etc + * + * The content for this is normally loaded from Header.class.php or + * Response.class.php and executed by ajax.js + */ +var PMA_commonActions = { + /** + * Saves the database name when it's changed + * and reloads the query window, if necessary + * + * @param string new_db The name of the new database + * + * @return void + */ + setDb: function (new_db) { + if (new_db != PMA_commonParams.get('db')) { + PMA_commonParams.setAll({'db': new_db, 'table': ''}); + } + }, + /** + * Opens a database in the main part of the page + * + * @param string new_db The name of the new database + * + * @return void + */ + openDb: function (new_db) { + PMA_commonParams + .set('db', new_db) + .set('table', ''); + PMA_querywindow.refresh(); + this.refreshMain( + PMA_commonParams.get('opendb_url') + ); + }, + /** + * Refreshes the main frame + * + * @param mixed url Undefined to refresh to the same page + * String to go to a different page, e.g: 'index.php' + * + * @return void + */ + refreshMain: function (url, callback) { + if (! url) { + url = $('#selflink a').attr('href'); + url = url.substring(0, url.indexOf('?')); + } + url += PMA_commonParams.getUrlQuery(); + $('', {href: url}) + .appendTo('body') + .click() + .remove(); + AJAX._callback = callback; + } +}; + +/** + * Common functions used for communicating with the querywindow + */ +var PMA_querywindow = (function ($, window) { + /** + * @var Object querywindow Reference to the window + * object of the querywindow + * @access private + */ + var querywindow = {}; + /** + * @var string queryToLoad Stores the SQL query that is to be displayed + * in the querywindow when it is ready + * @access private + */ + var queryToLoad = ''; + // The returned object is the public part of the module + return { + /** + * Opens the query window + * + * @param mixed url Undefined to open the default page + * String to go to a different + * + * @return void + */ + open: function (url, sql_query) { + if (! url) { + url = 'querywindow.php' + PMA_commonParams.getUrlQuery(); + } + if (sql_query) { + url += '&sql_query=' + encodeURIComponent(sql_query); + } + + if (! querywindow.closed && querywindow.location) { + var href = querywindow.location.href; + if (href != url && + href != PMA_commonParams.get('pma_absolute_uri') + url + ) { + if (PMA_commonParams.get('safari_browser')) { + querywindow.location.href = targeturl; + } else { + querywindow.location.replace(targeturl); + } + querywindow.focus(); + } + } else { + querywindow = window.open( + url + '&init=1', + '', + 'toolbar=0,location=0,directories=0,status=1,' + + 'menubar=0,scrollbars=yes,resizable=yes,' + + 'width=' + PMA_commonParams.get('querywindow_width') + ',' + + 'height=' + PMA_commonParams.get('querywindow_height') + ); + } + if (! querywindow.opener) { + querywindow.opener = window.window; + } + if (window.focus) { + querywindow.focus(); + } + }, + /** + * Opens, if necessary, focuses the query window + * and displays an SQL query. + * + * @param string sql_query The SQL query to display in + * the query window + * + * @return void + */ + focus: function (sql_query) { + if (! querywindow || querywindow.closed || ! querywindow.location) { + // we need first to open the window and cannot pass the query with it + // as we dont know if the query exceeds max url length + queryToLoad = sql_query; + this.open(false, sql_query); + } else { + //var querywindow = querywindow; + var hiddenqueryform = querywindow + .document + .getElementById('hiddenqueryform'); + if (hiddenqueryform.querydisplay_tab != 'sql') { + hiddenqueryform.querydisplay_tab.value = "sql"; + hiddenqueryform.sql_query.value = sql_query; + $(hiddenqueryform).addClass('disableAjax'); + hiddenqueryform.submit(); + querywindow.focus(); + } else { + querywindow.focus(); + } + } + }, + /** + * Refreshes the query window given a url + * + * @param string url Where to go to + * + * @return void + */ + refresh: function (url) { + if (! querywindow.closed && querywindow.location) { + var $form = $(querywindow.document).find('#sqlqueryform'); + if ($form.find('#checkbox_lock:checked').length === 0) { + PMA_querywindow.open(url); + } + } + }, + /** + * Reloads the query window given the details + * of a db, a table and an sql_query + * + * @param string db The name of the database + * @param string table The name of the table + * @param string sql_query The SQL query to be displayed + * + * @return void + */ + reload: function (db, table, sql_query) { + if (! querywindow.closed && querywindow.location) { + var $form = $(querywindow.document).find('#sqlqueryform'); + if ($form.find('#checkbox_lock:checked').length === 0) { + var $hiddenform = $(querywindow.document) + .find('#hiddenqueryform'); + $hiddenform.find('input[name=db]').val(db); + $hiddenform.find('input[name=table]').val(table); + if (sql_query) { + $hiddenform.find('input[name=sql_query]').val(sql_query); + } + $hiddenform.addClass('disableAjax').submit(); + } + } + } + }; +})(jQuery, window); diff --git a/phpMyAdmin/js/config.js b/phpMyAdmin/js/config.js index db62bff..9113c85 100644 --- a/phpMyAdmin/js/config.js +++ b/phpMyAdmin/js/config.js @@ -1,24 +1,798 @@ -var defaultValues={},PMA_messages={};$(".autosubmit").live("change",function(a){a.target.form.submit()});function getFieldType(a){a=$(a);var b=a.prop("tagName");if(b=="INPUT")return a.attr("type");else if(b=="SELECT")return"select";else if(b=="TEXTAREA")return"text";return""} -function setFieldValue(a,b,d){a=$(a);switch(b){case "text":a.attr("value",d!=undefined?d:a.attr("defaultValue"));break;case "checkbox":a.attr("checked",d!=undefined?d:a.attr("defaultChecked"));break;case "select":b=a.prop("options");var c,e=b.length;if(d==undefined)for(c=0;c');c.find("table").before(f)}else{f=$('
    ');c.closest("td").append(f)}c="";e=0;for(var g=d.length;e"+d[e]+"";f.html(c)}else f!== -null&&f.remove()}}function validate_fieldset(a,b,d){a=$(a);if(a.length&&typeof validators._fieldset[a.attr("id")]!="undefined"){a=validators._fieldset[a.attr("id")].apply(a[0],[b]);for(var c in a){if(typeof d[c]=="undefined")d[c]=[];if(typeof a[c]=="string")a[c]=[a[c]];$.merge(d[c],a[c])}}} -function validate_field(a,b,d){a=$(a);var c=a.attr("id");d[c]=[];for(var e=getFieldValidators(c,b),f=0;f for marking + var fieldMarker = (field.attr('type') == 'checkbox') ? field.parent() : field; + fieldMarker[errors.length ? 'addClass' : 'removeClass']('field-error'); + } + + if (errors.length) { + // if error container doesn't exist, create it + if (errorCnt.length === 0) { + if (isFieldset) { + errorCnt = $('
    '); + field.find('table').before(errorCnt); + } else { + errorCnt = $('
    '); + field.closest('td').append(errorCnt); + } + } + + var html = ''; + for (var i = 0, imax = errors.length; i < imax; i++) { + html += '
    ' + errors[i] + '
    '; + } + errorCnt.html(html); + } else if (errorCnt !== null) { + // remove useless error container + errorCnt.remove(); + } + } +} + +/** + * Validates fieldset and puts errors in 'errors' object + * + * @param {Element} fieldset + * @param {boolean} isKeyUp + * @param {Object} errors + */ +function validate_fieldset(fieldset, isKeyUp, errors) +{ + fieldset = $(fieldset); + if (fieldset.length && typeof validators._fieldset[fieldset.attr('id')] != 'undefined') { + var fieldset_errors = validators._fieldset[fieldset.attr('id')].apply(fieldset[0], [isKeyUp]); + for (var field_id in fieldset_errors) { + if (typeof errors[field_id] == 'undefined') { + errors[field_id] = []; + } + if (typeof fieldset_errors[field_id] == 'string') { + fieldset_errors[field_id] = [fieldset_errors[field_id]]; + } + $.merge(errors[field_id], fieldset_errors[field_id]); + } + } +} + +/** + * Validates form field and puts errors in 'errors' object + * + * @param {Element} field + * @param {boolean} isKeyUp + * @param {Object} errors + */ +function validate_field(field, isKeyUp, errors) +{ + var args, result; + field = $(field); + var field_id = field.attr('id'); + errors[field_id] = []; + var functions = getFieldValidators(field_id, isKeyUp); + for (var i = 0; i < functions.length; i++) { + if (typeof functions[i][1] !== 'undefined' && functions[i][1] !== null) { + args = functions[i][1].slice(0); + } else { + args = []; + } + args.unshift(isKeyUp); + result = functions[i][0].apply(field[0], args); + if (result !== true) { + if (typeof result == 'string') { + result = [result]; + } + $.merge(errors[field_id], result); + } + } +} + +/** + * Validates form field and parent fieldset + * + * @param {Element} field + * @param {boolean} isKeyUp + */ +function validate_field_and_fieldset(field, isKeyUp) +{ + field = $(field); + var errors = {}; + validate_field(field, isKeyUp, errors); + validate_fieldset(field.closest('fieldset'), isKeyUp, errors); + displayErrors(errors); +} + +/** + * Marks field depending on its value (system default or custom) + * + * @param {Element} field + */ +function markField(field) +{ + field = $(field); + var type = getFieldType(field); + var isDefault = checkFieldDefault(field, type); + + // checkboxes uses parent for marking + var fieldMarker = (type == 'checkbox') ? field.parent() : field; + setRestoreDefaultBtn(field, !isDefault); + fieldMarker[isDefault ? 'removeClass' : 'addClass']('custom'); +} + +/** + * Enables or disables the "restore default value" button + * + * @param {Element} field + * @param {boolean} display + */ +function setRestoreDefaultBtn(field, display) +{ + var el = $(field).closest('td').find('.restore-default img'); + el[display ? 'show' : 'hide'](); +} + +AJAX.registerOnload('config.js', function () { + // register validators and mark custom values + var elements = $('input[id], select[id], textarea[id]'); + $('input[id], select[id], textarea[id]').each(function () { + markField(this); + var el = $(this); + el.bind('change', function () { + validate_field_and_fieldset(this, false); + markField(this); + }); + var tagName = el.attr('tagName'); + // text fields can be validated after each change + if (tagName == 'INPUT' && el.attr('type') == 'text') { + el.keyup(function () { + validate_field_and_fieldset(el, true); + markField(el); + }); + } + // disable textarea spellcheck + if (tagName == 'TEXTAREA') { + el.attr('spellcheck', false); + } + }); + + // check whether we've refreshed a page and browser remembered modified + // form values + var check_page_refresh = $('#check_page_refresh'); + if (check_page_refresh.length === 0 || check_page_refresh.val() == '1') { + // run all field validators + var errors = {}; + for (var i = 0; i < elements.length; i++) { + validate_field(elements[i], false, errors); + } + // run all fieldset validators + $('fieldset').each(function () { + validate_fieldset(this, false, errors); + }); + + displayErrors(errors); + } else if (check_page_refresh) { + check_page_refresh.val('1'); + } +}); + +// +// END: Form validation and field operations +// ------------------------------------------------------------------ + +// ------------------------------------------------------------------ +// Tabbed forms +// + +/** + * Sets active tab + * + * @param {String} tab_id + */ +function setTab(tab_id) +{ + $('ul.tabs li').removeClass('active').find('a[href=#' + tab_id + ']').parent().addClass('active'); + $('div.tabs_contents fieldset').hide().filter('#' + tab_id).show(); + location.hash = 'tab_' + tab_id; + $('form.config-form input[name=tab_hash]').val(location.hash); +} + +AJAX.registerOnload('config.js', function () { + var tabs = $('ul.tabs'); + if (!tabs.length) { + return; + } + // add tabs events and activate one tab (the first one or indicated by location hash) + tabs.find('a') + .click(function (e) { + e.preventDefault(); + setTab($(this).attr('href').substr(1)); + }) + .filter(':first') + .parent() + .addClass('active'); + $('div.tabs_contents fieldset').hide().filter(':first').show(); + + // tab links handling, check each 200ms + // (works with history in FF, further browser support here would be an overkill) + var prev_hash; + var tab_check_fnc = function () { + if (location.hash != prev_hash) { + prev_hash = location.hash; + if (location.hash.match(/^#tab_.+/) && $('#' + location.hash.substr(5)).length) { + setTab(location.hash.substr(5)); + } + } + }; + tab_check_fnc(); + setInterval(tab_check_fnc, 200); +}); + +// +// END: Tabbed forms +// ------------------------------------------------------------------ + +// ------------------------------------------------------------------ +// Form reset buttons +// + +AJAX.registerOnload('config.js', function () { + $('input[type=button][name=submit_reset]').click(function () { + var fields = $(this).closest('fieldset').find('input, select, textarea'); + for (var i = 0, imax = fields.length; i < imax; i++) { + setFieldValue(fields[i], getFieldType(fields[i])); + } + }); +}); + +// +// END: Form reset buttons +// ------------------------------------------------------------------ + +// ------------------------------------------------------------------ +// "Restore default" and "set value" buttons +// + +/** + * Restores field's default value + * + * @param {String} field_id + */ +function restoreField(field_id) +{ + var field = $('#' + field_id); + if (field.length === 0 || defaultValues[field_id] === undefined) { + return; + } + setFieldValue(field, getFieldType(field), defaultValues[field_id]); +} + +AJAX.registerOnload('config.js', function () { + $('div.tabs_contents') + .delegate('.restore-default, .set-value', 'mouseenter', function () { + $(this).css('opacity', 1); + }) + .delegate('.restore-default, .set-value', 'mouseleave', function () { + $(this).css('opacity', 0.25); + }) + .delegate('.restore-default, .set-value', 'click', function (e) { + e.preventDefault(); + var href = $(this).attr('href'); + var field_sel; + if ($(this).hasClass('restore-default')) { + field_sel = href; + restoreField(field_sel.substr(1)); + } else { + field_sel = href.match(/^[^=]+/)[0]; + var value = href.match(/\=(.+)$/)[1]; + setFieldValue($(field_sel), 'text', value); + } + $(field_sel).trigger('change'); + }) + .find('.restore-default, .set-value') + // inline-block for IE so opacity inheritance works + .css({display: 'inline-block', opacity: 0.25}); +}); + +// +// END: "Restore default" and "set value" buttons +// ------------------------------------------------------------------ + +// ------------------------------------------------------------------ +// User preferences import/export +// + +AJAX.registerOnload('config.js', function () { + offerPrefsAutoimport(); + var radios = $('#import_local_storage, #export_local_storage'); + if (!radios.length) { + return; + } + + // enable JavaScript dependent fields + radios + .prop('disabled', false) + .add('#export_text_file, #import_text_file') + .click(function () { + var enable_id = $(this).attr('id'); + var disable_id; + if (enable_id.match(/local_storage$/)) { + disable_id = enable_id.replace(/local_storage$/, 'text_file'); + } else { + disable_id = enable_id.replace(/text_file$/, 'local_storage'); + } + $('#opts_' + disable_id).addClass('disabled').find('input').prop('disabled', true); + $('#opts_' + enable_id).removeClass('disabled').find('input').prop('disabled', false); + }); + + // detect localStorage state + var ls_supported = window.localStorage || false; + var ls_exists = ls_supported ? (window.localStorage.config || false) : false; + $('div.localStorage-' + (ls_supported ? 'un' : '') + 'supported').hide(); + $('div.localStorage-' + (ls_exists ? 'empty' : 'exists')).hide(); + if (ls_exists) { + updatePrefsDate(); + } + $('form.prefs-form').change(function () { + var form = $(this); + var disabled = false; + if (!ls_supported) { + disabled = form.find('input[type=radio][value$=local_storage]').prop('checked'); + } else if (!ls_exists && form.attr('name') == 'prefs_import' && + $('#import_local_storage')[0].checked + ) { + disabled = true; + } + form.find('input[type=submit]').prop('disabled', disabled); + }).submit(function (e) { + var form = $(this); + if (form.attr('name') == 'prefs_export' && $('#export_local_storage')[0].checked) { + e.preventDefault(); + // use AJAX to read JSON settings and save them + savePrefsToLocalStorage(form); + } else if (form.attr('name') == 'prefs_import' && $('#import_local_storage')[0].checked) { + // set 'json' input and submit form + form.find('input[name=json]').val(window.localStorage['config']); + } + }); + + $('div.click-hide-message').live('click', function () { + $(this) + .hide() + .parent('.group') + .css('height', '') + .next('form') + .show(); + }); +}); + +/** + * Saves user preferences to localStorage + * + * @param {Element} form + */ +function savePrefsToLocalStorage(form) +{ + form = $(form); + var submit = form.find('input[type=submit]'); + submit.prop('disabled', true); + $.ajax({ + url: 'prefs_manage.php', + cache: false, + type: 'POST', + data: { + ajax_request: true, + server: form.find('input[name=server]').val(), + token: form.find('input[name=token]').val(), + submit_get_json: true + }, + success: function (data) { + if (data.success === true) { + window.localStorage['config'] = data.prefs; + window.localStorage['config_mtime'] = data.mtime; + window.localStorage['config_mtime_local'] = (new Date()).toUTCString(); + updatePrefsDate(); + $('div.localStorage-empty').hide(); + $('div.localStorage-exists').show(); + var group = form.parent('.group'); + group.css('height', group.height() + 'px'); + form.hide('fast'); + form.prev('.click-hide-message').show('fast'); + } else { + PMA_ajaxShowMessage(data.error); + } + }, + complete: function () { + submit.prop('disabled', false); + } + }); +} + +/** + * Updates preferences timestamp in Import form + */ +function updatePrefsDate() +{ + var d = new Date(window.localStorage['config_mtime_local']); + var msg = PMA_messages.strSavedOn.replace( + '@DATE@', + PMA_formatDateTime(d) + ); + $('#opts_import_local_storage div.localStorage-exists').html(msg); +} + +/** + * Prepares message which informs that localStorage preferences are available and can be imported + */ +function offerPrefsAutoimport() +{ + var has_config = (window.localStorage || false) && (window.localStorage['config'] || false); + var cnt = $('#prefs_autoload'); + if (!cnt.length || !has_config) { + return; + } + cnt.find('a').click(function (e) { + e.preventDefault(); + var a = $(this); + if (a.attr('href') == '#no') { + cnt.remove(); + $.post('index.php', { + token: cnt.find('input[name=token]').val(), + prefs_autoload: 'hide' + }); + return; + } + cnt.find('input[name=json]').val(window.localStorage['config']); + cnt.find('form').submit(); + }); + cnt.show(); +} + +// +// END: User preferences import/export +// ------------------------------------------------------------------ diff --git a/phpMyAdmin/js/cross_framing_protection.js b/phpMyAdmin/js/cross_framing_protection.js index 2b6dcc8..5952ab7 100644 --- a/phpMyAdmin/js/cross_framing_protection.js +++ b/phpMyAdmin/js/cross_framing_protection.js @@ -1 +1,9 @@ -try{var topdomain=top.document.domain;if(topdomain!=self.document.domain){alert("Redirecting...");top.location.replace(self.document.URL.substring(0,self.document.URL.lastIndexOf("/")+1))}}catch(e$$5){alert("Redirecting... (error: "+e$$5);top.location.replace(self.document.URL.substring(0,self.document.URL.lastIndexOf("/")+1))}; +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Conditionally included if framing is not allowed + */ +if (self == top) { + document.documentElement.style.display = 'block'; +} else { + top.location = self.location; +} diff --git a/phpMyAdmin/js/date.js b/phpMyAdmin/js/date.js deleted file mode 100644 index adb29dd..0000000 --- a/phpMyAdmin/js/date.js +++ /dev/null @@ -1,9 +0,0 @@ -var MONTH_NAMES=["January","February","March","April","May","June","July","August","September","October","November","December","Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],DAY_NAMES=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sun","Mon","Tue","Wed","Thu","Fri","Sat"];function LZ(c){return(c<0||c>9?"":"0")+c}function isDate(c,e){if(getDateFromFormat(c,e)==0)return false;return true} -function compareDates(c,e,b,i){c=getDateFromFormat(c,e);b=getDateFromFormat(b,i);if(c==0||b==0)return-1;else if(c>b)return 1;return 0} -function formatDate(c,e){e+="";var b="",i=0,f="",a="";f=c.getYear()+"";a=c.getMonth()+1;var l=c.getDate(),m=c.getDay(),h=c.getHours(),k=c.getMinutes(),j=c.getSeconds(),d={};if(f.length<4)f=""+(f-0+1900);d.y=""+f;d.yyyy=f;d.yy=f.substring(2,4);d.M=a;d.MM=LZ(a);d.MMM=MONTH_NAMES[a-1];d.NNN=MONTH_NAMES[a+11];d.d=l;d.dd=LZ(l);d.E=DAY_NAMES[m+7];d.EE=DAY_NAMES[m];d.H=h;d.HH=LZ(h);d.h=h==0?12:h>12?h-12:h;d.hh=LZ(d.h);d.K=h>11?h-12:h;d.k=h+1;d.KK=LZ(d.K);d.kk=LZ(d.k);d.a=h>11?"PM":"AM";d.m=k;d.mm=LZ(k); -d.s=j;for(d.ss=LZ(j);i=b;i--){var f=c.substring(e,e+i);if(f.length70?1900+(k-0):2E3+(k-0)}else if(a=="MMM"||a=="NNN"){for(f=j=0;f11){j=f+1;if(j>12)j-=12;b+=p.length;break}}if(j<1||j>12)return 0}else if(a=="EE"||a=="E")for(f=0;f12)return 0;b+=j.length}else if(a=="dd"||a=="d"){d=_getInt(c,b,a.length,2);if(d==null||d<1||d>31)return 0;b+=d.length}else if(a== -"hh"||a=="h"){g=_getInt(c,b,a.length,2);if(g==null||g<1||g>12)return 0;b+=g.length}else if(a=="HH"||a=="H"){g=_getInt(c,b,a.length,2);if(g==null||g<0||g>23)return 0;b+=g.length}else if(a=="KK"||a=="K"){g=_getInt(c,b,a.length,2);if(g==null||g<0||g>11)return 0;b+=g.length}else if(a=="kk"||a=="k"){g=_getInt(c,b,a.length,2);if(g==null||g<1||g>24)return 0;b+=g.length;g--}else if(a=="mm"||a=="m"){n=_getInt(c,b,a.length,2);if(n==null||n<0||n>59)return 0;b+=n.length}else if(a=="ss"||a=="s"){h=_getInt(c,b, -a.length,2);if(h==null||h<0||h>59)return 0;b+=h.length}else if(a=="a"){if(c.substring(b,b+2).toLowerCase()=="am")o="AM";else if(c.substring(b,b+2).toLowerCase()=="pm")o="PM";else return 0;b+=2}else if(c.substring(b,b+a.length)!=a)return 0;else b+=a.length}if(b!=c.length)return 0;if(j==2)if(k%4==0&&k%100!=0||k%400==0){if(d>29)return 0}else if(d>28)return 0;if(j==4||j==6||j==9||j==11)if(d>30)return 0;if(g<12&&o=="PM")g=g-0+12;else if(g>11&&o=="AM")g-=12;return(new Date(k,j-1,d,g,n,h)).getTime()} -function parseDate(c){var e=arguments.length==2?arguments[1]:false;generalFormats=["y-M-d","MMM d, y","MMM d,y","y-MMM-d","d-MMM-y","MMM d"];monthFirst=["M/d/y","M-d-y","M.d.y","MMM-d","M/d","M-d"];dateFirst=["d/M/y","d-M-y","d.M.y","d-MMM","d/M","d-M"];e=["generalFormats",e?"dateFirst":"monthFirst",e?"monthFirst":"dateFirst"];for(var b=null,i=0;i"+PMA_messages.strReloadDatabase+"?").dialog({buttons:d})}else PMA_ajaxShowMessage(c.error,false)})})});$("#copy_db_form.ajax").live("submit",function(a){a.preventDefault();PMA_ajaxShowMessage(PMA_messages.strCopyingDatabase, -false);a=$(this);PMA_prepareForAjaxRequest(a);$.get(a.attr("action"),a.serialize(),function(b){$(".success").fadeOut();$(".error").fadeOut();if(b.success==true){PMA_ajaxShowMessage(b.message);if($("#checkbox_switch").is(":checked")){window.parent.db=b.newname;window.parent.refreshMain();window.parent.refreshNavigation()}else window.parent.refreshNavigation(true)}else PMA_ajaxShowMessage(b.error,false)})});$("#change_db_charset_form.ajax").live("submit",function(a){a.preventDefault();a=$(this);PMA_prepareForAjaxRequest(a); -PMA_ajaxShowMessage(PMA_messages.strChangingCharset);$.get(a.attr("action"),a.serialize()+"&submitcollation="+a.find("input[name=submitcollation]").attr("value"),function(b){b.success==true?PMA_ajaxShowMessage(b.message):PMA_ajaxShowMessage(b.error,false)})})},"top.frame_content"); +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * @fileoverview function used in server privilege pages + * @name Database Operations + * + * @requires jQuery + * @requires jQueryUI + * @requires js/functions.js + * + */ + +/** + * Ajax event handlers here for db_operations.php + * + * Actions Ajaxified here: + * Rename Database + * Copy Database + * Change charset + */ + +/** + * Unbind all event handlers before tearing down a page + */ +AJAX.registerTeardown('db_operations.js', function () { + $("#rename_db_form.ajax").die('submit'); + $("#copy_db_form.ajax").die('submit'); + $("#change_db_charset_form.ajax").die('submit'); +}); + +AJAX.registerOnload('db_operations.js', function () { + + /** + * Ajax event handlers for 'Rename Database' + */ + $("#rename_db_form.ajax").live('submit', function (event) { + event.preventDefault(); + + var $form = $(this); + + var question = escapeHtml('CREATE DATABASE ' + $('#new_db_name').val() + ' / DROP DATABASE ' + PMA_commonParams.get('db')); + + PMA_prepareForAjaxRequest($form); + + $form.PMA_confirm(question, $form.attr('action'), function (url) { + PMA_ajaxShowMessage(PMA_messages.strRenamingDatabases, false); + $.get(url, $("#rename_db_form").serialize() + '&is_js_confirmed=1', function (data) { + if (data.success === true) { + PMA_ajaxShowMessage(data.message); + PMA_commonParams.set('db', data.newname); + + PMA_reloadNavigation(function () { + $('#pma_navigation_tree') + .find("a:not('.expander')") + .each(function (index) { + var $thisAnchor = $(this); + if ($thisAnchor.text() == data.newname) { + // simulate a click on the new db name + // in navigation + $thisAnchor.trigger('click'); + } + }); + }); + } else { + PMA_ajaxShowMessage(data.error, false); + } + }); // end $.get() + }); + }); // end Rename Database + + /** + * Ajax Event Handler for 'Copy Database' + */ + $("#copy_db_form.ajax").live('submit', function (event) { + event.preventDefault(); + PMA_ajaxShowMessage(PMA_messages.strCopyingDatabase, false); + var $form = $(this); + PMA_prepareForAjaxRequest($form); + $.get($form.attr('action'), $form.serialize(), function (data) { + // use messages that stay on screen + $('div.success, div.error').fadeOut(); + if (data.success === true) { + if ($("#checkbox_switch").is(":checked")) { + PMA_commonParams.set('db', data.newname); + PMA_commonActions.refreshMain(false, function () { + PMA_ajaxShowMessage(data.message); + }); + } else { + PMA_commonParams.set('db', data.db); + PMA_ajaxShowMessage(data.message); + } + PMA_reloadNavigation(); + } else { + PMA_ajaxShowMessage(data.error, false); + } + }); // end $.get + }); // end copy database + + /** + * Ajax Event handler for 'Change Charset' of the database + */ + $("#change_db_charset_form.ajax").live('submit', function (event) { + event.preventDefault(); + var $form = $(this); + PMA_prepareForAjaxRequest($form); + PMA_ajaxShowMessage(PMA_messages.strChangingCharset); + $.get($form.attr('action'), $form.serialize() + "&submitcollation=1", function (data) { + if (data.success === true) { + PMA_ajaxShowMessage(data.message); + } else { + PMA_ajaxShowMessage(data.error, false); + } + }); // end $.get() + }); // end change charset +}); diff --git a/phpMyAdmin/js/db_search.js b/phpMyAdmin/js/db_search.js index 4294a40..6518aa0 100644 --- a/phpMyAdmin/js/db_search.js +++ b/phpMyAdmin/js/db_search.js @@ -1,7 +1,228 @@ -function loadResult(c,a,d,b){$(document).ready(function(){if(b){var e=PMA_ajaxShowMessage();$("#sqlqueryform").hide();$("#togglequerybox").hide();$("#table-info").show();$("#table-link").attr({href:"sql.php?"+d}).text(a);var f=c+" #sqlqueryresults";$("#browse-results").load(f,null,function(){$("html, body").animate({scrollTop:$("#browse-results").offset().top},1E3);PMA_ajaxRemoveMessage(e);window.parent.table=$("#table-link").text().trim();PMA_makegrid($("#table_results")[0],true,true,true,true)}).show()}else event.preventDefault()})} -function deleteResult(c,a,d){$(document).ready(function(){$("#table-info").hide();$("#browse-results").hide();$("#sqlqueryform").hide();$("#togglequerybox").hide();if(confirm(a))if(d){var b=PMA_ajaxShowMessage(PMA_messages.strDeleting,false);$("#sqlqueryform").html("");var e=c+" #result_query, #sqlqueryform";$("#browse-results").load(e,function(){document.getElementById("buttonGo").click();$("#togglequerybox").html(PMA_messages.strHideQueryBox);PMA_ajaxRemoveMessage(b);$("#browse-results").show(); -$("#sqlqueryform").show();$("#togglequerybox").show()})}else event.preventDefault()})} -$(document).ready(function(){var c=PMA_getImage("s_tbl.png","",{id:"table-image"}).toString();$("#table-info").prepend(c).hide();$("#buttonGo").click(function(){$("#table-info").hide();$("#browse-results").hide();$("#sqlqueryform").hide();$("#togglequerybox").hide()});$('
    ').insertAfter("#searchresults").hide();$('
    ').insertAfter("#togglesearchresultsdiv").show();$("#togglesearchresultlink").html(PMA_messages.strHideSearchResults).bind("click", -function(){var a=$(this);$("#searchresults").slideToggle();a.text()==PMA_messages.strHideSearchResults?a.text(PMA_messages.strShowSearchResults):a.text(PMA_messages.strHideSearchResults);return false});$('
    ').insertAfter("#db_search_form").hide();$("#togglequerybox").hide();$("#togglequerybox").bind("click",function(){var a=$(this);$("#sqlqueryform").slideToggle("medium");a.text()==PMA_messages.strHideQueryBox?a.text(PMA_messages.strShowQueryBox): -a.text(PMA_messages.strHideQueryBox);return false});$("#togglesearchformlink").html(PMA_messages.strShowSearchCriteria).bind("click",function(){var a=$(this);$("#db_search_form").slideToggle();a.text()==PMA_messages.strHideSearchCriteria?a.text(PMA_messages.strShowSearchCriteria):a.text(PMA_messages.strHideSearchCriteria);return false});$("#db_search_form.ajax").live("submit",function(a){a.preventDefault();var d=PMA_ajaxShowMessage(PMA_messages.strSearching,false);$form=$(this);PMA_prepareForAjaxRequest($form); -a=$form.serialize()+"&submit_search="+$("#buttonGo").val();$.post($form.attr("action"),a,function(b){if(typeof b=="string"){$("#searchresults").html(b);$("#togglesearchresultlink").text(PMA_messages.strHideSearchResults);$("#togglesearchresultsdiv").show();$("#searchresults").show();$("#db_search_form").slideToggle().hide();$("#togglesearchformlink").text(PMA_messages.strShowSearchCriteria);$("#togglesearchformdiv").show()}else $("#sqlqueryresults").html(b.message);PMA_ajaxRemoveMessage(d)})})},"top.frame_content"); +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * JavaScript functions used on Database Search page + * + * @requires jQuery + * @requires js/functions.js + * + * @package PhpMyAdmin + */ + +/** + * AJAX script for the Database Search page. + * + * Actions ajaxified here: + * Retrieve result of SQL query + */ + +/** + * Unbind all event handlers before tearing down a page + */ +AJAX.registerTeardown('db_search.js', function () { + $('#buttonGo').unbind('click'); + $('#togglesearchresultlink').unbind('click'); + $("#togglequerybox").unbind('click'); + $('#togglesearchformlink').unbind('click'); + $("#db_search_form.ajax").die('submit'); +}); + +/** + * Loads the database search results + * + * @param result_path Url of the page to load + * @param table_name Name of table to browse + * + * @return nothing + */ +function loadResult(result_path, table_name, link) +{ + $(function () { + /** Hides the results shown by the delete criteria */ + var $msg = PMA_ajaxShowMessage(PMA_messages.strBrowsing, false); + $('#sqlqueryform').hide(); + $('#togglequerybox').hide(); + /** Load the browse results to the page */ + $("#table-info").show(); + $('#table-link').attr({"href" : 'sql.php?' + link }).text(table_name); + var url = result_path + " #sqlqueryresults"; + $('#browse-results').load(url, null, function () { + $('html, body') + .animate({ + scrollTop: $("#browse-results").offset().top + }, 1000); + PMA_ajaxRemoveMessage($msg); + PMA_makegrid($('#table_results')[0], true, true, true, true); + }).show(); + }); +} + +/** + * Delete the selected search results + * + * @param result_path Url of the page to load + * @param msg Text for the confirmation dialog + * + * @return nothing + */ +function deleteResult(result_path, msg) +{ + $(function () { + /** Hides the results shown by the browse criteria */ + $("#table-info").hide(); + $('#browse-results').hide(); + $('#sqlqueryform').hide(); + $('#togglequerybox').hide(); + /** Conformation message for deletion */ + if (confirm(msg)) { + var $msg = PMA_ajaxShowMessage(PMA_messages.strDeleting, false); + /** Load the deleted option to the page*/ + $('#sqlqueryform').html(''); + var url = result_path + " #result_query, #sqlqueryform"; + $('#browse-results').load(url, function () { + /** Refresh the search results after the deletion */ + document.getElementById('buttonGo').click(); + $('#togglequerybox').html(PMA_messages.strHideQueryBox); + /** Show the results of the deletion option */ + $('#browse-results').show(); + $('#sqlqueryform').show(); + $('#togglequerybox').show(); + $('html, body') + .animate({ + scrollTop: $("#browse-results").offset().top + }, 1000); + PMA_ajaxRemoveMessage($msg); + }); + } + }); +} + +AJAX.registerOnload('db_search.js', function () { + /** Hide the table link in the initial search result */ + var icon = PMA_getImage('s_tbl.png', '', {'id': 'table-image'}).toString(); + $("#table-info").prepend(icon).hide(); + + /** Hide the browse and deleted results in the new search criteria */ + $('#buttonGo').click(function () { + $("#table-info").hide(); + $('#browse-results').hide(); + $('#sqlqueryform').hide(); + $('#togglequerybox').hide(); + }); + /** + * Prepare a div containing a link for toggle the search results + */ + $('
    ') + .insertAfter('#searchresults') + /** don't show it until we have results on-screen */ + .hide(); + + $('
    ').insertAfter("#togglesearchresultsdiv").show(); + /** + * Changing the displayed text according to + * the hide/show criteria in search result forms + */ + $('#togglesearchresultlink') + .html(PMA_messages.strHideSearchResults) + .bind('click', function () { + var $link = $(this); + $('#searchresults').slideToggle(); + if ($link.text() == PMA_messages.strHideSearchResults) { + $link.text(PMA_messages.strShowSearchResults); + } else { + $link.text(PMA_messages.strHideSearchResults); + } + /** avoid default click action */ + return false; + }); + + /** + * Prepare a div containing a link for toggle the search form, + * otherwise it's incorrectly displayed after a couple of clicks + */ + $('
    ') + .insertAfter('#db_search_form') + .hide(); // don't show it until we have results on-screen + + /** + * Changing the displayed text according to + * the hide/show criteria in search form + */ + $("#togglequerybox") + .hide() + .bind('click', function () { + var $link = $(this); + $('#sqlqueryform').slideToggle("medium"); + if ($link.text() == PMA_messages.strHideQueryBox) { + $link.text(PMA_messages.strShowQueryBox); + } else { + $link.text(PMA_messages.strHideQueryBox); + } + /** avoid default click action */ + return false; + }); + + /** don't show it until we have results on-screen */ + + /** + * Changing the displayed text according to + * the hide/show criteria in search criteria form + */ + $('#togglesearchformlink') + .html(PMA_messages.strShowSearchCriteria) + .bind('click', function () { + var $link = $(this); + $('#db_search_form').slideToggle(); + if ($link.text() == PMA_messages.strHideSearchCriteria) { + $link.text(PMA_messages.strShowSearchCriteria); + } else { + $link.text(PMA_messages.strHideSearchCriteria); + } + /** avoid default click action */ + return false; + }); + /** + * Ajax Event handler for retrieving the result of an SQL Query + */ + $("#db_search_form.ajax").live('submit', function (event) { + event.preventDefault(); + + var $msgbox = PMA_ajaxShowMessage(PMA_messages.strSearching, false); + // jQuery object to reuse + var $form = $(this); + + PMA_prepareForAjaxRequest($form); + + var url = $form.serialize() + "&submit_search=" + $("#buttonGo").val(); + $.post($form.attr('action'), url, function (data) { + if (data.success === true) { + // found results + $("#searchresults").html(data.message); + + $('#togglesearchresultlink') + // always start with the Show message + .text(PMA_messages.strHideSearchResults); + $('#togglesearchresultsdiv') + // now it's time to show the div containing the link + .show(); + $('#searchresults').show(); + + + $('#db_search_form') + // workaround for Chrome problem (bug #3168569) + .slideToggle() + .hide(); + $('#togglesearchformlink') + // always start with the Show message + .text(PMA_messages.strShowSearchCriteria); + $('#togglesearchformdiv') + // now it's time to show the div containing the link + .show(); + } else { + // error message (zero rows) + $("#sqlqueryresults").html(data.error); + } + + PMA_ajaxRemoveMessage($msgbox); + }); + }); +}); // end $() diff --git a/phpMyAdmin/js/db_structure.js b/phpMyAdmin/js/db_structure.js index aae86b0..63d6f43 100644 --- a/phpMyAdmin/js/db_structure.js +++ b/phpMyAdmin/js/db_structure.js @@ -1,13 +1,385 @@ -function PMA_adjustTotals(){var i=[PMA_messages.strB,PMA_messages.strKiB,PMA_messages.strMiB,PMA_messages.strGiB,PMA_messages.strTiB,PMA_messages.strPiB,PMA_messages.strEiB],a=$("#tablesForm table.data tbody:first tr"),c=a.size(),f=0,b=0,h=0,d=false;a.each(function(){var j=$(this),e=j.find(".tbl_rows").text();if(e.indexOf("~")==0){d=true;e=e.substring(1,e.length-1)}e=e.replace(/[,.]/g,"");e=parseInt(e,10);isNaN(e)||(f+=e);var o=e=0,n=$.trim(j.find(".tbl_size span:not(.unit)").text()),p=$.trim(j.find(".tbl_size span.unit").text()), -q=$.trim(j.find(".tbl_overhead span:not(.unit)").text());j=$.trim(j.find(".tbl_overhead span.unit").text());for(var l=0;l=1024;){b/=1024;m++}for(;h>=1024;){h/=1024;g++}b=Math.round(b*10)/10;h=Math.round(h*10)/10;var k=$("#tbl_summary_row");k.find(".tbl_num").text($.sprintf(PMA_messages.strTables, -c));k.find(".tbl_rows").text(a);k.find(".tbl_size").text(b+" "+i[m]);k.find(".tbl_overhead").text(h+" "+i[g])} -$(document).ready(function(){var i;$("td.insert_table a.ajax").live("click",function(a){a.preventDefault();i=$(this);a=$(this).attr("href");if(a.substring(0,15)=="tbl_change.php?")a=a.substring(15);$("#insert_table_dialog").length>0&&$("#insert_table_dialog").remove();var c=$('
    '),f={};f[PMA_messages.strCancel]=function(){$(this).dialog("close").remove()};var b={};b[PMA_messages.strOK]=function(){$(this).dialog("close").remove()};var h=PMA_ajaxShowMessage();$.get("tbl_change.php", -a+"&ajax_request=true",function(d){if(d.success!=undefined&&d.success==false)c.append(d.error).dialog({title:PMA_messages.strInsertTable,height:230,width:900,modal:true,open:PMA_verifyColumnsProperties,buttons:b});else{d=c.append(d).dialog({title:PMA_messages.strInsertTable,height:600,width:900,modal:true,open:PMA_verifyColumnsProperties,buttons:f});d.find("#topmenucontainer").hide();d.find(".datefield, .datetimefield").each(function(){PMA_addDatepicker($(this))});$(".insertRowTable").addClass("ajax"); -$("#buttonYes").addClass("ajax");c=$("#insert_table_dialog");PMA_convertFootnotesToTooltips(c)}PMA_ajaxRemoveMessage(h)})});$("#insertForm .insertRowTable.ajax input[type=submit]").live("click",function(a){a.preventDefault();a=$("#insertForm");$("#result_query").remove();PMA_prepareForAjaxRequest(a);$.post(a.attr("action"),a.serialize(),function(c){c.success==true?PMA_ajaxShowMessage(c.message):PMA_ajaxShowMessage(c.error,false);$("#insert_table_dialog").length>0&&$("#insert_table_dialog").dialog("close").remove(); -i.closest("tr").find(".value.tbl_rows").html(c.row_count);PMA_adjustTotals()})});$("#buttonYes.ajax").live("click",function(a){a.preventDefault();a=$("#insertForm");var c=$("#insertForm").find("#actions_panel .control_at_footer option:selected").attr("value"),f=$("#insertForm").find("#actions_panel select[name=after_insert] option:selected").attr("value");$("#result_query").remove();PMA_prepareForAjaxRequest(a);$.post(a.attr("action"),a.serialize(),function(b){if(b.success==true){PMA_ajaxShowMessage(b.message); -if(c=="showinsert"){$(b.sql_query).insertAfter("#floating_menubar");$("#result_query .notice").remove();$("#result_query").prepend(b.message)}f=="new_insert"&&i.trigger("click")}else PMA_ajaxShowMessage(b.error,false);$("#insert_table_dialog").length>0&&$("#insert_table_dialog").dialog("close").remove();i.closest("tr").find(".value.tbl_rows").html(b.row_count);PMA_adjustTotals()})});$(".truncate_table_anchor").live("click",function(a){a.preventDefault();var c=$(this);a=c.parents("tr").children("th").children("a").text(); -a="TRUNCATE "+escapeHtml(a);c.PMA_confirm(a,c.attr("href"),function(f){PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);$.get(f,{is_js_confirmed:1,ajax_request:true},function(b){if(b.success==true){PMA_ajaxShowMessage(b.message);b=c.closest("tr");b.find(".tbl_rows").text("0");b.find(".tbl_size, .tbl_overhead").text("-");b=c.html().replace(/b_empty/,"bd_empty");c.replaceWith(b).removeClass("truncate_table_anchor");PMA_adjustTotals()}else PMA_ajaxShowMessage(PMA_messages.strErrorProcessingRequest+ -" : "+b.error,false)})})});$(".drop_table_anchor").live("click",function(a){a.preventDefault();a=$(this);var c=a.parents("tr"),f=c.children("th").children("a").text(),b="DROP ";b+=a.hasClass("view")?"VIEW":"TABLE";b+=" "+escapeHtml(f);a.PMA_confirm(b,a.attr("href"),function(h){PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);$.get(h,{is_js_confirmed:1,ajax_request:true},function(d){if(d.success==true){PMA_ajaxShowMessage(d.message);toggleRowColors(c.next());c.hide("medium").remove();PMA_adjustTotals(); -window.parent&&window.parent.frame_navigation&&window.parent.frame_navigation.location.reload()}else PMA_ajaxShowMessage(PMA_messages.strErrorProcessingRequest+" : "+d.error,false)})})});$(".drop_tracking_anchor").live("click",function(a){a.preventDefault();a=$(this);var c=a.parents("tr");a.PMA_confirm(PMA_messages.strDeleteTrackingData,a.attr("href"),function(f){PMA_ajaxShowMessage(PMA_messages.strDeletingTrackingData);$.get(f,{is_js_confirmed:1,ajax_request:true},function(b){if(b.success==true){var h= -c.parents("table"),d=c.find("td:nth-child(2)").text();if(h.find("tbody tr").length===1)$("#tracked_tables").hide("slow").remove();else{toggleRowColors(c.next());c.hide("slow",function(){$(this).remove()})}$untracked_table=$("table#noversions");if($untracked_table.length>0){var m=$untracked_table.find("tbody tr");m.each(function(g){var k=$(this),j=k.find("td:first-child").text();g=g==m.length-1;if(j>d||g){g=k.clone();g.find("td:first-child").text(d);var e=g.find("td:nth-child(2) a").attr("href").replace("table="+ -j,"table="+encodeURIComponent(d));g.find("td:nth-child(2) a").attr("href",e);if(j>d){g.insertBefore(k);toggleRowColors(k);return false}else{g.insertAfter(k);toggleRowColors(g)}}})}PMA_ajaxShowMessage(b.message)}else PMA_ajaxShowMessage(PMA_messages.strErrorProcessingRequest+" : "+b.error,false)})})});$("#real_end_input").live("click",function(a){a.preventDefault();a=PMA_messages.strOperationTakesLongTime;$(this).PMA_confirm(a,"",function(){return true});return false})},"top.frame_content"); +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * @fileoverview functions used on the database structure page + * @name Database Structure + * + * @requires jQuery + * @requires jQueryUI + * @required js/functions.js + */ + +/** + * AJAX scripts for db_structure.php + * + * Actions ajaxified here: + * Drop Database + * Truncate Table + * Drop Table + * + */ + +/** + * Unbind all event handlers before tearing down a page + */ +AJAX.registerTeardown('db_structure.js', function () { + $("span.fkc_switch").unbind('click'); + $('#fkc_checkbox').unbind('change'); + $("a.truncate_table_anchor.ajax").die('click'); + $("a.drop_table_anchor.ajax").die('click'); + $('a.drop_tracking_anchor.ajax').die('click'); + $('#real_end_input').die('click'); +}); + +/** + * Adjust number of rows and total size in the summary + * when truncating, creating, dropping or inserting into a table + */ +function PMA_adjustTotals() { + var byteUnits = new Array( + PMA_messages.strB, + PMA_messages.strKiB, + PMA_messages.strMiB, + PMA_messages.strGiB, + PMA_messages.strTiB, + PMA_messages.strPiB, + PMA_messages.strEiB + ); + /** + * @var $allTr jQuery object that references all the rows in the list of tables + */ + var $allTr = $("#tablesForm table.data tbody:first tr"); + // New summary values for the table + var tableSum = $allTr.size(); + var rowsSum = 0; + var sizeSum = 0; + var overheadSum = 0; + var rowSumApproximated = false; + + $allTr.each(function () { + var $this = $(this); + var i, tmpVal; + // Get the number of rows for this SQL table + var strRows = $this.find('.tbl_rows').text(); + // If the value is approximated + if (strRows.indexOf('~') === 0) { + rowSumApproximated = true; + // The approximated value contains a preceding ~ and a following 2 (Eg 100 --> ~1002) + strRows = strRows.substring(1, strRows.length - 1); + } + strRows = strRows.replace(/[,.]/g, ''); + var intRow = parseInt(strRows, 10); + if (! isNaN(intRow)) { + rowsSum += intRow; + } + // Extract the size and overhead + var valSize = 0; + var valOverhead = 0; + var strSize = $.trim($this.find('.tbl_size span:not(.unit)').text()); + var strSizeUnit = $.trim($this.find('.tbl_size span.unit').text()); + var strOverhead = $.trim($this.find('.tbl_overhead span:not(.unit)').text()); + var strOverheadUnit = $.trim($this.find('.tbl_overhead span.unit').text()); + // Given a value and a unit, such as 100 and KiB, for the table size + // and overhead calculate their numeric values in bytes, such as 102400 + for (i = 0; i < byteUnits.length; i++) { + if (strSizeUnit == byteUnits[i]) { + tmpVal = parseFloat(strSize); + valSize = tmpVal * Math.pow(1024, i); + break; + } + } + for (i = 0; i < byteUnits.length; i++) { + if (strOverheadUnit == byteUnits[i]) { + tmpVal = parseFloat(strOverhead); + valOverhead = tmpVal * Math.pow(1024, i); + break; + } + } + sizeSum += valSize; + overheadSum += valOverhead; + }); + // Add some commas for readablility: + // 1000000 becomes 1,000,000 + var strRowSum = rowsSum + ""; + var regex = /(\d+)(\d{3})/; + while (regex.test(strRowSum)) { + strRowSum = strRowSum.replace(regex, '$1' + ',' + '$2'); + } + // If approximated total value add ~ in front + if (rowSumApproximated) { + strRowSum = "~" + strRowSum; + } + // Calculate the magnitude for the size and overhead values + var size_magnitude = 0, overhead_magnitude = 0; + while (sizeSum >= 1024) { + sizeSum /= 1024; + size_magnitude++; + } + while (overheadSum >= 1024) { + overheadSum /= 1024; + overhead_magnitude++; + } + + sizeSum = Math.round(sizeSum * 10) / 10; + overheadSum = Math.round(overheadSum * 10) / 10; + + // Update summary with new data + var $summary = $("#tbl_summary_row"); + $summary.find('.tbl_num').text($.sprintf(PMA_messages.strTables, tableSum)); + $summary.find('.tbl_rows').text(strRowSum); + $summary.find('.tbl_size').text(sizeSum + " " + byteUnits[size_magnitude]); + $summary.find('.tbl_overhead').text(overheadSum + " " + byteUnits[overhead_magnitude]); +} + +AJAX.registerOnload('db_structure.js', function () { + /** + * Handler for the print view multisubmit. + * All other multi submits can be handled via ajax, but this one needs + * special treatment as the results need to open in another browser window + */ + $('#tablesForm').submit(function (event) { + var $form = $(this); + if ($form.find('select[name=submit_mult]').val() === 'print') { + event.preventDefault(); + event.stopPropagation(); + $('form#clone').remove(); + var $clone = $form + .clone() + .hide() + .appendTo('body'); + $clone + .find('select[name=submit_mult]') + .val('print'); + $clone + .attr('target', 'printview') + .attr('id', 'clone') + .submit(); + } + }); + + /** + * Event handler for 'Foreign Key Checks' disabling option + * in the drop table confirmation form + */ + $("span.fkc_switch").click(function (event) { + if ($("#fkc_checkbox").prop('checked')) { + $("#fkc_checkbox").prop('checked', false); + $("#fkc_status").html(PMA_messages.strForeignKeyCheckDisabled); + return; + } + $("#fkc_checkbox").prop('checked', true); + $("#fkc_status").html(PMA_messages.strForeignKeyCheckEnabled); + }); + + $('#fkc_checkbox').change(function () { + if ($(this).prop("checked")) { + $("#fkc_status").html(PMA_messages.strForeignKeyCheckEnabled); + return; + } + $("#fkc_status").html(PMA_messages.strForeignKeyCheckDisabled); + }); // End of event handler for 'Foreign Key Check' + + /** + * Ajax Event handler for 'Truncate Table' + */ + $("a.truncate_table_anchor.ajax").live('click', function (event) { + event.preventDefault(); + + /** + * @var $this_anchor Object referring to the anchor clicked + */ + var $this_anchor = $(this); + + //extract current table name and build the question string + /** + * @var curr_table_name String containing the name of the table to be truncated + */ + var curr_table_name = $this_anchor.parents('tr').children('th').children('a').text(); + /** + * @var question String containing the question to be asked for confirmation + */ + var question = PMA_messages.strTruncateTableStrongWarning + ' ' + + $.sprintf(PMA_messages.strDoYouReally, 'TRUNCATE ' + escapeHtml(curr_table_name)); + + $this_anchor.PMA_confirm(question, $this_anchor.attr('href'), function (url) { + + PMA_ajaxShowMessage(PMA_messages.strProcessingRequest); + + $.get(url, {'is_js_confirmed' : 1, 'ajax_request' : true}, function (data) { + if (data.success === true) { + PMA_ajaxShowMessage(data.message); + // Adjust table statistics + var $tr = $this_anchor.closest('tr'); + $tr.find('.tbl_rows').text('0'); + $tr.find('.tbl_size, .tbl_overhead').text('-'); + //Fetch inner span of this anchor + //and replace the icon with its disabled version + var span = $this_anchor.html().replace(/b_empty/, 'bd_empty'); + //To disable further attempts to truncate the table, + //replace the a element with its inner span (modified) + $this_anchor + .replaceWith(span) + .removeClass('truncate_table_anchor'); + PMA_adjustTotals(); + } else { + PMA_ajaxShowMessage(PMA_messages.strErrorProcessingRequest + " : " + data.error, false); + } + }); // end $.get() + }); //end $.PMA_confirm() + }); //end of Truncate Table Ajax action + + /** + * Ajax Event handler for 'Drop Table' or 'Drop View' + */ + $("a.drop_table_anchor.ajax").live('click', function (event) { + event.preventDefault(); + + var $this_anchor = $(this); + + //extract current table name and build the question string + /** + * @var $curr_row Object containing reference to the current row + */ + var $curr_row = $this_anchor.parents('tr'); + /** + * @var curr_table_name String containing the name of the table to be truncated + */ + var curr_table_name = $curr_row.children('th').children('a').text(); + /** + * @var is_view Boolean telling if we have a view + */ + var is_view = $curr_row.hasClass('is_view') || $this_anchor.hasClass('view'); + /** + * @var question String containing the question to be asked for confirmation + */ + var question; + if (! is_view) { + question = PMA_messages.strDropTableStrongWarning + ' ' + + $.sprintf(PMA_messages.strDoYouReally, 'DROP TABLE ' + escapeHtml(curr_table_name)); + } else { + question = + $.sprintf(PMA_messages.strDoYouReally, 'DROP VIEW ' + escapeHtml(curr_table_name)); + } + + $this_anchor.PMA_confirm(question, $this_anchor.attr('href'), function (url) { + + var $msg = PMA_ajaxShowMessage(PMA_messages.strProcessingRequest); + + $.get(url, {'is_js_confirmed' : 1, 'ajax_request' : true}, function (data) { + if (data.success === true) { + PMA_ajaxShowMessage(data.message); + toggleRowColors($curr_row.next()); + $curr_row.hide("medium").remove(); + PMA_adjustTotals(); + PMA_reloadNavigation(); + PMA_ajaxRemoveMessage($msg); + } else { + PMA_ajaxShowMessage(PMA_messages.strErrorProcessingRequest + " : " + data.error, false); + } + }); // end $.get() + }); // end $.PMA_confirm() + }); //end of Drop Table Ajax action + + /** + * Ajax Event handler for 'Drop tracking' + */ + $('a.drop_tracking_anchor.ajax').live('click', function (event) { + event.preventDefault(); + + var $anchor = $(this); + + /** + * @var curr_tracking_row Object containing reference to the current tracked table's row + */ + var $curr_tracking_row = $anchor.parents('tr'); + /** + * @var question String containing the question to be asked for confirmation + */ + var question = PMA_messages.strDeleteTrackingData; + + $anchor.PMA_confirm(question, $anchor.attr('href'), function (url) { + + PMA_ajaxShowMessage(PMA_messages.strDeletingTrackingData); + + $.get(url, {'is_js_confirmed': 1, 'ajax_request': true}, function (data) { + if (data.success === true) { + var $tracked_table = $curr_tracking_row.parents('table'); + var table_name = $curr_tracking_row.find('td:nth-child(2)').text(); + + // Check how many rows will be left after we remove + if ($tracked_table.find('tbody tr').length === 1) { + // We are removing the only row it has + $('#tracked_tables').hide("slow").remove(); + } else { + // There are more rows left after the deletion + toggleRowColors($curr_tracking_row.next()); + $curr_tracking_row.hide("slow", function () { + $(this).remove(); + }); + } + + // Make the removed table visible in the list of 'Untracked tables'. + var $untracked_table = $('table#noversions'); + + // This won't work if no untracked tables are there. + if ($untracked_table.length > 0) { + var $rows = $untracked_table.find('tbody tr'); + + $rows.each(function (index) { + var $row = $(this); + var tmp_tbl_name = $row.find('td:first-child').text(); + var is_last_iteration = (index == ($rows.length - 1)); + + if (tmp_tbl_name > table_name || is_last_iteration) { + var $cloned = $row.clone(); + + // Change the table name of the cloned row. + $cloned.find('td:first-child').text(table_name); + + // Change the link of the cloned row. + var new_url = $cloned + .find('td:nth-child(2) a') + .attr('href') + .replace('table=' + tmp_tbl_name, 'table=' + encodeURIComponent(table_name)); + $cloned.find('td:nth-child(2) a').attr('href', new_url); + + // Insert the cloned row in an appropriate location. + if (tmp_tbl_name > table_name) { + $cloned.insertBefore($row); + toggleRowColors($row); + return false; + } else { + $cloned.insertAfter($row); + toggleRowColors($cloned); + } + } + }); + } + + PMA_ajaxShowMessage(data.message); + } else { + PMA_ajaxShowMessage(PMA_messages.strErrorProcessingRequest + " : " + data.error, false); + } + }); // end $.get() + }); // end $.PMA_confirm() + }); //end Drop Tracking + + //Calculate Real End for InnoDB + /** + * Ajax Event handler for calculatig the real end for a InnoDB table + * + */ + $('#real_end_input').live('click', function (event) { + event.preventDefault(); + + /** + * @var question String containing the question to be asked for confirmation + */ + var question = PMA_messages.strOperationTakesLongTime; + + $(this).PMA_confirm(question, '', function () { + return true; + }); + return false; + }); //end Calculate Real End for InnoDB + +}); // end $() diff --git a/phpMyAdmin/js/doclinks.js b/phpMyAdmin/js/doclinks.js new file mode 100644 index 0000000..678e7e8 --- /dev/null +++ b/phpMyAdmin/js/doclinks.js @@ -0,0 +1,365 @@ +/** + * Definition of links to MySQL documentation. + */ + +var mysql_doc_keyword = { + /* Multi word */ + 'CHARACTER SET': Array('charset'), + 'SHOW AUTHORS': Array('show-authors'), + 'SHOW BINARY LOGS': Array('show-binary-logs'), + 'SHOW BINLOG EVENTS': Array('show-binlog-events'), + 'SHOW CHARACTER SET': Array('show-character-set'), + 'SHOW COLLATION': Array('show-collation'), + 'SHOW COLUMNS': Array('show-columns'), + 'SHOW CONTRIBUTORS': Array('show-contributors'), + 'SHOW CREATE DATABASE': Array('show-create-database'), + 'SHOW CREATE EVENT': Array('show-create-event'), + 'SHOW CREATE FUNCTION': Array('show-create-function'), + 'SHOW CREATE PROCEDURE': Array('show-create-procedure'), + 'SHOW CREATE TABLE': Array('show-create-table'), + 'SHOW CREATE TRIGGER': Array('show-create-trigger'), + 'SHOW CREATE VIEW': Array('show-create-view'), + 'SHOW DATABASES': Array('show-databases'), + 'SHOW ENGINE': Array('show-engine'), + 'SHOW ENGINES': Array('show-engines'), + 'SHOW ERRORS': Array('show-errors'), + 'SHOW EVENTS': Array('show-events'), + 'SHOW FUNCTION CODE': Array('show-function-code'), + 'SHOW FUNCTION STATUS': Array('show-function-status'), + 'SHOW GRANTS': Array('show-grants'), + 'SHOW INDEX': Array('show-index'), + 'SHOW MASTER STATUS': Array('show-master-status'), + 'SHOW OPEN TABLES': Array('show-open-tables'), + 'SHOW PLUGINS': Array('show-plugins'), + 'SHOW PRIVILEGES': Array('show-privileges'), + 'SHOW PROCEDURE CODE': Array('show-procedure-code'), + 'SHOW PROCEDURE STATUS': Array('show-procedure-status'), + 'SHOW PROCESSLIST': Array('show-processlist'), + 'SHOW PROFILE': Array('show-profile'), + 'SHOW PROFILES': Array('show-profiles'), + 'SHOW RELAYLOG EVENTS': Array('show-relaylog-events'), + 'SHOW SLAVE HOSTS': Array('show-slave-hosts'), + 'SHOW SLAVE STATUS': Array('show-slave-status'), + 'SHOW STATUS': Array('show-status'), + 'SHOW TABLE STATUS': Array('show-table-status'), + 'SHOW TABLES': Array('show-tables'), + 'SHOW TRIGGERS': Array('show-triggers'), + 'SHOW VARIABLES': Array('show-variables'), + 'SHOW WARNINGS': Array('show-warnings'), + 'LOAD DATA INFILE': Array('load-data'), + 'LOAD XML': Array('load-xml'), + 'LOCK TABLES': Array('lock-tables'), + 'UNLOCK TABLES': Array('lock-tables'), + 'ALTER DATABASE': Array('alter-database'), + 'ALTER EVENT': Array('alter-event'), + 'ALTER LOGFILE GROUP': Array('alter-logfile-group'), + 'ALTER FUNCTION': Array('alter-function'), + 'ALTER PROCEDURE': Array('alter-procedure'), + 'ALTER SERVER': Array('alter-server'), + 'ALTER TABLE': Array('alter-table'), + 'ALTER TABLESPACE': Array('alter-tablespace'), + 'ALTER VIEW': Array('alter-view'), + 'CREATE DATABASE': Array('create-database'), + 'CREATE EVENT': Array('create-event'), + 'CREATE FUNCTION': Array('create-function'), + 'CREATE INDEX': Array('create-index'), + 'CREATE LOGFILE GROUP': Array('create-logfile-group'), + 'CREATE PROCEDURE': Array('create-procedure'), + 'CREATE SERVER': Array('create-server'), + 'CREATE TABLE': Array('create-table'), + 'CREATE TABLESPACE': Array('create-tablespace'), + 'CREATE TRIGGER': Array('create-trigger'), + 'CREATE VIEW': Array('create-view'), + 'DROP DATABASE': Array('drop-database'), + 'DROP EVENT': Array('drop-event'), + 'DROP FUNCTION': Array('drop-function'), + 'DROP INDEX': Array('drop-index'), + 'DROP LOGFILE GROUP': Array('drop-logfile-group'), + 'DROP PROCEDURE': Array('drop-procedure'), + 'DROP SERVER': Array('drop-server'), + 'DROP TABLE': Array('drop-table'), + 'DROP TABLESPACE': Array('drop-tablespace'), + 'DROP TRIGGER': Array('drop-trigger'), + 'DROP VIEW': Array('drop-view'), + 'RENAME TABLE': Array('rename-table'), + 'TRUNCATE TABLE': Array('truncate-table'), + + /* Statements */ + 'SELECT': Array('select'), + 'SET': Array('set'), + 'EXPLAIN': Array('explain'), + 'DESCRIBE': Array('describe'), + 'DELETE': Array('delete'), + 'SHOW': Array('show'), + 'UPDATE': Array('update'), + 'INSERT': Array('insert'), + 'REPLACE': Array('replace'), + 'CALL': Array('call'), + 'DO': Array('do'), + 'HANDLER': Array('handler'), + 'COLLATE': Array('charset-collations'), + + /* Functions */ + 'ABS': Array('mathematical-functions', 'function_abs'), + 'ACOS': Array('mathematical-functions', 'function_acos'), + 'ADDDATE': Array('date-and-time-functions', 'function_adddate'), + 'ADDTIME': Array('date-and-time-functions', 'function_addtime'), + 'AES_DECRYPT': Array('encryption-functions', 'function_aes_decrypt'), + 'AES_ENCRYPT': Array('encryption-functions', 'function_aes_encrypt'), + 'AND': Array('logical-operators', 'operator_and'), + 'ASCII': Array('string-functions', 'function_ascii'), + 'ASIN': Array('mathematical-functions', 'function_asin'), + 'ATAN2': Array('mathematical-functions', 'function_atan2'), + 'ATAN': Array('mathematical-functions', 'function_atan'), + 'AVG': Array('group-by-functions', 'function_avg'), + 'BENCHMARK': Array('information-functions', 'function_benchmark'), + 'BIN': Array('string-functions', 'function_bin'), + 'BINARY': Array('cast-functions', 'operator_binary'), + 'BIT_AND': Array('group-by-functions', 'function_bit_and'), + 'BIT_COUNT': Array('bit-functions', 'function_bit_count'), + 'BIT_LENGTH': Array('string-functions', 'function_bit_length'), + 'BIT_OR': Array('group-by-functions', 'function_bit_or'), + 'BIT_XOR': Array('group-by-functions', 'function_bit_xor'), + 'CASE': Array('control-flow-functions', 'operator_case'), + 'CAST': Array('cast-functions', 'function_cast'), + 'CEIL': Array('mathematical-functions', 'function_ceil'), + 'CEILING': Array('mathematical-functions', 'function_ceiling'), + 'CHAR_LENGTH': Array('string-functions', 'function_char_length'), + 'CHAR': Array('string-functions', 'function_char'), + 'CHARACTER_LENGTH': Array('string-functions', 'function_character_length'), + 'CHARSET': Array('information-functions', 'function_charset'), + 'COALESCE': Array('comparison-operators', 'function_coalesce'), + 'COERCIBILITY': Array('information-functions', 'function_coercibility'), + 'COLLATION': Array('information-functions', 'function_collation'), + 'COMPRESS': Array('encryption-functions', 'function_compress'), + 'CONCAT_WS': Array('string-functions', 'function_concat_ws'), + 'CONCAT': Array('string-functions', 'function_concat'), + 'CONNECTION_ID': Array('information-functions', 'function_connection_id'), + 'CONV': Array('mathematical-functions', 'function_conv'), + 'CONVERT_TZ': Array('date-and-time-functions', 'function_convert_tz'), + 'Convert': Array('cast-functions', 'function_convert'), + 'COS': Array('mathematical-functions', 'function_cos'), + 'COT': Array('mathematical-functions', 'function_cot'), + 'COUNT': Array('group-by-functions', 'function_count'), + 'CRC32': Array('mathematical-functions', 'function_crc32'), + 'CURDATE': Array('date-and-time-functions', 'function_curdate'), + 'CURRENT_DATE': Array('date-and-time-functions', 'function_current_date'), + 'CURRENT_TIME': Array('date-and-time-functions', 'function_current_time'), + 'CURRENT_TIMESTAMP': Array('date-and-time-functions', 'function_current_timestamp'), + 'CURRENT_USER': Array('information-functions', 'function_current_user'), + 'CURTIME': Array('date-and-time-functions', 'function_curtime'), + 'DATABASE': Array('information-functions', 'function_database'), + 'DATE_ADD': Array('date-and-time-functions', 'function_date_add'), + 'DATE_FORMAT': Array('date-and-time-functions', 'function_date_format'), + 'DATE_SUB': Array('date-and-time-functions', 'function_date_sub'), + 'DATE': Array('date-and-time-functions', 'function_date'), + 'DATEDIFF': Array('date-and-time-functions', 'function_datediff'), + 'DAY': Array('date-and-time-functions', 'function_day'), + 'DAYNAME': Array('date-and-time-functions', 'function_dayname'), + 'DAYOFMONTH': Array('date-and-time-functions', 'function_dayofmonth'), + 'DAYOFWEEK': Array('date-and-time-functions', 'function_dayofweek'), + 'DAYOFYEAR': Array('date-and-time-functions', 'function_dayofyear'), + 'DECLARE': Array('declare', 'declare'), + 'DECODE': Array('encryption-functions', 'function_decode'), + 'DEFAULT': Array('miscellaneous-functions', 'function_default'), + 'DEGREES': Array('mathematical-functions', 'function_degrees'), + 'DES_DECRYPT': Array('encryption-functions', 'function_des_decrypt'), + 'DES_ENCRYPT': Array('encryption-functions', 'function_des_encrypt'), + 'DIV': Array('arithmetic-functions', 'operator_div'), + 'ELT': Array('string-functions', 'function_elt'), + 'ENCODE': Array('encryption-functions', 'function_encode'), + 'ENCRYPT': Array('encryption-functions', 'function_encrypt'), + 'EXP': Array('mathematical-functions', 'function_exp'), + 'EXPORT_SET': Array('string-functions', 'function_export_set'), + 'EXTRACT': Array('date-and-time-functions', 'function_extract'), + 'ExtractValue': Array('xml-functions', 'function_extractvalue'), + 'FIELD': Array('string-functions', 'function_field'), + 'FIND_IN_SET': Array('string-functions', 'function_find_in_set'), + 'FLOOR': Array('mathematical-functions', 'function_floor'), + 'FORMAT': Array('string-functions', 'function_format'), + 'FOUND_ROWS': Array('information-functions', 'function_found_rows'), + 'FROM_DAYS': Array('date-and-time-functions', 'function_from_days'), + 'FROM_UNIXTIME': Array('date-and-time-functions', 'function_from_unixtime'), + 'GET_FORMAT': Array('date-and-time-functions', 'function_get_format'), + 'GET_LOCK': Array('miscellaneous-functions', 'function_get_lock'), + 'GREATEST': Array('comparison-operators', 'function_greatest'), + 'GROUP_CONCAT': Array('group-by-functions', 'function_group_concat'), + 'HEX': Array('string-functions', 'function_hex'), + 'HOUR': Array('date-and-time-functions', 'function_hour'), + 'IF': Array('control-flow-functions', 'function_if'), + 'IFNULL': Array('control-flow-functions', 'function_ifnull'), + 'IN': Array('comparison-operators', 'function_in'), + 'INET_ATON': Array('miscellaneous-functions', 'function_inet_aton'), + 'INET_NTOA': Array('miscellaneous-functions', 'function_inet_ntoa'), + 'INSTR': Array('string-functions', 'function_instr'), + 'INTERVAL': Array('comparison-operators', 'function_interval'), + 'IS_FREE_LOCK': Array('miscellaneous-functions', 'function_is_free_lock'), + 'IS_USED_LOCK': Array('miscellaneous-functions', 'function_is_used_lock'), + 'IS': Array('comparison-operators', 'operator_is'), + 'ISNULL': Array('comparison-operators', 'function_isnull'), + 'LAST_DAY': Array('date-and-time-functions', 'function_last_day'), + 'LAST_INSERT_ID': Array('information-functions', 'function_last_insert_id'), + 'LCASE': Array('string-functions', 'function_lcase'), + 'LEAST': Array('comparison-operators', 'function_least'), + 'LEFT': Array('string-functions', 'function_left'), + 'LENGTH': Array('string-functions', 'function_length'), + 'LIKE': Array('string-comparison-functions', 'operator_like'), + 'LN': Array('mathematical-functions', 'function_ln'), + 'LOAD_FILE': Array('string-functions', 'function_load_file'), + 'LOCALTIME': Array('date-and-time-functions', 'function_localtime'), + 'LOCALTIMESTAMP': Array('date-and-time-functions', 'function_localtimestamp'), + 'LOCATE': Array('string-functions', 'function_locate'), + 'LOG10': Array('mathematical-functions', 'function_log10'), + 'LOG2': Array('mathematical-functions', 'function_log2'), + 'LOG': Array('mathematical-functions', 'function_log'), + 'LOWER': Array('string-functions', 'function_lower'), + 'LPAD': Array('string-functions', 'function_lpad'), + 'LTRIM': Array('string-functions', 'function_ltrim'), + 'MAKE_SET': Array('string-functions', 'function_make_set'), + 'MAKEDATE': Array('date-and-time-functions', 'function_makedate'), + 'MAKETIME': Array('date-and-time-functions', 'function_maketime'), + 'MASTER_POS_WAIT': Array('miscellaneous-functions', 'function_master_pos_wait'), + 'MATCH': Array('fulltext-search', 'function_match'), + 'MAX': Array('group-by-functions', 'function_max'), + 'MD5': Array('encryption-functions', 'function_md5'), + 'MICROSECOND': Array('date-and-time-functions', 'function_microsecond'), + 'MID': Array('string-functions', 'function_mid'), + 'MIN': Array('group-by-functions', 'function_min'), + 'MINUTE': Array('date-and-time-functions', 'function_minute'), + 'MOD': Array('mathematical-functions', 'function_mod'), + 'MONTH': Array('date-and-time-functions', 'function_month'), + 'MONTHNAME': Array('date-and-time-functions', 'function_monthname'), + 'NAME_CONST': Array('miscellaneous-functions', 'function_name_const'), + 'NOT': Array('logical-operators', 'operator_not'), + 'NOW': Array('date-and-time-functions', 'function_now'), + 'NULLIF': Array('control-flow-functions', 'function_nullif'), + 'OCT': Array('mathematical-functions', 'function_oct'), + 'OCTET_LENGTH': Array('string-functions', 'function_octet_length'), + 'OLD_PASSWORD': Array('encryption-functions', 'function_old_password'), + 'OR': Array('logical-operators', 'operator_or'), + 'ORD': Array('string-functions', 'function_ord'), + 'PASSWORD': Array('encryption-functions', 'function_password'), + 'PERIOD_ADD': Array('date-and-time-functions', 'function_period_add'), + 'PERIOD_DIFF': Array('date-and-time-functions', 'function_period_diff'), + 'PI': Array('mathematical-functions', 'function_pi'), + 'POSITION': Array('string-functions', 'function_position'), + 'POW': Array('mathematical-functions', 'function_pow'), + 'POWER': Array('mathematical-functions', 'function_power'), + 'QUARTER': Array('date-and-time-functions', 'function_quarter'), + 'QUOTE': Array('string-functions', 'function_quote'), + 'RADIANS': Array('mathematical-functions', 'function_radians'), + 'RAND': Array('mathematical-functions', 'function_rand'), + 'REGEXP': Array('regexp', 'operator_regexp'), + 'RELEASE_LOCK': Array('miscellaneous-functions', 'function_release_lock'), + 'REPEAT': Array('string-functions', 'function_repeat'), + 'REVERSE': Array('string-functions', 'function_reverse'), + 'RIGHT': Array('string-functions', 'function_right'), + 'RLIKE': Array('regexp', 'operator_rlike'), + 'ROUND': Array('mathematical-functions', 'function_round'), + 'ROW_COUNT': Array('information-functions', 'function_row_count'), + 'RPAD': Array('string-functions', 'function_rpad'), + 'RTRIM': Array('string-functions', 'function_rtrim'), + 'SCHEMA': Array('information-functions', 'function_schema'), + 'SEC_TO_TIME': Array('date-and-time-functions', 'function_sec_to_time'), + 'SECOND': Array('date-and-time-functions', 'function_second'), + 'SESSION_USER': Array('information-functions', 'function_session_user'), + 'SHA': Array('encryption-functions', 'function_sha1'), + 'SHA1': Array('encryption-functions', 'function_sha1'), + 'SIGN': Array('mathematical-functions', 'function_sign'), + 'SIN': Array('mathematical-functions', 'function_sin'), + 'SLEEP': Array('miscellaneous-functions', 'function_sleep'), + 'SOUNDEX': Array('string-functions', 'function_soundex'), + 'SPACE': Array('string-functions', 'function_space'), + 'SQRT': Array('mathematical-functions', 'function_sqrt'), + 'STD': Array('group-by-functions', 'function_std'), + 'STDDEV_POP': Array('group-by-functions', 'function_stddev_pop'), + 'STDDEV_SAMP': Array('group-by-functions', 'function_stddev_samp'), + 'STDDEV': Array('group-by-functions', 'function_stddev'), + 'STR_TO_DATE': Array('date-and-time-functions', 'function_str_to_date'), + 'STRCMP': Array('string-comparison-functions', 'function_strcmp'), + 'SUBDATE': Array('date-and-time-functions', 'function_subdate'), + 'SUBSTR': Array('string-functions', 'function_substr'), + 'SUBSTRING_INDEX': Array('string-functions', 'function_substring_index'), + 'SUBSTRING': Array('string-functions', 'function_substring'), + 'SUBTIME': Array('date-and-time-functions', 'function_subtime'), + 'SUM': Array('group-by-functions', 'function_sum'), + 'SYSDATE': Array('date-and-time-functions', 'function_sysdate'), + 'SYSTEM_USER': Array('information-functions', 'function_system_user'), + 'TAN': Array('mathematical-functions', 'function_tan'), + 'TIME_FORMAT': Array('date-and-time-functions', 'function_time_format'), + 'TIME_TO_SEC': Array('date-and-time-functions', 'function_time_to_sec'), + 'TIME': Array('date-and-time-functions', 'function_time'), + 'TIMEDIFF': Array('date-and-time-functions', 'function_timediff'), + 'TIMESTAMP': Array('date-and-time-functions', 'function_timestamp'), + 'TIMESTAMPADD': Array('date-and-time-functions', 'function_timestampadd'), + 'TIMESTAMPDIFF': Array('date-and-time-functions', 'function_timestampdiff'), + 'TO_DAYS': Array('date-and-time-functions', 'function_to_days'), + 'TRIM': Array('string-functions', 'function_trim'), + 'TRUNCATE': Array('mathematical-functions', 'function_truncate'), + 'UCASE': Array('string-functions', 'function_ucase'), + 'UNCOMPRESS': Array('encryption-functions', 'function_uncompress'), + 'UNCOMPRESSED_LENGTH': Array('encryption-functions', 'function_uncompressed_length'), + 'UNHEX': Array('string-functions', 'function_unhex'), + 'UNIX_TIMESTAMP': Array('date-and-time-functions', 'function_unix_timestamp'), + 'UpdateXML': Array('xml-functions', 'function_updatexml'), + 'UPPER': Array('string-functions', 'function_upper'), + 'USER': Array('information-functions', 'function_user'), + 'UTC_DATE': Array('date-and-time-functions', 'function_utc_date'), + 'UTC_TIME': Array('date-and-time-functions', 'function_utc_time'), + 'UTC_TIMESTAMP': Array('date-and-time-functions', 'function_utc_timestamp'), + 'UUID_SHORT': Array('miscellaneous-functions', 'function_uuid_short'), + 'UUID': Array('miscellaneous-functions', 'function_uuid'), + 'VALUES': Array('miscellaneous-functions', 'function_values'), + 'VAR_POP': Array('group-by-functions', 'function_var_pop'), + 'VAR_SAMP': Array('group-by-functions', 'function_var_samp'), + 'VARIANCE': Array('group-by-functions', 'function_variance'), + 'VERSION': Array('information-functions', 'function_version'), + 'WEEK': Array('date-and-time-functions', 'function_week'), + 'WEEKDAY': Array('date-and-time-functions', 'function_weekday'), + 'WEEKOFYEAR': Array('date-and-time-functions', 'function_weekofyear'), + 'XOR': Array('logical-operators', 'operator_xor'), + 'YEAR': Array('date-and-time-functions', 'function_year'), + 'YEARWEEK': Array('date-and-time-functions', 'function_yearweek'), + 'SOUNDS_LIKE': Array('string-functions', 'operator_sounds-like'), + 'IS_NOT_NULL': Array('comparison-operators', 'operator_is-not-null'), + 'IS_NOT': Array('comparison-operators', 'operator_is-not'), + 'IS_NULL': Array('comparison-operators', 'operator_is-null'), + 'NOT_LIKE': Array('string-comparison-functions', 'operator_not-like'), + 'NOT_REGEXP': Array('regexp', 'operator_not-regexp'), + 'COUNT_DISTINCT': Array('group-by-functions', 'function_count-distinct'), + 'NOT_IN': Array('comparison-operators', 'function_not-in') +}; + +var mysql_doc_builtin = { + 'TINYINT': Array('numeric-types'), + 'SMALLINT': Array('numeric-types'), + 'MEDIUMINT': Array('numeric-types'), + 'INT': Array('numeric-types'), + 'BIGINT': Array('numeric-types'), + 'DECIMAL': Array('numeric-types'), + 'FLOAT': Array('numeric-types'), + 'DOUBLE': Array('numeric-types'), + 'REAL': Array('numeric-types'), + 'BIT': Array('numeric-types'), + 'BOOLEAN': Array('numeric-types'), + 'SERIAL': Array('numeric-types'), + 'DATE': Array('date-and-time-types'), + 'DATETIME': Array('date-and-time-types'), + 'TIMESTAMP': Array('date-and-time-types'), + 'TIME': Array('date-and-time-types'), + 'YEAR': Array('date-and-time-types'), + 'CHAR': Array('string-types'), + 'VARCHAR': Array('string-types'), + 'TINYTEXT': Array('string-types'), + 'TEXT': Array('string-types'), + 'MEDIUMTEXT': Array('string-types'), + 'LONGTEXT': Array('string-types'), + 'BINARY': Array('string-types'), + 'VARBINARY': Array('string-types'), + 'TINYBLOB': Array('string-types'), + 'MEDIUMBLOB': Array('string-types'), + 'BLOB': Array('string-types'), + 'LONGBLOB': Array('string-types'), + 'ENUM': Array('string-types'), + 'SET': Array('string-types') +}; diff --git a/phpMyAdmin/js/dom-drag.js b/phpMyAdmin/js/dom-drag.js deleted file mode 100644 index a9dbfbc..0000000 --- a/phpMyAdmin/js/dom-drag.js +++ /dev/null @@ -1,6 +0,0 @@ -var Drag={obj:null,init:function(b,a,c,d,g,e,f,j,h,i){b.onmousedown=Drag.start;b.hmode=f?false:true;b.vmode=j?false:true;b.root=a&&a!=null?a:b;if(b.hmode&&isNaN(parseInt(b.root.style.left)))b.root.style.left="0px";if(b.vmode&&isNaN(parseInt(b.root.style.top)))b.root.style.top="0px";if(!b.hmode&&isNaN(parseInt(b.root.style.right)))b.root.style.right="0px";if(!b.vmode&&isNaN(parseInt(b.root.style.bottom)))b.root.style.bottom="0px";b.minX=typeof c!="undefined"?c:null;b.minY=typeof g!="undefined"?g:null; -b.maxX=typeof d!="undefined"?d:null;b.maxY=typeof e!="undefined"?e:null;b.xMapper=h?h:null;b.yMapper=i?i:null;b.root.onDragStart=new Function;b.root.onDragEnd=new Function;b.root.onDrag=new Function},start:function(b){var a=Drag.obj=this;b=Drag.fixE(b);var c=parseInt(a.vmode?a.root.style.top:a.root.style.bottom),d=parseInt(a.hmode?a.root.style.left:a.root.style.right);a.root.onDragStart(d,c);a.lastMouseX=b.clientX;a.lastMouseY=b.clientY;if(a.hmode){if(a.minX!=null)a.minMouseX=b.clientX-d+a.minX;if(a.maxX!= -null)a.maxMouseX=a.minMouseX+a.maxX-a.minX}else{if(a.minX!=null)a.maxMouseX=-a.minX+b.clientX+d;if(a.maxX!=null)a.minMouseX=-a.maxX+b.clientX+d}if(a.vmode){if(a.minY!=null)a.minMouseY=b.clientY-c+a.minY;if(a.maxY!=null)a.maxMouseY=a.minMouseY+a.maxY-a.minY}else{if(a.minY!=null)a.maxMouseY=-a.minY+b.clientY+c;if(a.maxY!=null)a.minMouseY=-a.maxY+b.clientY+c}document.onmousemove=Drag.drag;document.onmouseup=Drag.end;return false},drag:function(b){b=Drag.fixE(b);var a=Drag.obj,c=b.clientY;b=b.clientX; -var d=parseInt(a.vmode?a.root.style.top:a.root.style.bottom),g=parseInt(a.hmode?a.root.style.left:a.root.style.right),e,f;if(a.minX!=null)b=a.hmode?Math.max(b,a.minMouseX):Math.min(b,a.maxMouseX);if(a.maxX!=null)b=a.hmode?Math.min(b,a.maxMouseX):Math.max(b,a.minMouseX);if(a.minY!=null)c=a.vmode?Math.max(c,a.minMouseY):Math.min(c,a.maxMouseY);if(a.maxY!=null)c=a.vmode?Math.min(c,a.maxMouseY):Math.max(c,a.minMouseY);e=g+(b-a.lastMouseX)*(a.hmode?1:-1);f=d+(c-a.lastMouseY)*(a.vmode?1:-1);if(a.xMapper)e= -a.xMapper(d);else if(a.yMapper)f=a.yMapper(g);Drag.obj.root.style[a.hmode?"left":"right"]=e+"px";Drag.obj.root.style[a.vmode?"top":"bottom"]=f+"px";Drag.obj.lastMouseX=b;Drag.obj.lastMouseY=c;Drag.obj.root.onDrag(e,f);return false},end:function(){document.onmousemove=null;document.onmouseup=null;Drag.obj.root.onDragEnd(parseInt(Drag.obj.root.style[Drag.obj.hmode?"left":"right"]),parseInt(Drag.obj.root.style[Drag.obj.vmode?"top":"bottom"]));Drag.obj=null},fixE:function(b){if(typeof b=="undefined")b= -window.event;if(typeof b.layerX=="undefined")b.layerX=b.offsetX;if(typeof b.layerY=="undefined")b.layerY=b.offsetY;return b}}; diff --git a/phpMyAdmin/js/error_report.js b/phpMyAdmin/js/error_report.js new file mode 100644 index 0000000..c376530 --- /dev/null +++ b/phpMyAdmin/js/error_report.js @@ -0,0 +1,310 @@ +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * general function, usually for data manipulation pages + * + */ + +var ErrorReport = { + /** + * @var object stores the last exception info + */ + _last_exception: null, + /** + * handles thrown error exceptions based on user preferences + * + * @return void + */ + error_handler: function (exception) { + ErrorReport._last_exception = exception; + $.get("error_report.php", { + ajax_request: true, + token: PMA_commonParams.get('token'), + get_settings: true + }, function (data) { + if (!data.success === true) { + PMA_ajaxShowMessage(data.error, false); + return; + } + if (data.report_setting == "ask") { + ErrorReport._showErrorNotification(); + } else if (data.report_setting == "always") { + report_data = ErrorReport._get_report_data(exception); + post_data = $.extend(report_data, { + send_error_report: true, + automatic: true + }); + $.post("error_report.php", post_data, function (data) { + if (data.success === false) { + //in the case of an error, show the error message returned. + PMA_ajaxShowMessage(data.error, false); + } else { + PMA_ajaxShowMessage(data.message, false); + } + }); + } + }); + }, + /** + * Shows the modal dialog previewing the report + * + * @param object error report info + * + * @return void + */ + _showReportDialog: function (exception) { + var report_data = ErrorReport._get_report_data(exception); + + /*Remove the hidden dialogs if there are*/ + if ($('#error_report_dialog').length !== 0) { + $('#error_report_dialog').remove(); + } + var $div = $('
    '); + + var button_options = {}; + + button_options[PMA_messages.strSendErrorReport] = function () { + $dialog = $(this); + post_data = $.extend(report_data, { + send_error_report: true, + description: $("#report_description").val(), + always_send: $("#always_send_checkbox")[0].checked + }); + $.post("error_report.php", post_data, function (data) { + $dialog.dialog('close'); + if (data.success === false) { + //in the case of an error, show the error message returned. + PMA_ajaxShowMessage(data.error, false); + } else { + PMA_ajaxShowMessage(data.message, 3000); + } + }); + }; + + button_options[PMA_messages.strCancel] = function () { + $(this).dialog('close'); + }; + + $.post("error_report.php", report_data, function (data) { + if (data.success === false) { + //in the case of an error, show the error message returned. + PMA_ajaxShowMessage(data.error, false); + } else { + // Show dialog if the request was successful + $div + .append(data.message) + .dialog({ + title: PMA_messages.strSubmitErrorReport, + width: 650, + modal: true, + buttons: button_options, + close: function () { + $(this).remove(); + } + }); + } + }); // end $.get() + }, + /** + * Shows the small notification that asks for user permission + * + * @return void + */ + _showErrorNotification: function () { + ErrorReport._removeErrorNotification(); + + $div = $( + '
    ' + ).append( + PMA_getImage("s_error.png") + PMA_messages.strErrorOccurred + ); + + $buttons = $('
    '); + + button_html = ''; + + button_html += ''; + button_html += PMA_getImage('s_cog.png', PMA_messages.strChangeReportSettings); + button_html += ''; + + button_html += ''; + button_html += PMA_getImage('b_close.png', PMA_messages.strIgnore); + button_html += ''; + + $buttons.html(button_html); + + $div.append($buttons); + $div.appendTo(document.body); + $("#change_error_settings").on("click", ErrorReport._redirect_to_settings); + $("#show_error_report").on("click", ErrorReport._createReportDialog); + $("#ignore_error").on("click", ErrorReport._removeErrorNotification); + }, + /** + * Removes the notification if it was displayed before + * + * @return void + */ + _removeErrorNotification: function () { + $("#error_notification").fadeOut(function () { + $(this).remove(); + }); + }, + /** + * Shows the modal dialog previewing the report + * + * @return void + */ + _createReportDialog: function () { + ErrorReport._removeErrorNotification(); + ErrorReport._showReportDialog(ErrorReport._last_exception); + }, + /** + * Returns the needed info about stored microhistory + * + * @return object + */ + _get_microhistory: function () { + cached_pages = AJAX.cache.pages.slice(-7); + remove = ["common_query", "table", "db", "token", "pma_absolute_uri"]; + return { + pages: cached_pages.map(function (page) { + simplepage = { + hash: page.hash + }; + + if (page.params) { + simplepage.params = $.extend({}, page.params); + $.each(simplepage.params, function (param) { + if ($.inArray(param, remove) != -1) { + delete simplepage.params[param]; + } + }); + } + + return simplepage; + }), + current_index: AJAX.cache.current - + (AJAX.cache.pages.length - cached_pages.length) + }; + }, + /** + * Redirects to the settings page containing error report + * preferences + * + * @return void + */ + _redirect_to_settings: function () { + window.location.href = "prefs_forms.php?token=" + PMA_commonParams.get('token'); + }, + /** + * Returns the report data to send to the server + * + * @param object exception info + * + * @return object + */ + _get_report_data: function (exception) { + var report_data = { + "ajax_request": true, + "token": PMA_commonParams.get('token'), + "exception": exception, + "current_url": window.location.href, + "microhistory": ErrorReport._get_microhistory() + }; + if (typeof AJAX.cache.pages[AJAX.cache.current - 1] !== 'undefined') { + report_data.scripts = AJAX.cache.pages[AJAX.cache.current - 1].scripts.map( + function (script) { + return script.name; + } + ); + } + return report_data; + }, + /** + * Wraps all global functions that start with PMA_ + * + * @return void + */ + wrap_global_functions: function () { + for (var key in window) { + var global = window[key]; + if (typeof(global) === "function" && key.indexOf("PMA_") === 0) { + window[key] = ErrorReport.wrap_function(global); + } + } + }, + /** + * Wraps given function in error reporting code and returns wrapped function + * + * @param function function to be wrapped + * + * @return function + */ + wrap_function: function (func) { + if (!func.wrapped) { + var new_func = function () { + try { + return func.apply(this, arguments); + } catch (x) { + TraceKit.report(x); + } + }; + new_func.wrapped = true; + //Set guid of wrapped function same as original function, so it can be removed + //See bug#4146 (problem with jquery draggable and sortable) + new_func.guid = func.guid = func.guid || new_func.guid || jQuery.guid++; + return new_func; + } else { + return func; + } + }, + /** + * Automatically wraps the callback in AJAX.registerOnload + * + * @return void + */ + _wrap_ajax_onload_callback: function () { + var oldOnload = AJAX.registerOnload; + AJAX.registerOnload = function (file, func) { + func = ErrorReport.wrap_function(func); + oldOnload.call(this, file, func); + }; + }, + /** + * Automatically wraps the callback in $.fn.on + * + * @return void + */ + _wrap_$_on_callback: function () { + var oldOn = $.fn.on; + $.fn.on = function () { + for (var i = 1; i <= 3; i++) { + if (typeof(arguments[i]) === "function") { + arguments[i] = ErrorReport.wrap_function(arguments[i]); + break; + } + } + return oldOn.apply(this, arguments); + }; + }, + /** + * Wraps all global functions that start with PMA_ + * also automatically wraps the callback in AJAX.registerOnload + * + * @return void + */ + set_up_error_reporting: function () { + ErrorReport.wrap_global_functions(); + ErrorReport._wrap_ajax_onload_callback(); + ErrorReport._wrap_$_on_callback(); + } + +}; + +TraceKit.report.subscribe(ErrorReport.error_handler); +ErrorReport.set_up_error_reporting(); +$(function () { + ErrorReport.wrap_global_functions(); +}); diff --git a/phpMyAdmin/js/export.js b/phpMyAdmin/js/export.js index 352d424..a16bd29 100644 --- a/phpMyAdmin/js/export.js +++ b/phpMyAdmin/js/export.js @@ -1,13 +1,282 @@ -$(document).ready(function(){$("#plugins").change(function(){$(".format_specific_options").each(function(){$(this).hide()});var a=$("#plugins option:selected").attr("value");$("#"+a+"_options").show()})}); -$(document).ready(function(){$("input[type='radio'][name$='sql_structure_or_data']").change(function(){if($("input[type='radio'][name$='sql_structure_or_data']:checked").attr("value")=="data"){$("#checkbox_sql_dates").parent().fadeTo("fast",0.4);$("#checkbox_sql_dates").attr("disabled","disabled");$("#checkbox_sql_relation").parent().fadeTo("fast",0.4);$("#checkbox_sql_relation").attr("disabled","disabled");$("#checkbox_sql_mime").parent().fadeTo("fast",0.4);$("#checkbox_sql_mime").attr("disabled", -"disabled")}else{$("#checkbox_sql_dates").parent().fadeTo("fast",1);$("#checkbox_sql_dates").removeAttr("disabled");$("#checkbox_sql_relation").parent().fadeTo("fast",1);$("#checkbox_sql_relation").removeAttr("disabled");$("#checkbox_sql_mime").parent().fadeTo("fast",1);$("#checkbox_sql_mime").removeAttr("disabled")}})}); -function toggle_structure_data_opts(a){var b="#"+a+"_data",c="#"+a+"_structure";a=$("input[type='radio'][name='"+(a+"_structure_or_data")+"']:checked").attr("value");if(a=="data"){$(b).slideDown("slow");$(c).slideUp("slow")}else{$(c).slideDown("slow");a=="structure"?$(b).slideUp("slow"):$(b).slideDown("slow")}} -$(document).ready(function(){$("input[type='radio'][name='latex_structure_or_data']").change(function(){toggle_structure_data_opts("latex")});$("input[type='radio'][name='odt_structure_or_data']").change(function(){toggle_structure_data_opts("odt")});$("input[type='radio'][name='texytext_structure_or_data']").change(function(){toggle_structure_data_opts("texytext")});$("input[type='radio'][name='htmlword_structure_or_data']").change(function(){toggle_structure_data_opts("htmlword")});$("input[type='radio'][name='sql_structure_or_data']").change(function(){toggle_structure_data_opts("sql")})}); -function toggle_save_to_file(){if($("#radio_dump_asfile:checked").length==0){$("#ul_save_asfile > li").fadeTo("fast",0.4);$("#ul_save_asfile > li > input").attr("disabled","disabled");$("#ul_save_asfile > li> select").attr("disabled","disabled")}else{$("#ul_save_asfile > li").fadeTo("fast",1);$("#ul_save_asfile > li > input").removeAttr("disabled");$("#ul_save_asfile > li> select").removeAttr("disabled")}}$(document).ready(function(){toggle_save_to_file();$("input[type='radio'][name='output_format']").change(function(){toggle_save_to_file()})}); -function toggle_sql_include_comments(){$("#checkbox_sql_include_comments").change(function(){if($("#checkbox_sql_include_comments:checked").length==0){$("#ul_include_comments > li").fadeTo("fast",0.4);$("#ul_include_comments > li > input").attr("disabled","disabled")}else if($("#radio_sql_structure_or_data_data:checked").length==1){$("#text_sql_header_comment").parent("li").fadeTo("fast",1);$("#text_sql_header_comment").removeAttr("disabled")}else{$("#ul_include_comments > li").fadeTo("fast",1);$("#ul_include_comments > li > input").removeAttr("disabled")}})} -$(document).ready(function(){$("#checkbox_sql_create_table_statements").change(function(){if($("#checkbox_sql_create_table_statements:checked").length==0){$("#checkbox_sql_if_not_exists").removeAttr("checked");$("#checkbox_sql_auto_increment").removeAttr("checked")}else{$("#checkbox_sql_if_not_exists").attr("checked","checked");$("#checkbox_sql_auto_increment").attr("checked","checked")}})}); -$(document).ready(function(){$("#plugins").change(function(){var a=$("#plugins option:selected").attr("value");if($("#force_file_"+a).attr("value")=="true"){$("#radio_view_as_text").attr("disabled","disabled");$("#radio_view_as_text").parent().fadeTo("fast",0.4)}else{$("#radio_view_as_text").removeAttr("disabled");$("#radio_view_as_text").parent().fadeTo("fast",1)}})}); -function toggle_quick_or_custom(){if($("$(this):checked").attr("value")=="custom"){$("#databases_and_tables").show();$("#rows").show();$("#output").show();$("#format_specific_opts").show();$("#output_quick_export").hide();var a=$("#plugins option:selected").attr("value");$("#"+a+"_options").show()}else{$("#databases_and_tables").hide();$("#rows").hide();$("#output").hide();$("#format_specific_opts").hide();$("#output_quick_export").show()}}$(document).ready(function(){$("input[type='radio'][name='quick_or_custom']").change(function(){toggle_quick_or_custom()})}); -$(document).ready(function(){$("input[type='hidden'][name='export_method']").attr("value")!="custom-no-form"&&$("#quick_or_custom").show();$("#scroll_to_options_msg").hide();$(".format_specific_options").hide();$(".format_specific_options").css({border:0,margin:0,padding:0});$(".format_specific_options h3").remove();toggle_quick_or_custom();toggle_structure_data_opts($("select[id='plugins']").attr("value"));toggle_sql_include_comments()}); -$(document).ready(function(){$("input[type='radio'][name='allrows']").change(function(){if($("input[type='radio'][name='allrows']:checked").attr("value")=="1"){$("label[for='limit_to']").fadeTo("fast",0.4);$("label[for='limit_from']").fadeTo("fast",0.4);$("input[type='text'][name='limit_to']").attr("disabled","disabled");$("input[type='text'][name='limit_from']").attr("disabled","disabled")}else{$("label[for='limit_to']").fadeTo("fast",1);$("label[for='limit_from']").fadeTo("fast",1);$("input[type='text'][name='limit_to']").removeAttr("disabled"); -$("input[type='text'][name='limit_from']").removeAttr("disabled")}})}); +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * Functions used in the export tab + * + */ + +/** + * Disables the "Dump some row(s)" sub-options + */ +function disable_dump_some_rows_sub_options() +{ + $("label[for='limit_to']").fadeTo('fast', 0.4); + $("label[for='limit_from']").fadeTo('fast', 0.4); + $("input[type='text'][name='limit_to']").prop('disabled', 'disabled'); + $("input[type='text'][name='limit_from']").prop('disabled', 'disabled'); +} + +/** + * Enables the "Dump some row(s)" sub-options + */ +function enable_dump_some_rows_sub_options() +{ + $("label[for='limit_to']").fadeTo('fast', 1); + $("label[for='limit_from']").fadeTo('fast', 1); + $("input[type='text'][name='limit_to']").prop('disabled', ''); + $("input[type='text'][name='limit_from']").prop('disabled', ''); +} + +/** + * Unbind all event handlers before tearing down a page + */ +AJAX.registerTeardown('export.js', function () { + $("#plugins").unbind('change'); + $("input[type='radio'][name='sql_structure_or_data']").unbind('change'); + $("input[type='radio'][name='latex_structure_or_data']").unbind('change'); + $("input[type='radio'][name='odt_structure_or_data']").unbind('change'); + $("input[type='radio'][name='texytext_structure_or_data']").unbind('change'); + $("input[type='radio'][name='htmlword_structure_or_data']").unbind('change'); + $("input[type='radio'][name='sql_structure_or_data']").unbind('change'); + $("input[type='radio'][name='output_format']").unbind('change'); + $("#checkbox_sql_include_comments").unbind('change'); + $("#plugins").unbind('change'); + $("input[type='radio'][name='quick_or_custom']").unbind('change'); + $("input[type='radio'][name='allrows']").unbind('change'); +}); + +AJAX.registerOnload('export.js', function () { + /** + * Toggles the hiding and showing of each plugin's options + * according to the currently selected plugin from the dropdown list + */ + $("#plugins").change(function () { + $("#format_specific_opts div.format_specific_options").hide(); + var selected_plugin_name = $("#plugins option:selected").val(); + $("#" + selected_plugin_name + "_options").show(); + }); + + /** + * Toggles the enabling and disabling of the SQL plugin's comment options that apply only when exporting structure + */ + $("input[type='radio'][name='sql_structure_or_data']").change(function () { + var comments_are_present = $("#checkbox_sql_include_comments").prop("checked"); + var show = $("input[type='radio'][name='sql_structure_or_data']:checked").val(); + if (show == 'data') { + // disable the SQL comment options + if (comments_are_present) { + $("#checkbox_sql_dates").prop('disabled', true).parent().fadeTo('fast', 0.4); + } + $("#checkbox_sql_relation").prop('disabled', true).parent().fadeTo('fast', 0.4); + $("#checkbox_sql_mime").prop('disabled', true).parent().fadeTo('fast', 0.4); + } else { + // enable the SQL comment options + if (comments_are_present) { + $("#checkbox_sql_dates").removeProp('disabled').parent().fadeTo('fast', 1); + } + $("#checkbox_sql_relation").removeProp('disabled').parent().fadeTo('fast', 1); + $("#checkbox_sql_mime").removeProp('disabled').parent().fadeTo('fast', 1); + } + }); +}); + + +/** + * Toggles the hiding and showing of plugin structure-specific and data-specific + * options + */ +function toggle_structure_data_opts(pluginName) +{ + var radioFormName = pluginName + "_structure_or_data"; + var dataDiv = "#" + pluginName + "_data"; + var structureDiv = "#" + pluginName + "_structure"; + var show = $("input[type='radio'][name='" + radioFormName + "']:checked").val(); + if (show == 'data') { + $(dataDiv).slideDown('slow'); + $(structureDiv).slideUp('slow'); + } else { + $(structureDiv).slideDown('slow'); + if (show == 'structure') { + $(dataDiv).slideUp('slow'); + } else { + $(dataDiv).slideDown('slow'); + } + } +} + +AJAX.registerOnload('export.js', function () { + $("input[type='radio'][name='latex_structure_or_data']").change(function () { + toggle_structure_data_opts("latex"); + }); + $("input[type='radio'][name='odt_structure_or_data']").change(function () { + toggle_structure_data_opts("odt"); + }); + $("input[type='radio'][name='texytext_structure_or_data']").change(function () { + toggle_structure_data_opts("texytext"); + }); + $("input[type='radio'][name='htmlword_structure_or_data']").change(function () { + toggle_structure_data_opts("htmlword"); + }); + $("input[type='radio'][name='sql_structure_or_data']").change(function () { + toggle_structure_data_opts("sql"); + }); +}); + +/** + * Toggles the disabling of the "save to file" options + */ +function toggle_save_to_file() +{ + if (!$("#radio_dump_asfile").prop("checked")) { + $("#ul_save_asfile > li").fadeTo('fast', 0.4); + $("#ul_save_asfile > li > input").prop('disabled', true); + $("#ul_save_asfile > li> select").prop('disabled', true); + } else { + $("#ul_save_asfile > li").fadeTo('fast', 1); + $("#ul_save_asfile > li > input").removeProp('disabled'); + $("#ul_save_asfile > li> select").removeProp('disabled'); + } +} + +AJAX.registerOnload('export.js', function () { + toggle_save_to_file(); + $("input[type='radio'][name='output_format']").change(toggle_save_to_file); +}); + +/** + * For SQL plugin, toggles the disabling of the "display comments" options + */ +function toggle_sql_include_comments() +{ + $("#checkbox_sql_include_comments").change(function () { + if (!$("#checkbox_sql_include_comments").prop("checked")) { + $("#ul_include_comments > li").fadeTo('fast', 0.4); + $("#ul_include_comments > li > input").prop('disabled', true); + } else { + // If structure is not being exported, the comment options for structure should not be enabled + if ($("#radio_sql_structure_or_data_data").prop("checked")) { + $("#text_sql_header_comment").removeProp('disabled').parent("li").fadeTo('fast', 1); + } else { + $("#ul_include_comments > li").fadeTo('fast', 1); + $("#ul_include_comments > li > input").removeProp('disabled'); + } + } + }); +} + +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 + */ + $("#plugins").change(function () { + var active_plugin = $("#plugins option:selected").val(); + var force_file = $("#force_file_" + active_plugin).val(); + if (force_file == "true") { + $("#radio_view_as_text").prop('disabled', true).parent().fadeTo('fast', 0.4); + } else { + $("#radio_view_as_text").removeProp('disabled').parent().fadeTo('fast', 1); + } + }); +}); + +/** + * Toggles display of options when quick and custom export are selected + */ +function toggle_quick_or_custom() +{ + if ($("#radio_custom_export").prop("checked")) { + $("#databases_and_tables").show(); + $("#rows").show(); + $("#output").show(); + $("#format_specific_opts").show(); + $("#output_quick_export").hide(); + var selected_plugin_name = $("#plugins option:selected").val(); + $("#" + selected_plugin_name + "_options").show(); + } else { + $("#databases_and_tables").hide(); + $("#rows").hide(); + $("#output").hide(); + $("#format_specific_opts").hide(); + $("#output_quick_export").show(); + } +} +var time_out; +function check_time_out(time_limit) +{ + //margin of one second to avoid race condition to set/access session variable + time_limit = time_limit + 1; + var href = "export.php"; + var params = { + 'ajax_request' : true, + 'token' : PMA_commonParams.get('token'), + 'check_time_out' : true + }; + clearTimeout(time_out); + time_out = setTimeout(function(){ + $.get(href, params, function (data) { + if (data['message'] !== 'success') { + PMA_ajaxShowMessage( + '
    ' + + PMA_messages.strTimeOutError + + '
    ', + false + ); + } + }); + }, time_limit * 1000); + +} +AJAX.registerOnload('export.js', function () { + $("input[type='radio'][name='quick_or_custom']").change(toggle_quick_or_custom); + + /** + * Sets up the interface for Javascript-enabled browsers since the default is for + * Javascript-disabled browsers + * TODO: drop non-JS behaviour + */ + if ($("input[type='hidden'][name='export_method']").val() != "custom-no-form") { + $("#quick_or_custom").show(); + } + $("#scroll_to_options_msg").hide(); + $("#format_specific_opts div.format_specific_options") + .hide() + .css({ + "border": 0, + "margin": 0, + "padding": 0 + }) + .find("h3") + .remove(); + toggle_quick_or_custom(); + toggle_structure_data_opts($("select#plugins").val()); + toggle_sql_include_comments(); + + /** + * Initially disables the "Dump some row(s)" sub-options + */ + disable_dump_some_rows_sub_options(); + + /** + * Disables the "Dump some row(s)" sub-options when it is not selected + */ + $("input[type='radio'][name='allrows']").change(function () { + if ($("input[type='radio'][name='allrows']").prop("checked")) { + enable_dump_some_rows_sub_options(); + } else { + disable_dump_some_rows_sub_options(); + } + }); +}); diff --git a/phpMyAdmin/js/functions.js b/phpMyAdmin/js/functions.js index 0ec7268..7663565 100644 --- a/phpMyAdmin/js/functions.js +++ b/phpMyAdmin/js/functions.js @@ -1,110 +1,4090 @@ -var sql_box_locked=false,only_once_elements=[],ajax_message_count=0,codemirror_editor=false,chart_activeTimeouts={};function getWindowSize(a){a=a||window;return{width:a.innerWidth||(a.documentElement!==undefined?a.documentElement.clientWidth:false)||$(a).width(),height:a.innerHeight||(a.documentElement!==undefined?a.documentElement.clientHeight:false)||$(a).height()}} -$.ajaxPrefilter(function(a,b){var c=(new Date).getTime()+""+Math.floor(Math.random()*1E6);if(typeof a.data=="string")a.data+="&_nocache="+c;else if(typeof a.data=="object")a.data=$.extend(b.data,{_nocache:c})});function PMA_prepareForAjaxRequest(a){a.find("input:hidden").is("#ajax_request_hidden")||a.append('')} -function suggestPassword(a){var b=a.generated_pw;b.value="";for(i=0;i<16;i++)b.value+="abcdefhjmnpqrstuvwxyz23456789ABCDEFGHJKLMNPQRSTUVWYXZ".charAt(Math.floor(Math.random()*53));a.text_pma_pw.value=b.value;a.text_pma_pw2.value=b.value;return true} -function parseVersionString(a){if(typeof a!="string")return false;var b=0,c=a.split("-");if(c.length>=2)if(c[1].substr(0,2)=="rc")b=-20-parseInt(c[1].substr(2));else if(c[1].substr(0,4)=="beta")b=-40-parseInt(c[1].substr(4));else if(c[1].substr(0,5)=="alpha")b=-60-parseInt(c[1].substr(5));else if(c[1].substr(0,3)=="dev")b=0;var d=a.split(".");a=parseInt(d[0])||0;c=parseInt(d[1])||0;var e=parseInt(d[2])||0;d=parseInt(d[3])||0;return a*1E8+c*1E6+e*1E4+d*100+b} -function PMA_current_version(a){if(a&&a.version&&a.date){var b=parseVersionString(pmaversion),c=parseVersionString(a.version),d=PMA_messages.strLatestAvailable+" "+escapeHtml(a.version);if(c>b){a=$.sprintf(PMA_messages.strNewerVersion,escapeHtml(a.version),escapeHtml(a.date));klass=Math.floor(c/1E4)===Math.floor(b/1E4)?"error":"notice";$("#maincontainer").after('
    '+a+"
    ")}if(c===b)d=" ("+PMA_messages.strUpToDate+")";$("#li_pma_version").append(d)}} -function displayPasswordGenerateButton(){$("#tr_element_before_generate_password").parent().append(""+PMA_messages.strGeneratePassword+'');$("#div_element_before_generate_password").parent().append('
    ')} -function PMA_addDatepicker(a,b){var c=false;if(a.is(".datetimefield"))c=true;a.datetimepicker($.extend({showOn:"button",buttonImage:themeCalendarImage,buttonImageOnly:true,stepMinutes:1,stepHours:1,showSecond:true,showTimepicker:c,showButtonPanel:false,dateFormat:"yy-mm-dd",timeFormat:"hh:mm:ss",altFieldTimeOnly:false,showAnim:"",beforeShow:function(){a.data("comes_from","datepicker");setTimeout(function(){$("#ui-timepicker-div").css("z-index",$("#ui-datepicker-div").css("z-index"))},0)},onClose:function(){a.data("comes_from", -"")}},b))}function selectContent(a,b,c){if(!(c&&only_once_elements[a.name])){only_once_elements[a.name]=true;b||a.select()}} -function confirmLink(a,b){if(PMA_messages.strDoYouReally==""||typeof window.opera!="undefined")return true;var c=confirm(PMA_messages.strDoYouReally+" :\n"+b);if(c)if($(a).hasClass("formLinkSubmit")){var d="is_js_confirmed";if($(a).attr("href").indexOf("usesubform")!=-1)d="subform["+$(a).attr("href").substr("#").match(/usesubform\[(\d+)\]/i)[1]+"][is_js_confirmed]";$(a).parents("form").append('')}else if(typeof a.href!="undefined")a.href+="&is_js_confirmed=1"; -else if(typeof a.form!="undefined")a.form.action+="?is_js_confirmed=1";return c} -function confirmQuery(a,b){if(PMA_messages.strDoYouReally=="")return true;if(PMA_messages.strNoDropDatabases!="")if(/(^|;)\s*DROP\s+(IF EXISTS\s+)?DATABASE\s/i.test(b.value)){alert(PMA_messages.strNoDropDatabases);a.reset();b.focus();return false}var c=/^\s*ALTER\s+TABLE\s+((`[^`]+`)|([A-Za-z0-9_$]+))\s+DROP\s/i,d=/^\s*DELETE\s+FROM\s/i,e=/^\s*TRUNCATE\s/i;if(/^\s*DROP\s+(IF EXISTS\s+)?(TABLE|DATABASE|PROCEDURE)\s/i.test(b.value)||c.test(b.value)||d.test(b.value)||e.test(b.value)){c=b.value.length> -100?b.value.substr(0,100)+"\n ...":b.value;if(confirm(PMA_messages.strDoYouReally+" :\n"+c)){a.elements.is_js_confirmed.value=1;return true}else{window.focus();b.focus();return false}}return true}function confirmDisableRepository(){if(PMA_messages.strDoYouReally==""||typeof window.opera!="undefined")return true;return confirm(PMA_messages.strBLOBRepositoryDisableStrongWarning+"\n"+PMA_messages.strBLOBRepositoryDisableAreYouSure)} -function checkSqlQuery(a){var b=a.elements.sql_query,c=/\s+/;if(typeof a.elements.sql_file!="undefined"&&a.elements.sql_file.value.replace(c,"")!="")return true;if(typeof a.elements.sql_localfile!="undefined"&&a.elements.sql_localfile.value.replace(c,"")!="")return true;if(typeof a.elements.id_bookmark!="undefined"&&(a.elements.id_bookmark.value!=null||a.elements.id_bookmark.value!="")&&a.elements.id_bookmark.selectedIndex!=0)return true;if(b.value.replace(c,"")!="")return confirmQuery(a,b)?true: -false;a.reset();b.select();alert(PMA_messages.strFormEmpty);b.focus();return false}function emptyCheckTheField(a,b){return a.elements[b].value.replace(/\s+/,"")==""?1:0}function emptyFormElements(a,b){return emptyCheckTheField(a,b)} -function checkFormElementInRange(a,b,c,d,e){a=a.elements[b];b=parseInt(a.value);if(typeof d=="undefined")d=0;if(typeof e=="undefined")e=Number.MAX_VALUE;if(isNaN(b)){a.select();alert(PMA_messages.strNotNumber);a.focus();return false}else if(be){a.select();alert(c.replace("%d",b));a.focus();return false}else a.value=b;return true} -function checkTableEditForm(a,b){var c=0,d,e,g,f;for(d=0;d=0){if(last_shift_clicked_row>=last_clicked_row){a=last_clicked_row;c=last_shift_clicked_row}else{a=last_shift_clicked_row;c=last_clicked_row}b.parent().find("tr.odd:not(.noclick), tr.even:not(.noclick)").slice(a,c+1).removeClass("marked").find(":checkbox").attr("checked",false)}d=$("tr.odd:not(.noclick), tr.even:not(.noclick)").index(this);if(d>=last_clicked_row){a= -last_clicked_row;c=d}else{a=d;c=last_clicked_row}b.parent().find("tr.odd:not(.noclick), tr.even:not(.noclick)").slice(a,c+1).addClass("marked").find(":checkbox").attr("checked",true);last_shift_clicked_row=d}}});$.timepicker!=undefined&&$(".datefield, .datetimefield").each(function(){PMA_addDatepicker($(this))})});var last_click_checked=false,last_clicked_row=-1,last_shift_clicked_row=-1,marked_row=[]; -function markAllRows(a){$("#"+a).find("input:checkbox:enabled").attr("checked","checked").parents("tr").addClass("marked");return true}function unMarkAllRows(a){$("#"+a).find("input:checkbox:enabled").removeAttr("checked").parents("tr").removeClass("marked");return true}function setCheckboxes(a,b){b?$("#"+a).find("input:checkbox").attr("checked","checked"):$("#"+a).find("input:checkbox").removeAttr("checked");return true} -function setSelectOptions(a,b,c){$("form[name='"+a+"'] select[name='"+b+"']").find("option").attr("selected",c);return true}function setQuery(a){if(codemirror_editor)codemirror_editor.setValue(a);else document.sqlform.sql_query.value=a} -function insertQuery(a){if(a=="clear")setQuery("");else{var b="",c=document.sqlform.dummy,d=document.sqlform.table.value;if(c.options.length>0){sql_box_locked=true;for(var e="",g="",f="",h=0,j=0;j1){e+=", ";g+=",";f+=","}e+=c.options[j].value;g+="[value-"+h+"]";f+=c.options[j].value+"=[value-"+h+"]"}if(a=="selectall")b="SELECT * FROM `"+d+"` WHERE 1";else if(a=="select")b="SELECT "+e+" FROM `"+d+"` WHERE 1";else if(a=="insert")b="INSERT INTO `"+d+"`("+e+") VALUES ("+ -g+")";else if(a=="update")b="UPDATE `"+d+"` SET "+f+" WHERE 1";else if(a=="delete")b="DELETE FROM `"+d+"` WHERE 1";setQuery(b);sql_box_locked=false}}} -function insertValueQuery(){var a=document.sqlform.sql_query,b=document.sqlform.dummy;if(b.options.length>0){sql_box_locked=true;for(var c="",d=0,e=0;e1)c+=", ";c+=b.options[e].value}if(codemirror_editor)codemirror_editor.replaceSelection(c);else if(document.selection){a.focus();sel=document.selection.createRange();sel.text=c;document.sqlform.insert.focus()}else if(document.sqlform.sql_query.selectionStart||document.sqlform.sql_query.selectionStart== -"0"){b=document.sqlform.sql_query.selectionEnd;d=document.sqlform.sql_query.value;a.value=d.substring(0,document.sqlform.sql_query.selectionStart)+c+d.substring(b,d.length)}else a.value+=c;sql_box_locked=false}}function goToUrl(a,b){eval("document.location.href = '"+b+"pos="+a.options[a.selectedIndex].value+"'")}function refreshDragOption(a){if($("#"+a).css("visibility")=="visible"){refreshLayout();TableDragInit()}} -function refreshLayout(){var a=$("#pdflayout"),b=$("#orientation_opt").val(),c=$("#paper_opt").length==1?$("#paper_opt").val():"A4";if(b=="P"){posa="x";posb="y"}else{posa="y";posb="x"}a.css("width",pdfPaperSize(c,posa)+"px");a.css("height",pdfPaperSize(c,posb)+"px")} -function ToggleDragDrop(a){a=$("#"+a);if(a.css("visibility")=="hidden"){PDFinit();a.css("visibility","visible");a.css("display","block");$("#showwysiwyg").val("1")}else{a.css("visibility","hidden");a.css("display","none");$("#showwysiwyg").val("0")}}function dragPlace(a,b,c){a=$("#table_"+a);b=="x"?a.css("left",c+"px"):a.css("top",c+"px")} -function pdfPaperSize(a,b){switch(a.toUpperCase()){case "4A0":return b=="x"?4767.87:6740.79;case "2A0":return b=="x"?3370.39:4767.87;case "A0":return b=="x"?2383.94:3370.39;case "A1":return b=="x"?1683.78:2383.94;case "A2":return b=="x"?1190.55:1683.78;case "A3":return b=="x"?841.89:1190.55;case "A4":return b=="x"?595.28:841.89;case "A5":return b=="x"?419.53:595.28;case "A6":return b=="x"?297.64:419.53;case "A7":return b=="x"?209.76:297.64;case "A8":return b=="x"?147.4:209.76;case "A9":return b== -"x"?104.88:147.4;case "A10":return b=="x"?73.7:104.88;case "B0":return b=="x"?2834.65:4008.19;case "B1":return b=="x"?2004.09:2834.65;case "B2":return b=="x"?1417.32:2004.09;case "B3":return b=="x"?1000.63:1417.32;case "B4":return b=="x"?708.66:1000.63;case "B5":return b=="x"?498.9:708.66;case "B6":return b=="x"?354.33:498.9;case "B7":return b=="x"?249.45:354.33;case "B8":return b=="x"?175.75:249.45;case "B9":return b=="x"?124.72:175.75;case "B10":return b=="x"?87.87:124.72;case "C0":return b=="x"? -2599.37:3676.54;case "C1":return b=="x"?1836.85:2599.37;case "C2":return b=="x"?1298.27:1836.85;case "C3":return b=="x"?918.43:1298.27;case "C4":return b=="x"?649.13:918.43;case "C5":return b=="x"?459.21:649.13;case "C6":return b=="x"?323.15:459.21;case "C7":return b=="x"?229.61:323.15;case "C8":return b=="x"?161.57:229.61;case "C9":return b=="x"?113.39:161.57;case "C10":return b=="x"?79.37:113.39;case "RA0":return b=="x"?2437.8:3458.27;case "RA1":return b=="x"?1729.13:2437.8;case "RA2":return b== -"x"?1218.9:1729.13;case "RA3":return b=="x"?864.57:1218.9;case "RA4":return b=="x"?609.45:864.57;case "SRA0":return b=="x"?2551.18:3628.35;case "SRA1":return b=="x"?1814.17:2551.18;case "SRA2":return b=="x"?1275.59:1814.17;case "SRA3":return b=="x"?907.09:1275.59;case "SRA4":return b=="x"?637.8:907.09;case "LETTER":return b=="x"?612:792;case "LEGAL":return b=="x"?612:1008;case "EXECUTIVE":return b=="x"?521.86:756;case "FOLIO":return b=="x"?612:936}return 0} -function popupBSMedia(a,b,c,d,e,g){if(e==undefined)e=640;if(g==undefined)g=480;window.open("bs_play_media.php?"+a+"&bs_reference="+b+"&media_type="+c+"&custom_type="+d,"viewBSMedia","width="+e+", height="+g+", resizable=1, scrollbars=1, status=0")}function requestMIMETypeChange(a,b,c,d){if(undefined==d)d="";var e=prompt("Enter custom MIME type",d);e&&e!=d&&changeMIMEType(a,b,c,e)} -function changeMIMEType(a,b,c,d){jQuery.post("bs_change_mime_type.php",{bs_db:a,bs_table:b,bs_reference:c,bs_new_mime_type:d})} -$(document).ready(function(){$(".inline_edit_sql").live("click",function(){if($("#sql_query_edit").length)return false;var a=$(this).prev(),b=a.find("input[name='sql_query']").val(),c=$(this).parent().prev().find(".inner_sql"),d=c.html();b='\n";b+='\n';b+='\n';c.replaceWith(b);c=$("#sql_query_edit").css("height"); -codemirror_editor=CodeMirror.fromTextArea($('textarea[name="sql_query_edit"]')[0],{lineNumbers:true,matchBrackets:true,indentUnit:4,mode:"text/x-mysql",lineWrapping:true});codemirror_editor.getScrollerElement().style.height=c;codemirror_editor.refresh();$(".btnSave").click(function(){var e=codemirror_editor!==undefined?codemirror_editor.getValue():$(this).prev().val();$("
    ",{action:"import.php",method:"post"}).append(a.find("input[name=server], input[name=db], input[name=table], input[name=token]").clone()).append($("", -{type:"hidden",name:"show_query",value:1})).append($("",{type:"hidden",name:"sql_query",value:e})).appendTo($("body")).submit()});$(".btnDiscard").click(function(){$(this).closest(".sql").html(''+d+"")});return false});$(".sqlbutton").click(function(a){insertQuery(a.target.id);return false});$("#export_type").change(function(){if($("#export_type").val()=="svg"){$("#show_grid_opt").attr("disabled","disabled");$("#orientation_opt").attr("disabled", -"disabled");$("#with_doc").attr("disabled","disabled");$("#show_table_dim_opt").removeAttr("disabled");$("#all_table_same_wide").removeAttr("disabled");$("#paper_opt").removeAttr("disabled","disabled");$("#show_color_opt").removeAttr("disabled","disabled")}else if($("#export_type").val()=="dia"){$("#show_grid_opt").attr("disabled","disabled");$("#with_doc").attr("disabled","disabled");$("#show_table_dim_opt").attr("disabled","disabled");$("#all_table_same_wide").attr("disabled","disabled");$("#paper_opt").removeAttr("disabled", -"disabled");$("#show_color_opt").removeAttr("disabled","disabled");$("#orientation_opt").removeAttr("disabled","disabled")}else if($("#export_type").val()=="eps"){$("#show_grid_opt").attr("disabled","disabled");$("#orientation_opt").removeAttr("disabled");$("#with_doc").attr("disabled","disabled");$("#show_table_dim_opt").attr("disabled","disabled");$("#all_table_same_wide").attr("disabled","disabled");$("#paper_opt").attr("disabled","disabled");$("#show_color_opt").attr("disabled","disabled")}else if($("#export_type").val()== -"pdf"){$("#show_grid_opt").removeAttr("disabled");$("#orientation_opt").removeAttr("disabled");$("#with_doc").removeAttr("disabled","disabled");$("#show_table_dim_opt").removeAttr("disabled","disabled");$("#all_table_same_wide").removeAttr("disabled","disabled");$("#paper_opt").removeAttr("disabled","disabled");$("#show_color_opt").removeAttr("disabled","disabled")}});$("#sqlquery").focus().keydown(function(a){a.ctrlKey&&a.keyCode==13&&$("#sqlqueryform").submit()});if($("#input_username"))$("#input_username").val()== -""?$("#input_username").focus():$("#input_password").focus()}); -function PMA_ajaxShowMessage(a,b){var c=true,d=true;if(a=="")return true;else if(a){if(a==PMA_messages.strProcessingRequest)c=d=false}else{a=PMA_messages.strLoading;c=d=false}if(b==undefined)b=5E3;else if(b===false)c=false;$("#loading_parent").length==0&&$('
    ').prependTo("body");ajax_message_count++;$(".ajax_notification[id^=ajax_message_num]").remove();var e=$('').hide().appendTo("#loading_parent").html(a).fadeIn("medium"); -c&&e.delay(b).fadeOut("medium",function(){$(this).is(".dismissable")&&$(this).qtip("hide");$(this).remove()});if(d){e.addClass("dismissable").css("cursor","pointer");PMA_createqTip(e,PMA_messages.strDismiss,{show:{effect:{length:0},delay:0},hide:{effect:{length:0},delay:0}})}return e}function PMA_ajaxRemoveMessage(a){if(a!=undefined&&a instanceof jQuery){a.stop(true,true).fadeOut("medium");if(a.is(".dismissable"))$("#no_hint").length<0&&a.qtip("hide");else a.remove()}} -$(document).ready(function(){$(".ajax_notification.dismissable").live("click",function(){PMA_ajaxRemoveMessage($(this))});$(".ajax_notification a, .ajax_notification button, .ajax_notification input").live("mouseover",function(){$(this).parents(".ajax_notification").qtip("hide")});$(".ajax_notification a, .ajax_notification button, .ajax_notification input").live("mouseout",function(){$(this).parents(".ajax_notification").qtip("show")})}); -function PMA_showNoticeForEnum(a){var b=a.attr("id").split("_")[1];b+="_"+(parseInt(a.attr("id").split("_")[2])+1);a=a.val();a=="ENUM"||a=="SET"?$("p[id='enum_notice_"+b+"']").show():$("p[id='enum_notice_"+b+"']").hide()} -function PMA_createTableDialog(a,b,c){var d={};d[PMA_messages.strCancel]=function(){$(this).closest(".ui-dialog-content").dialog("close").remove()};var e={};e[PMA_messages.strOK]=function(){$(this).closest(".ui-dialog-content").dialog("close").remove()};var g=PMA_ajaxShowMessage();$.get(c,b,function(f){if(f.success!=undefined&&f.success==false)a.append(f.error).dialog({height:230,width:900,open:PMA_verifyColumnsProperties,buttons:e}).find("fieldset").remove();else{var h=getWindowSize(),j;a.append(f).dialog({dialogClass:"create-table", -resizable:false,draggable:false,modal:true,stack:false,position:["left","top"],width:h.width-10,height:h.height-10,open:function(){var k=$(this).attr("id");$(window).bind("resize.dialog-resizer",function(){clearTimeout(j);j=setTimeout(function(){var o=getWindowSize();$("#"+k).dialog("option",{width:o.width-10,height:o.height-10})},50)});var n=$("
    ",{id:"content-hide"}).hide();$("body > *:not(.ui-dialog)").wrapAll(n);$(this).scrollTop(0).closest(".ui-dialog").css({left:0,top:0});PMA_verifyColumnsProperties(); -n=$(".ui-dialog-buttonpane");var l=n.find(".ui-button"),m=$("#create_table_form").find("input[name='do_save_data']");l.insertAfter(m);n.hide()},close:function(){$(window).unbind("resize.dialog-resizer");$("#content-hide > *").unwrap();menuResize();menuResize()},buttons:d})}PMA_convertFootnotesToTooltips(a);PMA_ajaxRemoveMessage(g)})} -function PMA_createProfilingChartJqplot(a,b){return $.jqplot(a,[b],{seriesDefaults:{renderer:$.jqplot.PieRenderer,rendererOptions:{showDataLabels:true}},legend:{show:true,location:"e"},seriesColors:["#fce94f","#fcaf3e","#e9b96e","#8ae234","#729fcf","#ad7fa8","#ef2929","#eeeeec","#888a85","#c4a000","#ce5c00","#8f5902","#4e9a06","#204a87","#5c3566","#a40000","#babdb6","#2e3436"]})} -function PMA_prettyProfilingNum(a,b){b||(b=2);b=Math.pow(10,b);a=a*1E3<0.1?Math.round(b*a*1E3*1E3)/b+"\u00b5":a<0.1?Math.round(b*a*1E3)/b+"m":Math.round(b*a)/b;return a+"s"} -function PMA_SQLPrettyPrint(a){for(var b=CodeMirror.getMode({},"text/x-mysql"),c=new CodeMirror.StringStream(a),d=b.startState(),e,g=[],f="",h=function(o){for(var p="",q=0;q<4*o;q++)p+=" ";return p},j={select:["select","from","on","where","having","limit","order by","group by"],update:["update","set","where"],"insert into":["insert into","values"]},k={";":true,",":true,".":true,"(":true},n={".":true};!c.eol();){c.start=c.pos;e=b.token(c,d);e!=null&&g.push([e,c.current().toLowerCase()])}b=g[0][1]; -if(!j[b])return a;a=[];var l,m;c=0;d=j[b][0];a.unshift("statement");for(e=0;e0&&g[e-1][0]=="builtin"?a.unshift(l="function"):a.unshift(l="generic");else l=null;if(g[e][1]==")"){m=a[0];a.shift()}else m=null;if(e>0&&l=="statement"){c++;f+="\n"+h(c)+g[e][1]+" "+g[e+1][1].toUpperCase()+"\n"+h(c+1);b=g[e+1][1];e++}else{if(m=="statement"&&c>0){f+="\n"+h(c);c--}m=j[b].indexOf(g[e][1]);if(m!=-1){if(e> -0)f+="\n";f+=h(c)+g[e][1].toUpperCase();f+="\n"+h(c+1);d=g[e][1]}else{if(!k[g[e][1]]&&!(e>0&&n[g[e-1][1]])&&f.charAt(f.length-1)!=" ")f+=" ";f+=g[e][0]=="keyword"?g[e][1].toUpperCase():g[e][1]}if((d=="select"||d=="where"||d=="set")&&g[e][1]==","&&a[0]=="statement")f+="\n"+h(c+1);if(d=="where"&&(g[e][1]=="and"||g[e][1]=="or"||g[e][1]=="xor"))if(a[0]=="statement")f+="\n"+h(c+1)}}return f} -jQuery.fn.PMA_confirm=function(a,b,c){if(PMA_messages.strDoYouReally=="")return true;var d={};d[PMA_messages.strOK]=function(){$(this).dialog("close").remove();$.isFunction(c)&&c.call(this,b)};d[PMA_messages.strCancel]=function(){$(this).dialog("close").remove()};$('
    ').prepend(a).dialog({buttons:d})}; -jQuery.fn.PMA_sort_table=function(a){return this.each(function(){var b=$(this),c=$(this).find("tr").get();$.each(c,function(d,e){e.sortKey=$.trim($(e).find(a).text().toLowerCase())});c.sort(function(d,e){if(d.sortKeye.sortKey)return 1;return 0});$.each(c,function(d,e){$(b).append(e);e.sortKey=null});$(this).find("tr:odd").removeClass("even").addClass("odd").end().find("tr:even").removeClass("odd").addClass("even")})}; -$(document).ready(function(){$("#create_table_form_minimal.ajax").live("submit",function(a){a.preventDefault();$form=$(this);PMA_prepareForAjaxRequest($form);a=$form.serialize();var b=$form.attr("action"),c=$('
    ');PMA_createTableDialog(c,a,b);$form.find("input[name=table],input[name=num_fields]").val("")});$("#create_table_form input[name=do_save_data]").live("click",function(a){a.preventDefault();a=$("#create_table_form");if(checkTableEditForm(a[0],a.find("input[name=orig_num_fields]").val()))if(a.hasClass("ajax")){PMA_ajaxShowMessage(PMA_messages.strProcessingRequest); -PMA_prepareForAjaxRequest(a);$.post(a.attr("action"),a.serialize()+"&do_save_data="+$(this).val(),function(b){if(b.success==true){$("#properties_message").removeClass("error").html("");PMA_ajaxShowMessage(b.message);$("#create_table_dialog").length>0&&$("#create_table_dialog").dialog("close").remove();var c=$("#tablesForm").find("tbody").not("#tbl_summary_row");if(c.length==0)window.parent&&window.parent.frame_content&&window.parent.frame_content.location.reload();else{var d=$(c).find("tr:last"); -d=$(d).find("input:checkbox").attr("id").match(/\d+/)[0];d="checkbox_tbl_"+(parseFloat(d)+1);b.new_table_string=b.new_table_string.replace(/checkbox_tbl_/,d);$(b.new_table_string).appendTo(c);$(c).PMA_sort_table("th");PMA_adjustTotals()}window.parent&&window.parent.frame_navigation&&window.parent.frame_navigation.location.reload()}else{$("#properties_message").addClass("error").html(b.error);$("#properties_message")[0].scrollIntoView()}})}else{a.append(''); -a.submit()}});$("#create_table_form.ajax input[name=submit_num_fields]").live("click",function(a){a.preventDefault();a=$("#create_table_form");var b=PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);PMA_prepareForAjaxRequest(a);$.post(a.attr("action"),a.serialize()+"&submit_num_fields="+$(this).val(),function(c){$("#create_table_dialog").length>0&&$("#create_table_dialog").html(c);$("#create_table_div").length>0&&$("#create_table_div").html(c);PMA_verifyColumnsProperties();PMA_ajaxRemoveMessage(b)})})}, -"top.frame_content"); -$(document).ready(function(){$("#alterTableOrderby.ajax").live("submit",function(a){a.preventDefault();a=$(this);PMA_prepareForAjaxRequest(a);$.post(a.attr("action"),a.serialize()+"&submitorderby=Go",function(b){$("#sqlqueryresults").length!=0&&$("#sqlqueryresults").remove();$("#result_query").length!=0&&$("#result_query").remove();if(b.success==true){PMA_ajaxShowMessage(b.message);$("
    ").insertAfter("#floating_menubar");$("#sqlqueryresults").html(b.sql_query);$("#result_query .notice").remove(); -$("#result_query").prepend(b.message)}else{var c=$("
    ");c.html(b.error);b=c.find("code").addClass("error");PMA_ajaxShowMessage(b,false)}})});$("#copyTable.ajax input[name='submit_copy']").live("click",function(a){a.preventDefault();a=$("#copyTable");if(a.find("input[name='switch_to_new']").attr("checked")){a.append('');a.removeClass("ajax");a.find("#ajax_request_hidden").remove();a.submit()}else{PMA_prepareForAjaxRequest(a); -$.post(a.attr("action"),a.serialize()+"&submit_copy=Go",function(b){$("#sqlqueryresults").length!=0&&$("#sqlqueryresults").remove();$("#result_query").length!=0&&$("#result_query").remove();if(b.success==true){PMA_ajaxShowMessage(b.message);$("
    ").insertAfter("#floating_menubar");$("#sqlqueryresults").html(b.sql_query);$("#result_query .notice").remove();$("#result_query").prepend(b.message);$("#copyTable").find("select[name='target_db'] option").filterByValue(b.db).attr("selected", -"selected");window.parent&&window.parent.frame_navigation&&window.parent.frame_navigation.location.reload()}else{var c=$("
    ");c.html(b.error);b=c.find("code").addClass("error");PMA_ajaxShowMessage(b,false)}})}});$("#tbl_maintenance.ajax li a.maintain_action").live("click",function(a){a.preventDefault();a=$(this).attr("href");a=a.split("?");$("#sqlqueryresults").length!=0&&$("#sqlqueryresults").remove();$("#result_query").length!=0&&$("#result_query").remove();$.post(a[0],a[1]+ -"&ajax_request=true",function(b){if(b.success==undefined){var c=$("
    ");c.html(b);c=c.find("#result_query .success");PMA_ajaxShowMessage(c);$("
    ").insertAfter("#floating_menubar");$("#sqlqueryresults").html(b);PMA_init_slider();$("#sqlqueryresults").children("fieldset").remove()}else if(b.success==true){PMA_ajaxShowMessage(b.message);$("
    ").insertAfter("#floating_menubar");$("#sqlqueryresults").html(b.sql_query)}else{c= -$("
    ");c.html(b.error);b=c.find("code").addClass("error");PMA_ajaxShowMessage(b,false)}})})},"top.frame_content"); -$(document).ready(function(){$("#drop_db_anchor").live("click",function(a){a.preventDefault();a=PMA_messages.strDropDatabaseStrongWarning+"\n"+PMA_messages.strDoYouReally+" :\nDROP DATABASE "+escapeHtml(window.parent.db);$(this).PMA_confirm(a,$(this).attr("href"),function(b){PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);$.get(b,{is_js_confirmed:"1",ajax_request:true},function(){window.parent.refreshNavigation();window.parent.refreshMain()})})})}); -$(document).ready(function(){$("#create_database_form.ajax").live("submit",function(a){a.preventDefault();$form=$(this);PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);PMA_prepareForAjaxRequest($form);$.post($form.attr("action"),$form.serialize(),function(b){if(b.success==true){PMA_ajaxShowMessage(b.message);$("#tabledatabases").find("tbody").append(b.new_db_string).PMA_sort_table(".name").find("#db_summary_row").appendTo("#tabledatabases tbody").removeClass("odd even");b=$("#databases_count"); -var c=parseInt(b.text());b.text(++c);window.parent&&window.parent.frame_navigation&&window.parent.frame_navigation.location.reload()}else PMA_ajaxShowMessage(b.error,false)})})}); -function checkPassword(a){if(typeof a.elements.nopass!="undefined"&&a.elements.nopass[0].checked)return true;else if(typeof a.elements.pred_password!="undefined"&&(a.elements.pred_password.value=="none"||a.elements.pred_password.value=="keep"))return true;var b=a.elements.pma_pw;a=a.elements.pma_pw2;var c=false;if(b.value=="")c=PMA_messages.strPasswordEmpty;else if(b.value!=a.value)c=PMA_messages.strPasswordNotSame;if(c){alert(c);b.value="";a.value="";b.focus();return false}return true} -$(document).ready(function(){$("#change_password_anchor.dialog_active").live("click",function(a){a.preventDefault();return false});$("#change_password_anchor.ajax").live("click",function(a){a.preventDefault();$(this).removeClass("ajax").addClass("dialog_active");var b={};b[PMA_messages.strCancel]=function(){$(this).dialog("close").remove()};$.get($(this).attr("href"),{ajax_request:true},function(c){$('
    ').dialog({title:PMA_messages.strChangePassword,width:600, -close:function(){$(this).remove()},buttons:b,beforeClose:function(){$("#change_password_anchor.dialog_active").removeClass("dialog_active").addClass("ajax")}}).append(c);displayPasswordGenerateButton();$("#change_password_form").bind("submit",function(d){d.preventDefault();$(this).closest(".ui-dialog").find(".ui-dialog-buttonpane .ui-button").first().click()})})});$("#change_password_form.ajax").find("input[name=change_pw]").live("click",function(a){a.preventDefault();a=$("#change_password_form"); -if(!checkPassword(a[0]))return false;var b=$(this).val(),c=PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);$(a).append('');$.post($(a).attr("action"),$(a).serialize()+"&change_pw="+b,function(d){if(d.success==true){$("#floating_menubar").after(d.sql_query);$("#change_password_dialog").hide().remove();$("#edit_user_dialog").dialog("close").remove();$("#change_password_anchor.dialog_active").removeClass("dialog_active").addClass("ajax"); -PMA_ajaxRemoveMessage(c)}else PMA_ajaxShowMessage(d.error,false)})})});$(document).ready(function(){PMA_verifyColumnsProperties();$("select[class='column_type']").live("change",function(){PMA_showNoticeForEnum($(this))});$(".default_type").live("change",function(){PMA_hideShowDefaultValue($(this))})});function PMA_verifyColumnsProperties(){$("select[class='column_type']").each(function(){PMA_showNoticeForEnum($(this))});$(".default_type").each(function(){PMA_hideShowDefaultValue($(this))})} -function PMA_hideShowDefaultValue(a){a.val()=="USER_DEFINED"?a.siblings(".default_value").show().focus():a.siblings(".default_value").hide()}var $enum_editor_dialog=null; -$(document).ready(function(){$("a.open_enum_editor").live("click",function(){var a=$(this).closest("tr").find("input:first").val();a=a.length<1?PMA_messages.enum_newColumnVals:PMA_messages.enum_columnVals.replace(/%s/,'"'+decodeURIComponent(a)+'"');var b=$(this).closest("td").find("input").val();b=$("
    ").text(b).html();for(var c=[],d=false,e,g,f="",h=0;h0&&c.push(f);b="";c.length==0&&c.push("","","","");d=PMA_getImage("b_drop.png");for(h=0;h"+d+"";a="
    "+a+"

    "+PMA_getImage("s_notice.png")+PMA_messages.enum_hint+"

    "+b+"
    ";c={};c[PMA_messages.strGo]=function(){var j=[];$(this).find(".values input").each(function(n,l){var m=l.value.replace(/\\/g,"\\\\").replace(/'/g,"''");j.push("'"+m+"'")});var k=$(this).find("input[type='hidden']").attr("value");$("input[id='"+k+"']").attr("value",j.join(","));$(this).dialog("close")};c[PMA_messages.strClose]=function(){$(this).dialog("close")}; -(h=parseInt(parseInt($("html").css("font-size"),10)/13*340,10))||(h=340);$enum_editor_dialog=$(a).dialog({minWidth:h,modal:true,title:PMA_messages.enum_editor,buttons:c,open:function(){$(this).closest(".ui-dialog").find(".ui-dialog-buttonpane button:first").focus()},close:function(){$(this).remove()}});$enum_editor_dialog.find(".slider").slider({animate:true,range:"min",value:1,min:1,max:9,slide:function(j,k){$(this).closest("table").find("input[type=submit]").val(PMA_messages.enum_addValue.replace(/%d/, -k.value))}});$(".ui-slider-handle").addClass("ui-state-focus");return false});$("input.add_value").live("click",function(a){a.preventDefault();for(a=$enum_editor_dialog.find("div.slider").slider("value");a--;)$enum_editor_dialog.find(".values").append(""+PMA_getImage("b_drop.png")+"").find("tr:last").show("fast")});$("#enum_editor td.drop").live("click",function(){$(this).closest("tr").hide("fast",function(){$(this).remove()})})}); -$(document).ready(function(){PMA_convertFootnotesToTooltips()});function checkIndexName(a){if($("#"+a).length==0)return false;a=$("#input_index_name");if($("#select_index_type").find("option:selected").attr("value")=="PRIMARY"){a.attr("value","PRIMARY");a.attr("disabled",true)}else{a.attr("value")=="PRIMARY"&&a.attr("value","");a.attr("disabled",false)}return true} -function PMA_convertFootnotesToTooltips(a){if(a==undefined||!a instanceof jQuery||a.length==0)a=$("body");$footnotes=a.find(".footnotes");$footnotes.hide();$footnotes.find("span").each(function(){$(this).children("sup").remove()});$footnotes.css("border","none");$footnotes.css("padding","0px");a.find("sup.footnotemarker").hide();a.find("img.footnotemarker").show();a.find("img.footnotemarker").each(function(){var b=$(this).attr("class");b=b.split(" ");for(i=0;i li"),f=e.find("li"),h=f.length>0,j=h?d:0,k=0;k=b&&--k>=0;){n=true;var l=$(g[k]),m=l.outerWidth(true);l.data("width",m);if(h){j-=m;l.prependTo(e)}else{j-=m;l.prependTo(e);j+=d;h=true}}if(!n)for(k=0;k -0?c.addClass("shown"):c.removeClass("shown");a.find("> li").length==1?e.removeClass().addClass("only"):e.removeClass().addClass("notonly");c.find(".tabactive").length?c.addClass("active").find("> a").removeClass("tab").addClass("tabactive"):c.removeClass("active").find("> a").addClass("tab").removeClass("tabactive")} -$(function(){var a=$("#topmenu");if(a.length!=0){var b=$("",{href:"#","class":"tab"}).text(PMA_messages.strMore).click(function(c){c.preventDefault()});a.find("li:first-child img").length&&$(PMA_getImage("b_more.png").toString()).prependTo(b);b=$("
  • ",{"class":"submenu"}).append(b).append($("
  • '; - $r = '
    '; - $r .= '' . __('Indexes'); - $r .= PMA_showMySQLDocu('optimization', 'optimizing-database-structure'); - $r .= ''; - $r .= $no_indexes; - if (count($indexes) < 1) { - $r .= '
    '; - return $r; - } if (! $print_mode) { + $r = '
    '; + $r .= '' . __('Indexes'); + $r .= PMA_Util::showMySQLDocu('optimizing-database-structure'); + + $r .= ''; + $r .= $no_indexes; + if (count($indexes) < 1) { + $r .= '
    '; + return $r; + } $r .= PMA_Index::findDuplicates($table, $schema); + } else { + $r = '

    ' . __('Indexes') . '

    '; + $r .= $no_indexes; + if (count($indexes) < 1) { + return $r; + } } $r .= ''; $r .= ''; @@ -445,7 +568,9 @@ static public function getView($table, $schema, $print_mode = false) $r .= ''; $r .= ''; $r .= ''; - $r .= ''; + if (PMA_MYSQL_INT_VERSION > 50500) { + $r .= ''; + } $r .= ''; $r .= ''; $r .= ''; @@ -459,40 +584,62 @@ static public function getView($table, $schema, $print_mode = false) if (! $print_mode) { $this_params = $GLOBALS['url_params']; $this_params['index'] = $index->getName(); - $r .= '' . "\n"; - $this_params = $GLOBALS['url_params']; if ($index->getName() == 'PRIMARY') { - $this_params['sql_query'] = 'ALTER TABLE ' . PMA_backquote($table) . ' DROP PRIMARY KEY'; - $this_params['message_to_show'] = __('The primary key has been dropped'); - $js_msg = PMA_jsFormat('ALTER TABLE ' . $table . ' DROP PRIMARY KEY'); + $this_params['sql_query'] = 'ALTER TABLE ' + . PMA_Util::backquote($table) + . ' DROP PRIMARY KEY;'; + $this_params['message_to_show'] + = __('The primary key has been dropped'); + $js_msg = PMA_jsFormat( + 'ALTER TABLE ' . $table . ' DROP PRIMARY KEY' + ); } else { - $this_params['sql_query'] = 'ALTER TABLE ' . PMA_backquote($table) . ' DROP INDEX ' . PMA_backquote($index->getName()); - $this_params['message_to_show'] = sprintf(__('Index %s has been dropped'), $index->getName()); - $js_msg = PMA_jsFormat('ALTER TABLE ' . $table . ' DROP INDEX ' . $index->getName()); + $this_params['sql_query'] = 'ALTER TABLE ' + . PMA_Util::backquote($table) . ' DROP INDEX ' + . PMA_Util::backquote($index->getName()) . ';'; + $this_params['message_to_show'] = sprintf( + __('Index %s has been dropped.'), $index->getName() + ); + + $js_msg = PMA_jsFormat( + 'ALTER TABLE ' . $table . ' DROP INDEX ' + . $index->getName() . ';' + ); + } $r .= '' . "\n"; } - $r .= ''; - $r .= ''; + if (! $print_mode) { + $r .= ''; + } else { + $r .= ''; + } + $r .= ''; $r .= ''; $r .= ''; @@ -505,11 +652,19 @@ static public function getView($table, $schema, $print_mode = false) $r .= ' (' . $column->getSubPart() . ')'; } $r .= ''; - $r .= ''; - $r .= ''; - $r .= ''; - - if ($column->getSeqInIndex() == 1) { + $r .= ''; + $r .= ''; + $r .= ''; + + if (PMA_MYSQL_INT_VERSION > 50500 + && $column->getSeqInIndex() == 1 + ) { $r .= ''; } @@ -520,11 +675,18 @@ static public function getView($table, $schema, $print_mode = false) } // end while $r .= ''; $r .= '
    ' . __('Cardinality') . '' . __('Collation') . '' . __('Null') . '' . __('Comment') . '' . __('Comment') . '
    ' - . ' ' . PMA_getIcon('b_edit.png', __('Edit')) . '' + . ' ' . PMA_Util::getIcon('b_edit.png', __('Edit')) . '' . ''; - $r .= ''; - $r .= ' '; + $r .= ' ' - . PMA_getIcon('b_drop.png', __('Drop')) . '' + . PMA_Util::getIcon('b_drop.png', __('Drop')) . '' . '' . htmlspecialchars($index->getName()) . '' . htmlspecialchars($index->getType()) . '' + . htmlspecialchars($index->getName()) + . '' + . htmlspecialchars($index->getName()) + . '' + . htmlspecialchars($index->getType()) + . '' . $index->isUnique(true) . '' . $index->isPacked(true) . '' . htmlspecialchars($column->getCardinality()) . '' . htmlspecialchars($column->getCollation()) . '' . htmlspecialchars($column->getNull(true)) . '' + . htmlspecialchars($column->getCardinality()) + . '' + . htmlspecialchars($column->getCollation()) + . '' + . htmlspecialchars($column->getNull(true)) + . '' . htmlspecialchars($index->getComments()) . '
    '; - $r .= ''; + if (! $print_mode) { + $r .= ''; + } return $r; } + /** + * Gets the properties in an array for comparison purposes + * + * @return array an array containing the properties of the index + */ public function getCompareData() { $data = array( @@ -543,9 +705,11 @@ public function getCompareData() /** * Function to check over array of indexes and look for common problems * + * @param string $table table name + * @param string $schema schema name + * + * @return string Output HTML * @access public - * @param string name of table - * @return string Output HTML */ static public function findDuplicates($table, $schema) { @@ -570,7 +734,9 @@ static public function findDuplicates($table, $schema) // did not find any difference // so it makes no sense to have this two equal indexes - $message = PMA_Message::notice(__('The indexes %1$s and %2$s seem to be equal and one of them could possibly be removed.')); + $message = PMA_Message::notice( + __('The indexes %1$s and %2$s seem to be equal and one of them could possibly be removed.') + ); $message->addParam($each_index->getName()); $message->addParam($while_index->getName()); $output .= $message->getDisplay(); @@ -585,6 +751,8 @@ static public function findDuplicates($table, $schema) } /** + * Index column wrapper + * * @package PhpMyAdmin */ class PMA_Index_Column @@ -592,17 +760,18 @@ class PMA_Index_Column /** * @var string The column name */ - protected $_name = ''; + private $_name = ''; /** * @var integer The column sequence number in the index, starting with 1. */ - protected $_seq_in_index = 1; + private $_seq_in_index = 1; /** - * @var string How the column is sorted in the index. “A†(Ascending) or NULL (Not sorted) + * @var string How the column is sorted in the index. “A†(Ascending) or + * NULL (Not sorted) */ - protected $_collation = null; + private $_collation = null; /** * The number of indexed characters if the column is only partly indexed, @@ -610,7 +779,7 @@ class PMA_Index_Column * * @var integer */ - protected $_sub_part = null; + private $_sub_part = null; /** * Contains YES if the column may contain NULL. @@ -618,7 +787,7 @@ class PMA_Index_Column * * @var string */ - protected $_null = ''; + private $_null = ''; /** * An estimate of the number of unique values in the index. This is updated @@ -629,13 +798,25 @@ class PMA_Index_Column * * @var integer */ - protected $_cardinality = null; + private $_cardinality = null; + /** + * Constructor + * + * @param array $params an array containing the parameters of the index column + */ public function __construct($params = array()) { $this->set($params); } + /** + * Sets parameters of the index column + * + * @param array $params an array containing the parameters of the index column + * + * @return void + */ public function set($params) { if (isset($params['Column_name'])) { @@ -658,21 +839,44 @@ public function set($params) } } + /** + * Returns the column name + * + * @return string column name + */ public function getName() { return $this->_name; } + /** + * Return the column collation + * + * @return string column collation + */ public function getCollation() { return $this->_collation; } + /** + * Returns the cardinality of the column + * + * @return int cardinality of the column + */ public function getCardinality() { return $this->_cardinality; } + /** + * Returns whether the column is nullable + * + * @param boolean $as_text whether to returned the string representation + * + * @return mixed nullability of the column. True/false or Yes/No depending + * on the value of the $as_text parameter + */ public function getNull($as_text = false) { return $as_text @@ -680,16 +884,32 @@ public function getNull($as_text = false) : $this->_null; } + /** + * Returns the sequence number of the column in the index + * + * @return int sequence number of the column in the index + */ public function getSeqInIndex() { return $this->_seq_in_index; } + /** + * Returns the number of indexed characters if the column is only + * partly indexed + * + * @return int the number of indexed characters + */ public function getSubPart() { return $this->_sub_part; } + /** + * Gets the properties in an array for comparison purposes + * + * @return array an array containing the properties of the index column + */ public function getCompareData() { return array( diff --git a/phpMyAdmin/libraries/List.class.php b/phpMyAdmin/libraries/List.class.php index 661073b..eb40b86 100644 --- a/phpMyAdmin/libraries/List.class.php +++ b/phpMyAdmin/libraries/List.class.php @@ -5,12 +5,17 @@ * * @package PhpMyAdmin */ +if (! defined('PHPMYADMIN')) { + exit; +} /** + * Generic list class + * * @todo add caching - * @since phpMyAdmin 2.9.10 * @abstract * @package PhpMyAdmin + * @since phpMyAdmin 2.9.10 */ abstract class PMA_List extends ArrayObject { @@ -19,15 +24,23 @@ abstract class PMA_List extends ArrayObject */ protected $item_empty = ''; - public function __construct($array = array(), $flags = 0, $iterator_class = "ArrayIterator") - { + /** + * PMA_List constructor + * + * @param array $array The input parameter accepts an array or an Object. + * @param int $flags Flags to control the behaviour of the ArrayObject object. + * @param string $iterator_class Specify the class that will be used for iteration of the ArrayObject object. ArrayIterator is the default class used. + */ + public function __construct( + $array = array(), $flags = 0, $iterator_class = "ArrayIterator" + ) { parent::__construct($array, $flags, $iterator_class); } /** * returns item only if there is only one in the list * - * @return single item + * @return PMA_List single item */ public function getSingleItem() { @@ -41,7 +54,7 @@ public function getSingleItem() /** * defines what is an empty item (0, '', false or null) * - * @return mixed an empty item + * @return mixed an empty item */ public function getEmpty() { @@ -52,8 +65,7 @@ public function getEmpty() * checks if the given db names exists in the current list, if there is * missing at least one item it returns false otherwise true * - * @param string $db_name,.. one or more mysql result resources - * @return boolean true if all items exists, otheriwse false + * @return boolean true if all items exists, otheriwse false */ public function exists() { @@ -70,12 +82,15 @@ public function exists() /** * returns HTML
    * * more advanced usage example: @@ -27,15 +27,15 @@ * $message = PMA_Message::success('strSomeLocaleMessage'); * * // create another message, a hint, with a localized string which expects - * // two parameters: $strSomeFootnote = 'Read the %smanual%s' - * $hint = PMA_Message::notice('strSomeFootnote'); - * // replace %d with the following params - * $hint->addParam('[a@./Documentation.html#cfg_Example@_blank]'); - * $hint->addParam('[/a]'); - * // add this hint as a footnote - * $hint = PMA_showHint($hint); + * // two parameters: $strSomeTooltip = 'Read the %smanual%s' + * $hint = PMA_Message::notice('strSomeTooltip'); + * // replace placeholders with the following params + * $hint->addParam('[doc@cfg_Example]'); + * $hint->addParam('[/doc]'); + * // add this hint as a tooltip + * $hint = showHint($hint); * - * // add the retrieved footnote reference to the original message + * // add the retrieved tooltip reference to the original message * $message->addMessage($hint); * * // create another message ... @@ -54,6 +54,7 @@ * // strSomeLocaleMessage 1 strSomeMoreLocale
    * // strSomeEvenMoreLocale - some final words *
    + * * @package PhpMyAdmin */ class PMA_Message @@ -84,7 +85,7 @@ class PMA_Message * @access protected * @var integer */ - protected $_number = PMA_Message::NOTICE; + protected $number = PMA_Message::NOTICE; /** * The locale string identifier @@ -92,7 +93,7 @@ class PMA_Message * @access protected * @var string */ - protected $_string = ''; + protected $string = ''; /** * The formatted message @@ -100,7 +101,7 @@ class PMA_Message * @access protected * @var string */ - protected $_message = ''; + protected $message = ''; /** * Whether the message was already displayed @@ -108,7 +109,7 @@ class PMA_Message * @access protected * @var boolean */ - protected $_is_displayed = false; + protected $isDisplayed = false; /** * Unique id @@ -116,7 +117,7 @@ class PMA_Message * @access protected * @var string */ - protected $_hash = null; + protected $hash = null; /** * holds parameters @@ -124,7 +125,7 @@ class PMA_Message * @access protected * @var array */ - protected $_params = array(); + protected $params = array(); /** * holds additional messages @@ -132,19 +133,20 @@ class PMA_Message * @access protected * @var array */ - protected $_added_messages = array(); + protected $addedMessages = array(); /** * Constructor * - * @param string $string - * @param integer $number - * @param array $params - * @param integer $sanitize + * @param string $string The message to be displayed + * @param integer $number A numeric representation of the type of message + * @param array $params An array of parameters to use in the message + * @param integer $sanitize A flag to indicate what to sanitize, see + * constant definitions above */ public function __construct($string = '', $number = PMA_Message::NOTICE, - $params = array(), $sanitize = PMA_Message::SANITIZE_NONE) - { + $params = array(), $sanitize = PMA_Message::SANITIZE_NONE + ) { $this->setString($string, $sanitize & PMA_Message::SANITIZE_STRING); $this->setNumber($number); $this->setParams($params, $sanitize & PMA_Message::SANITIZE_PARAMS); @@ -165,9 +167,12 @@ public function __toString() * * shorthand for getting a simple success message * + * @param string $string A localized string + * e.g. __('Your SQL query has been + * executed successfully') + * + * @return PMA_Message * @static - * @param string $string a localized string e.g. __('Your SQL query has been executed successfully') - * @return PMA_Message */ static public function success($string = '') { @@ -183,9 +188,10 @@ static public function success($string = '') * * shorthand for getting a simple error message * + * @param string $string A localized string e.g. __('Error') + * + * @return PMA_Message * @static - * @param string $string a localized string e.g. __('Error') - * @return PMA_Message */ static public function error($string = '') { @@ -201,9 +207,13 @@ static public function error($string = '') * * shorthand for getting a simple notice message * + * @param string $string A localized string + * e.g. __('The additional features for working with + * linked tables have been deactivated. To find out + * why click %shere%s.') + * + * @return PMA_Message * @static - * @param string $string a localized string e.g. __('The additional features for working with linked tables have been deactivated. To find out why click %shere%s.') - * @return PMA_Message */ static public function notice($string) { @@ -215,10 +225,11 @@ static public function notice($string) * * shorthand for getting a customized message * + * @param string $message A localized string + * @param integer $type A numeric representation of the type of message + * + * @return PMA_Message * @static - * @param string $message - * @param integer $type - * @return PMA_Message */ static public function raw($message, $type = PMA_Message::NOTICE) { @@ -232,13 +243,16 @@ static public function raw($message, $type = PMA_Message::NOTICE) * * shorthand for getting a customized message * + * @param integer $rows Number of rows + * + * @return PMA_Message * @static - * @param integer $rows Number of rows - * @return PMA_Message */ - static public function affected_rows($rows) + static public function getMessageForAffectedRows($rows) { - $message = PMA_Message::success(_ngettext('%1$d row affected.', '%1$d rows affected.', $rows)); + $message = PMA_Message::success( + _ngettext('%1$d row affected.', '%1$d rows affected.', $rows) + ); $message->addParam($rows); return $message; } @@ -248,13 +262,16 @@ static public function affected_rows($rows) * * shorthand for getting a customized message * + * @param integer $rows Number of rows + * + * @return PMA_Message * @static - * @param integer $rows Number of rows - * @return PMA_Message */ - static public function deleted_rows($rows) + static public function getMessageForDeletedRows($rows) { - $message = PMA_Message::success(_ngettext('%1$d row deleted.', '%1$d rows deleted.', $rows)); + $message = PMA_Message::success( + _ngettext('%1$d row deleted.', '%1$d rows deleted.', $rows) + ); $message->addParam($rows); return $message; } @@ -264,13 +281,16 @@ static public function deleted_rows($rows) * * shorthand for getting a customized message * + * @param integer $rows Number of rows + * + * @return PMA_Message * @static - * @param integer $rows Number of rows - * @return PMA_Message */ - static public function inserted_rows($rows) + static public function getMessageForInsertedRows($rows) { - $message = PMA_Message::success(_ngettext('%1$d row inserted.', '%1$d rows inserted.', $rows)); + $message = PMA_Message::success( + _ngettext('%1$d row inserted.', '%1$d rows inserted.', $rows) + ); $message->addParam($rows); return $message; } @@ -280,9 +300,10 @@ static public function inserted_rows($rows) * * shorthand for getting a customized error message * + * @param string $message A localized string + * + * @return PMA_Message * @static - * @param string $message - * @return PMA_Message */ static public function rawError($message) { @@ -294,9 +315,10 @@ static public function rawError($message) * * shorthand for getting a customized notice message * + * @param string $message A localized string + * + * @return PMA_Message * @static - * @param string $message - * @return PMA_Message */ static public function rawNotice($message) { @@ -308,9 +330,10 @@ static public function rawNotice($message) * * shorthand for getting a customized success message * + * @param string $message A localized string + * + * @return PMA_Message * @static - * @param string $message - * @return PMA_Message */ static public function rawSuccess($message) { @@ -321,8 +344,9 @@ static public function rawSuccess($message) * returns whether this message is a success message or not * and optionaly makes this message a success message * - * @param boolean $set - * @return boolean whether this is a success message or not + * @param boolean $set Whether to make this message of SUCCESS type + * + * @return boolean whether this is a success message or not */ public function isSuccess($set = false) { @@ -337,8 +361,9 @@ public function isSuccess($set = false) * returns whether this message is a notice message or not * and optionally makes this message a notice message * - * @param boolean $set - * @return boolean whether this is a notice message or not + * @param boolean $set Whether to make this message of NOTICE type + * + * @return boolean whether this is a notice message or not */ public function isNotice($set = false) { @@ -353,8 +378,9 @@ public function isNotice($set = false) * returns whether this message is an error message or not * and optionally makes this message an error message * - * @param boolean $set - * @return boolean whether this is an error message or not + * @param boolean $set Whether to make this message of ERROR type + * + * @return boolean Whether this is an error message or not */ public function isError($set = false) { @@ -368,39 +394,45 @@ public function isError($set = false) /** * set raw message (overrides string) * - * @param string $message - * @param boolean $sanitize whether to sanitize $message or not + * @param string $message A localized string + * @param boolean $sanitize Whether to sanitize $message or not + * + * @return void */ public function setMessage($message, $sanitize = false) { if ($sanitize) { $message = PMA_Message::sanitize($message); } - $this->_message = $message; + $this->message = $message; } /** * set string (does not take effect if raw message is set) * - * @param string $_string + * @param string $string string to set * @param boolean $sanitize whether to sanitize $string or not + * + * @return void */ - public function setString($_string, $sanitize = true) + public function setString($string, $sanitize = true) { if ($sanitize) { - $_string = PMA_Message::sanitize($_string); + $string = PMA_Message::sanitize($string); } - $this->_string = $_string; + $this->string = $string; } /** * set message type number * - * @param integer $number + * @param integer $number message type number to set + * + * @return void */ public function setNumber($number) { - $this->_number = $number; + $this->number = $number; } /** @@ -413,37 +445,44 @@ public function setNumber($number) * $message->addParam('', false); * * - * @param mixed $param - * @param boolean $raw + * @param mixed $param parameter to add + * @param boolean $raw whether parameter should be passed as is + * without html escaping + * + * @return void */ public function addParam($param, $raw = true) { if ($param instanceof PMA_Message) { - $this->_params[] = $param; + $this->params[] = $param; } elseif ($raw) { - $this->_params[] = htmlspecialchars($param); + $this->params[] = htmlspecialchars($param); } else { - $this->_params[] = PMA_Message::notice($param); + $this->params[] = PMA_Message::notice($param); } } /** * add another string to be concatenated on displaying * - * @param string $string to be added - * @param string $separator to use between this and previous string/message + * @param string $string to be added + * @param string $separator to use between this and previous string/message + * + * @return void */ public function addString($string, $separator = ' ') { - $this->_added_messages[] = $separator; - $this->_added_messages[] = PMA_Message::notice($string); + $this->addedMessages[] = $separator; + $this->addedMessages[] = PMA_Message::notice($string); } /** * add a bunch of messages at once * - * @param array $messages to be added - * @param string $separator to use between this and previous string/message + * @param array $messages to be added + * @param string $separator to use between this and previous string/message + * + * @return void */ public function addMessages($messages, $separator = ' ') { @@ -455,34 +494,38 @@ public function addMessages($messages, $separator = ' ') /** * add another raw message to be concatenated on displaying * - * @param mixed $message to be added - * @param string $separator to use between this and previous string/message + * @param mixed $message to be added + * @param string $separator to use between this and previous string/message + * + * @return void */ public function addMessage($message, $separator = ' ') { if (strlen($separator)) { - $this->_added_messages[] = $separator; + $this->addedMessages[] = $separator; } if ($message instanceof PMA_Message) { - $this->_added_messages[] = $message; + $this->addedMessages[] = $message; } else { - $this->_added_messages[] = PMA_Message::rawNotice($message); + $this->addedMessages[] = PMA_Message::rawNotice($message); } } /** * set all params at once, usually used in conjunction with string * - * @param array $params - * @param boolean $sanitize + * @param array $params parameters to set + * @param boolean $sanitize whether to sanitize params + * + * @return void */ public function setParams($params, $sanitize = false) { if ($sanitize) { $params = PMA_Message::sanitize($params); } - $this->_params = $params; + $this->params = $params; } /** @@ -492,7 +535,7 @@ public function setParams($params, $sanitize = false) */ public function getParams() { - return $this->_params; + return $this->params; } /** @@ -502,16 +545,17 @@ public function getParams() */ public function getAddedMessages() { - return $this->_added_messages; + return $this->addedMessages; } /** * Sanitizes $message * - * @static - * @param mixed $message the message(s) - * @return mixed the sanitized message(s) + * @param mixed $message the message(s) + * + * @return mixed the sanitized message(s) * @access public + * @static */ static public function sanitize($message) { @@ -530,10 +574,11 @@ static public function sanitize($message) * decode $message, taking into account our special codes * for formatting * - * @static - * @param string $message the message - * @return string the decoded message + * @param string $message the message + * + * @return string the decoded message * @access public + * @static */ static public function decodeBB($message) { @@ -543,7 +588,7 @@ static public function decodeBB($message) /** * wrapper for sprintf() * - * @return string formatted + * @return string formatted */ static public function format() { @@ -557,31 +602,31 @@ static public function format() } /** - * returns unique PMA_Message::$_hash, if not exists it will be created + * returns unique PMA_Message::$hash, if not exists it will be created * - * @return string PMA_Message::$_hash + * @return string PMA_Message::$hash */ public function getHash() { - if (null === $this->_hash) { - $this->_hash = md5( + if (null === $this->hash) { + $this->hash = md5( $this->getNumber() . - $this->_string . - $this->_message + $this->string . + $this->message ); } - return $this->_hash; + return $this->hash; } /** * returns compiled message * - * @return string complete message + * @return string complete message */ public function getMessage() { - $message = $this->_message; + $message = $this->message; if (0 === strlen($message)) { $string = $this->getString(); @@ -594,6 +639,9 @@ public function getMessage() } } + if ($this->isDisplayed()) { + $message = $this->getMessageWithIcon($message); + } if (count($this->getParams()) > 0) { $message = PMA_Message::format($message, $this->getParams()); } @@ -608,29 +656,29 @@ public function getMessage() } /** - * returns PMA_Message::$_string + * returns PMA_Message::$string * - * @return string PMA_Message::$_string + * @return string PMA_Message::$string */ public function getString() { - return $this->_string; + return $this->string; } /** - * returns PMA_Message::$_number + * returns PMA_Message::$number * - * @return integer PMA_Message::$_number + * @return integer PMA_Message::$number */ public function getNumber() { - return $this->_number; + return $this->number; } /** * returns level of message * - * @return string level of message + * @return string level of message */ public function getLevel() { @@ -640,6 +688,7 @@ public function getLevel() /** * Displays the message in HTML * + * @return void */ public function display() { @@ -650,11 +699,11 @@ public function display() /** * returns HTML code for displaying this message * - * * @return string whole message box */ public function getDisplay() { + $this->isDisplayed(true); return '
    ' . $this->getMessage() . '
    '; } @@ -662,16 +711,39 @@ public function getDisplay() /** * sets and returns whether the message was displayed or not * - * @param boolean $is_displayed - * @return boolean PMA_Message::$_is_displayed + * @param boolean $isDisplayed whether to set displayed flag + * + * @return boolean PMA_Message::$isDisplayed */ - public function isDisplayed($is_displayed = false) + public function isDisplayed($isDisplayed = false) { - if ($is_displayed) { - $this->_is_displayed = true; + if ($isDisplayed) { + $this->isDisplayed = true; } - return $this->_is_displayed; + return $this->isDisplayed; + } + + /** + * Returns the message with corresponding image icon + * + * @param string $message the message(s) + * + * @return string message with icon + */ + public function getMessageWithIcon($message) + { + $image = ''; + if ('error' == $this->getLevel()) { + $image = 's_error.png'; + } elseif ('success' == $this->getLevel()) { + $image = 's_success.png'; + } else { + $image = 's_notice.png'; + } + $message = PMA_Message::notice(PMA_Util::getImage($image)) . " " . $message; + return $message; + } } ?> diff --git a/phpMyAdmin/libraries/OutputBuffering.class.php b/phpMyAdmin/libraries/OutputBuffering.class.php new file mode 100644 index 0000000..ff1f0b7 --- /dev/null +++ b/phpMyAdmin/libraries/OutputBuffering.class.php @@ -0,0 +1,142 @@ +_mode = $this->_getMode(); + $this->_on = false; + } + + /** + * This function could be used eventually to support more modes. + * + * @return integer the output buffer mode + */ + private function _getMode() + { + $mode = 0; + if ($GLOBALS['cfg']['OBGzip'] && function_exists('ob_start')) { + if (ini_get('output_handler') == 'ob_gzhandler') { + // If a user sets the output_handler in php.ini to ob_gzhandler, then + // any right frame file in phpMyAdmin will not be handled properly by + // the browser. My fix was to check the ini file within the + // PMA_outBufferModeGet() function. + $mode = 0; + } elseif (function_exists('ob_get_level') && ob_get_level() > 0) { + // If output buffering is enabled in php.ini it's not possible to + // add the ob_gzhandler without a warning message from php 4.3.0. + // Being better safe than sorry, check for any existing output + // handler instead of just checking the 'output_buffering' setting. + $mode = 0; + } else { + $mode = 1; + } + } + // Zero (0) is no mode or in other words output buffering is OFF. + // Follow 2^0, 2^1, 2^2, 2^3 type values for the modes. + // Usefull if we ever decide to combine modes. Then a bitmask field of + // the sum of all modes will be the natural choice. + return $mode; + } + + /** + * Returns the singleton PMA_OutputBuffering object + * + * @return PMA_OutputBuffering object + */ + public static function getInstance() + { + if (empty(self::$_instance)) { + self::$_instance = new PMA_OutputBuffering(); + } + return self::$_instance; + } + + /** + * This function will need to run at the top of all pages if output + * output buffering is turned on. It also needs to be passed $mode from + * the PMA_outBufferModeGet() function or it will be useless. + * + * @return void + */ + public function start() + { + if (! $this->_on) { + if ($this->_mode) { + ob_start('ob_gzhandler'); + } + ob_start(); + if (! defined('TESTSUITE')) { + header('X-ob_mode: ' . $this->_mode); + } + register_shutdown_function('PMA_OutputBuffering::stop'); + $this->_on = true; + } + } + + /** + * This function will need to run at the bottom of all pages if output + * buffering is turned on. It also needs to be passed $mode from the + * PMA_outBufferModeGet() function or it will be useless. + * + * @return void + */ + public static function stop() + { + $buffer = PMA_OutputBuffering::getInstance(); + if ($buffer->_on) { + $buffer->_on = false; + $buffer->_content = ob_get_contents(); + ob_end_clean(); + } + PMA_Response::response(); + } + + /** + * Gets buffer content + * + * @return string buffer content + */ + public function getContents() + { + return $this->_content; + } + + /** + * Flushes output buffer + * + * @return void + */ + public function flush() + { + if (ob_get_status() && $this->_mode) { + ob_flush(); + } else { + flush(); + } + } +} + +?> diff --git a/phpMyAdmin/libraries/PDF.class.php b/phpMyAdmin/libraries/PDF.class.php index 0be8997..026a87f 100644 --- a/phpMyAdmin/libraries/PDF.class.php +++ b/phpMyAdmin/libraries/PDF.class.php @@ -2,9 +2,14 @@ /* vim: set expandtab sw=4 ts=4 sts=4: */ /** * TCPDF wrapper class. + * + * @package PhpMyAdmin */ +if (! defined('PHPMYADMIN')) { + exit; +} -require_once './libraries/tcpdf/tcpdf.php'; +require_once TCPDF_INC; /** * PDF font to use. @@ -13,17 +18,36 @@ /** * PDF export base class providing basic configuration. + * + * @package PhpMyAdmin */ class PMA_PDF extends TCPDF { var $footerset; var $Alias = array(); - public function __construct($orientation='P', $unit='mm', $format='A4', $unicode=true, $encoding='UTF-8', $diskcache=false) - { - parent::__construct(); + /** + * Constructs PDF and configures standard parameters. + * + * @param string $orientation page orientation + * @param string $unit unit + * @param mixed $format the format used for pages + * @param boolean $unicode true means that the input text is unicode + * @param string $encoding charset encoding; default is UTF-8. + * @param boolean $diskcache if true reduce the RAM memory usage by caching + * temporary data on filesystem (slower). + * @param boolean $pdfa If TRUE set the document to PDF/A mode. + * + * @access public + */ + public function __construct($orientation = 'P', $unit = 'mm', $format = 'A4', + $unicode = true, $encoding = 'UTF-8', $diskcache = false, $pdfa=false + ) { + parent::__construct( + $orientation, $unit, $format, $unicode, + $encoding, $diskcache, $pdfa + ); $this->SetAuthor('phpMyAdmin ' . PMA_VERSION); - $this->AliasNbPages(); $this->AddFont('DejaVuSans', '', 'dejavusans.php'); $this->AddFont('DejaVuSans', 'B', 'dejavusansb.php'); $this->SetFont(PMA_PDF_FONT, '', 14); @@ -32,6 +56,8 @@ public function __construct($orientation='P', $unit='mm', $format='A4', $unicode /** * This function must be named "Footer" to work with the TCPDF library + * + * @return void */ function Footer() { @@ -39,8 +65,13 @@ function Footer() if (!isset($this->footerset[$this->page])) { $this->SetY(-15); $this->SetFont(PMA_PDF_FONT, '', 14); - $this->Cell(0, 6, __('Page number:') . ' ' . $this->getAliasNumPage() . '/' . $this->getAliasNbPages(), 'T', 0, 'C'); - $this->Cell(0, 6, PMA_localisedDate(), 0, 1, 'R'); + $this->Cell( + 0, 6, + __('Page number:') . ' ' + . $this->getAliasNumPage() . '/' . $this->getAliasNbPages(), + 'T', 0, 'C' + ); + $this->Cell(0, 6, PMA_Util::localisedDate(), 0, 1, 'R'); $this->SetY(20); // set footerset @@ -50,14 +81,26 @@ function Footer() /** * Function to set alias which will be expanded on page rendering. + * + * @param string $name name of the alias + * @param string $value value of the alias + * + * @return void */ function SetAlias($name, $value) { - $this->Alias[$this->UTF8ToUTF16BE($name)] = $this->UTF8ToUTF16BE($value); + $name = TCPDF_FONTS::UTF8ToUTF16BE( + $name, false, true, $this->CurrentFont + ); + $this->Alias[$name] = TCPDF_FONTS::UTF8ToUTF16BE( + $value, false, true, $this->CurrentFont + ); } /** * Improved with alias expading. + * + * @return void */ function _putpages() { @@ -74,21 +117,29 @@ function _putpages() * Displays an error message * * @param string $error_message the error mesage + * + * @return void */ function Error($error_message = '') { - include './libraries/header.inc.php'; - PMA_Message::error(__('Error while creating PDF:') . ' ' . $error_message)->display(); - include './libraries/footer.inc.php'; + PMA_Message::error( + __('Error while creating PDF:') . ' ' . $error_message + )->display(); + exit; } /** * Sends file as a download to user. + * + * @param string $filename file name + * + * @return void */ function Download($filename) { $pdfData = $this->getPDFData(); - PMA_download_header($filename, 'application/pdf', strlen($pdfData)); + PMA_Response::getInstance()->disable(); + PMA_downloadHeader($filename, 'application/pdf', strlen($pdfData)); echo $pdfData; } } diff --git a/phpMyAdmin/libraries/PMA.php b/phpMyAdmin/libraries/PMA.php index db13bab..021917d 100644 --- a/phpMyAdmin/libraries/PMA.php +++ b/phpMyAdmin/libraries/PMA.php @@ -1,10 +1,16 @@ getDatabaseList(); - break; - case 'userlink' : - return $this->userlink; - break; - case 'controllink' : - return $this->controllink; - break; + case 'databases' : + return $this->getDatabaseList(); + break; + case 'userlink' : + return $this->userlink; + break; + case 'controllink' : + return $this->controllink; + break; } return null; @@ -68,20 +72,21 @@ public function __get($param) /** * magic access to protected/inaccessible members/properties * - * @see http://php.net/language.oop5.overloading + * @param string $param parameter name + * @param mixed $value value to set * - * @param string $param - * @param mixed $value + * @return void + * @see http://php.net/language.oop5.overloading */ public function __set($param, $value) { switch ($param) { - case 'userlink' : - $this->userlink = $value; - break; - case 'controllink' : - $this->controllink = $value; - break; + case 'userlink' : + $this->userlink = $value; + break; + case 'controllink' : + $this->controllink = $value; + break; } } @@ -93,7 +98,10 @@ public function __set($param, $value) public function getDatabaseList() { if (null === $this->databases) { - $this->databases = new PMA_List_Database($this->userlink, $this->controllink); + $this->databases = new PMA_List_Database( + $this->userlink, + $this->controllink + ); } return $this->databases; diff --git a/phpMyAdmin/libraries/Partition.class.php b/phpMyAdmin/libraries/Partition.class.php index 0fb68c4..5125885 100644 --- a/phpMyAdmin/libraries/Partition.class.php +++ b/phpMyAdmin/libraries/Partition.class.php @@ -5,10 +5,13 @@ * * @package PhpMyAdmin */ - +if (! defined('PHPMYADMIN')) { + exit; +} /** * base Partition Class + * * @package PhpMyAdmin */ class PMA_Partition @@ -16,13 +19,20 @@ class PMA_Partition /** * returns array of partition names for a specific db/table * + * @param string $db database name + * @param string $table table name + * * @access public - * @return array of partition names + * @return array of partition names */ static public function getPartitionNames($db, $table) { if (PMA_Partition::havePartitioning()) { - return PMA_DBI_fetch_result("select `PARTITION_NAME` from `information_schema`.`PARTITIONS` where `TABLE_SCHEMA` = '" . $db . "' and `TABLE_NAME` = '" . $table . "'"); + return $GLOBALS['dbi']->fetchResult( + "SELECT `PARTITION_NAME` FROM `information_schema`.`PARTITIONS`" + . " WHERE `TABLE_SCHEMA` = '" . $db + . "' AND `TABLE_NAME` = '" . $table . "'" + ); } else { return array(); } @@ -35,7 +45,7 @@ static public function getPartitionNames($db, $table) * @staticvar boolean $have_partitioning * @staticvar boolean $already_checked * @access public - * @return boolean + * @return boolean */ static public function havePartitioning() { @@ -43,12 +53,27 @@ static public function havePartitioning() static $already_checked = false; if (! $already_checked) { - $have_partitioning = PMA_MYSQL_INT_VERSION >= 50100 && PMA_DBI_fetch_value("SHOW VARIABLES LIKE 'have_partitioning';"); - $already_checked = true; + if (PMA_MYSQL_INT_VERSION >= 50100) { + if (PMA_MYSQL_INT_VERSION < 50600) { + if ($GLOBALS['dbi']->fetchValue( + "SHOW VARIABLES LIKE 'have_partitioning';" + )) { + $have_partitioning = true; + } + } else { + // see http://dev.mysql.com/doc/refman/5.6/en/partitioning.html + $plugins = $GLOBALS['dbi']->fetchResult("SHOW PLUGINS"); + foreach ($plugins as $value) { + if ($value['Name'] == 'partition') { + $have_partitioning = true; + break; + } + } + } + $already_checked = true; + } } return $have_partitioning; } - } - ?> diff --git a/phpMyAdmin/libraries/RecentTable.class.php b/phpMyAdmin/libraries/RecentTable.class.php index 6642acb..65b798f 100644 --- a/phpMyAdmin/libraries/RecentTable.class.php +++ b/phpMyAdmin/libraries/RecentTable.class.php @@ -1,16 +1,22 @@ pma_table = PMA_backquote($GLOBALS['cfg']['Server']['pmadb']) .".". - PMA_backquote($GLOBALS['cfg']['Server']['recent']); + if (strlen($GLOBALS['cfg']['Server']['pmadb']) + && strlen($GLOBALS['cfg']['Server']['recent']) + ) { + $this->_pmaTable + = PMA_Util::backquote($GLOBALS['cfg']['Server']['pmadb']) . "." + . PMA_Util::backquote($GLOBALS['cfg']['Server']['recent']); } $server_id = $GLOBALS['server']; - if (! isset($_SESSION['tmp_user_values']['recent_tables'][$server_id])) { - $_SESSION['tmp_user_values']['recent_tables'][$server_id] = - isset($this->pma_table) ? $this->getFromDb() : array(); + if (! isset($_SESSION['tmpval']['recent_tables'][$server_id])) { + $_SESSION['tmpval']['recent_tables'][$server_id] + = isset($this->_pmaTable) ? $this->getFromDb() : array(); } - $this->tables =& $_SESSION['tmp_user_values']['recent_tables'][$server_id]; + $this->tables =& $_SESSION['tmpval']['recent_tables'][$server_id]; } /** @@ -70,61 +81,69 @@ public static function getInstance() /** * Returns recently used tables from phpMyAdmin database. * - * * @return array */ public function getFromDb() { // Read from phpMyAdmin database, if recent tables is not in session $sql_query - = " SELECT `tables` FROM " . $this->pma_table . + = " SELECT `tables` FROM " . $this->_pmaTable . " WHERE `username` = '" . $GLOBALS['cfg']['Server']['user'] . "'"; - $row = PMA_DBI_fetch_array(PMA_query_as_controluser($sql_query)); - if (isset($row[0])) { - return json_decode($row[0], true); - } else { - return array(); + $return = array(); + $result = PMA_queryAsControlUser($sql_query, false); + if ($result) { + $row = $GLOBALS['dbi']->fetchArray($result); + if (isset($row[0])) { + $return = json_decode($row[0], true); + } } + return $return; } /** * Save recent tables into phpMyAdmin database. * - * * @return true|PMA_Message */ public function saveToDb() { $username = $GLOBALS['cfg']['Server']['user']; $sql_query - = " REPLACE INTO " . $this->pma_table . " (`username`, `tables`)" . - " VALUES ('" . $username . "', '" . PMA_sqlAddSlashes(json_encode($this->tables)) . "')"; + = " REPLACE INTO " . $this->_pmaTable . " (`username`, `tables`)" . + " VALUES ('" . $username . "', '" + . PMA_Util::sqlAddSlashes( + json_encode($this->tables) + ) . "')"; - $success = PMA_DBI_try_query($sql_query, $GLOBALS['controllink']); + $success = $GLOBALS['dbi']->tryQuery($sql_query, $GLOBALS['controllink']); - if (!$success) { + if (! $success) { $message = PMA_Message::error(__('Could not save recent table')); $message->addMessage('

    '); - $message->addMessage(PMA_Message::rawError(PMA_DBI_getError($GLOBALS['controllink']))); + $message->addMessage( + PMA_Message::rawError( + $GLOBALS['dbi']->getError($GLOBALS['controllink']) + ) + ); return $message; } return true; } /** - * Trim recent table according to the LeftRecentTable configuration. + * Trim recent table according to the NumRecentTables configuration. * * @return boolean True if trimming occurred */ public function trim() { - $max = max($GLOBALS['cfg']['LeftRecentTable'], 0); - $trimming_occured = count($this->tables) > $max; + $max = max($GLOBALS['cfg']['NumRecentTables'], 0); + $trimming_occurred = count($this->tables) > $max; while (count($this->tables) > $max) { array_pop($this->tables); } - return $trimming_occured; + return $trimming_occurred; } /** @@ -135,18 +154,24 @@ public function trim() public function getHtmlSelectOption() { // trim and save, in case where the configuration is changed - if ($this->trim() && isset($this->pma_table)) { + if ($this->trim() && isset($this->_pmaTable)) { $this->saveToDb(); } $html = ''; if (count($this->tables)) { foreach ($this->tables as $table) { - $html .= ''; + $html .= ''; } } else { - $html .= ''; + $html .= ''; } return $html; } @@ -158,9 +183,7 @@ public function getHtmlSelectOption() */ public function getHtmlSelect() { - $html = ''; - $html .= ''; $html .= $this->getHtmlSelectOption(); $html .= ''; @@ -170,8 +193,8 @@ public function getHtmlSelect() /** * Add recently used tables. * - * @param string $db Database name where the table is located - * @param string $table Table name + * @param string $db database name where the table is located + * @param string $table table name * * @return true|PMA_Message True if success, PMA_Message if not */ @@ -186,7 +209,7 @@ public function add($db, $table) array_unshift($this->tables, $table_arr); $this->tables = array_merge(array_unique($this->tables, SORT_REGULAR)); $this->trim(); - if (isset($this->pma_table)) { + if (isset($this->_pmaTable)) { return $this->saveToDb(); } } diff --git a/phpMyAdmin/libraries/Response.class.php b/phpMyAdmin/libraries/Response.class.php new file mode 100644 index 0000000..10858d2 --- /dev/null +++ b/phpMyAdmin/libraries/Response.class.php @@ -0,0 +1,380 @@ +start(); + } + $this->_header = new PMA_Header(); + $this->_HTML = ''; + $this->_JSON = array(); + $this->_footer = new PMA_Footer(); + + $this->_isSuccess = true; + $this->_isAjax = false; + $this->_isAjaxPage = false; + if (isset($_REQUEST['ajax_request']) && $_REQUEST['ajax_request'] == true) { + $this->_isAjax = true; + } + if (isset($_REQUEST['ajax_page_request']) + && $_REQUEST['ajax_page_request'] == true + ) { + $this->_isAjaxPage = true; + } + $this->_header->setAjax($this->_isAjax); + $this->_footer->setAjax($this->_isAjax); + $this->_CWD = getcwd(); + } + + /** + * Returns the singleton PMA_Response object + * + * @return PMA_Response object + */ + public static function getInstance() + { + if (empty(self::$_instance)) { + self::$_instance = new PMA_Response(); + } + return self::$_instance; + } + + /** + * Set the status of an ajax response, + * whether it is a success or an error + * + * @param bool $state Whether the request was successfully processed + * + * @return void + */ + public function isSuccess($state) + { + $this->_isSuccess = ($state == true); + } + + /** + * Returns true or false depending on whether + * we are servicing an ajax request + * + * @return bool + */ + public function isAjax() + { + return $this->_isAjax; + } + + /** + * Returns the path to the current working directory + * Necessary to work around a PHP bug where the CWD is + * reset after the initial script exits + * + * @return string + */ + public function getCWD() + { + return $this->_CWD; + } + + /** + * Disables the rendering of the header + * and the footer in responses + * + * @return void + */ + public function disable() + { + $this->_header->disable(); + $this->_footer->disable(); + } + + /** + * Returns a PMA_Header object + * + * @return PMA_Header + */ + public function getHeader() + { + return $this->_header; + } + + /** + * Returns a PMA_Footer object + * + * @return PMA_Footer + */ + public function getFooter() + { + return $this->_footer; + } + + /** + * Add HTML code to the response + * + * @param string $content A string to be appended to + * the current output buffer + * + * @return void + */ + public function addHTML($content) + { + if (is_array($content)) { + foreach ($content as $msg) { + $this->addHTML($msg); + } + } elseif ($content instanceof PMA_Message) { + $this->_HTML .= $content->getDisplay(); + } else { + $this->_HTML .= $content; + } + } + + /** + * Add JSON code to the response + * + * @param mixed $json Either a key (string) or an + * array or key-value pairs + * @param mixed $value Null, if passing an array in $json otherwise + * it's a string value to the key + * + * @return void + */ + public function addJSON($json, $value = null) + { + if (is_array($json)) { + foreach ($json as $key => $value) { + $this->addJSON($key, $value); + } + } else { + if ($value instanceof PMA_Message) { + $this->_JSON[$json] = $value->getDisplay(); + } else { + $this->_JSON[$json] = $value; + } + } + + } + + /** + * Renders the HTML response text + * + * @return string + */ + private function _getDisplay() + { + // The header may contain nothing at all, + // if it's content was already rendered + // and, in this case, the header will be + // in the content part of the request + $retval = $this->_header->getDisplay(); + $retval .= $this->_HTML; + $retval .= $this->_footer->getDisplay(); + return $retval; + } + + /** + * Sends an HTML response to the browser + * + * @return void + */ + private function _htmlResponse() + { + echo $this->_getDisplay(); + } + + /** + * Sends a JSON response to the browser + * + * @return void + */ + private function _ajaxResponse() + { + if (! isset($this->_JSON['message'])) { + $this->_JSON['message'] = $this->_getDisplay(); + } else if ($this->_JSON['message'] instanceof PMA_Message) { + $this->_JSON['message'] = $this->_JSON['message']->getDisplay(); + } + + if ($this->_isSuccess) { + $this->_JSON['success'] = true; + } else { + $this->_JSON['success'] = false; + $this->_JSON['error'] = $this->_JSON['message']; + unset($this->_JSON['message']); + } + + if ($this->_isAjaxPage && $this->_isSuccess) { + $this->addJSON('_title', $this->getHeader()->getTitleTag()); + + $menuHash = $this->getHeader()->getMenu()->getHash(); + $this->addJSON('_menuHash', $menuHash); + $hashes = array(); + if (isset($_REQUEST['menuHashes'])) { + $hashes = explode('-', $_REQUEST['menuHashes']); + } + if (! in_array($menuHash, $hashes)) { + $this->addJSON('_menu', $this->getHeader()->getMenu()->getDisplay()); + } + + $this->addJSON('_scripts', $this->getHeader()->getScripts()->getFiles()); + $this->addJSON('_selflink', $this->getFooter()->getSelfUrl('unencoded')); + $this->addJSON('_displayMessage', $this->getHeader()->getMessage()); + $errors = $this->_footer->getErrorMessages(); + if (strlen($errors)) { + $this->addJSON('_errors', $errors); + } + if (empty($GLOBALS['error_message'])) { + // set current db, table and sql query in the querywindow + $query = ''; + $maxChars = $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']; + if (isset($GLOBALS['sql_query']) + && strlen($GLOBALS['sql_query']) < $maxChars + ) { + $query = PMA_escapeJsString($GLOBALS['sql_query']); + } + $this->addJSON( + '_reloadQuerywindow', + array( + 'db' => PMA_ifSetOr($GLOBALS['db'], ''), + 'table' => PMA_ifSetOr($GLOBALS['table'], ''), + 'sql_query' => $query + ) + ); + if (! empty($GLOBALS['focus_querywindow'])) { + $this->addJSON('_focusQuerywindow', $query); + } + if (! empty($GLOBALS['reload'])) { + $this->addJSON('_reloadNavigation', 1); + } + $this->addJSON('_params', $this->getHeader()->getJsParams()); + } + } + + // Set the Content-Type header to JSON so that jQuery parses the + // response correctly. + if (! defined('TESTSUITE')) { + header('Cache-Control: no-cache'); + header('Content-Type: application/json'); + } + + echo json_encode($this->_JSON); + } + + /** + * Sends an HTML response to the browser + * + * @static + * @return void + */ + public static function response() + { + $response = PMA_Response::getInstance(); + chdir($response->getCWD()); + $buffer = PMA_OutputBuffering::getInstance(); + if (empty($response->_HTML)) { + $response->_HTML = $buffer->getContents(); + } + if ($response->isAjax()) { + $response->_ajaxResponse(); + } else { + $response->_htmlResponse(); + } + $buffer->flush(); + exit; + } +} + +?> diff --git a/phpMyAdmin/libraries/Scripts.class.php b/phpMyAdmin/libraries/Scripts.class.php new file mode 100644 index 0000000..1ceb370 --- /dev/null +++ b/phpMyAdmin/libraries/Scripts.class.php @@ -0,0 +1,248 @@ +"; + } + } + $static_scripts = sprintf( + '', + PMA_URL_getCommon(array(), 'none'), implode("&", $scripts) + ); + return $static_scripts . $dynamic_scripts; + } + + /** + * Generates new PMA_Scripts objects + * + * @return PMA_Scripts object + */ + public function __construct() + { + $this->_files = array(); + $this->_code = ''; + $this->_events = array(); + + } + + /** + * Adds a new file to the list of scripts + * + * @param string $filename The name of the file to include + * @param bool $conditional_ie Whether to wrap the script tag in + * conditional comments for IE + * + * @return void + */ + public function addFile($filename, $conditional_ie = false) + { + $hash = md5($filename); + if (empty($this->_files[$hash])) { + $has_onload = $this->_eventBlacklist($filename); + $this->_files[$hash] = array( + 'has_onload' => $has_onload, + 'filename' => $filename, + 'conditional_ie' => $conditional_ie + ); + } + } + + /** + * Determines whether to fire up an onload event for a file + * + * @param string $filename The name of the file to be checked + * against the blacklist + * + * @return int 1 to fire up the event, 0 not to + */ + private function _eventBlacklist($filename) + { + if ( strpos($filename, 'jquery') !== false + || strpos($filename, 'codemirror') !== false + || strpos($filename, 'messages.php') !== false + || strpos($filename, 'ajax.js') !== false + || strpos($filename, 'navigation.js') !== false + || strpos($filename, 'get_image.js.php') !== false + || strpos($filename, 'cross_framing_protection.js') !== false + ) { + return 0; + } else { + return 1; + } + } + + /** + * Adds a new code snippet to the code to be executed + * + * @param string $code The JS code to be added + * + * @return void + */ + public function addCode($code) + { + $this->_code .= "$code\n"; + } + + /** + * Adds a new event to the list of events + * + * @param string $event The name of the event to register + * @param string $function The code to execute when the event fires + * E.g: 'function () { doSomething(); }' + * or 'doSomething' + * + * @return void + */ + public function addEvent($event, $function) + { + $this->_events[] = array( + 'event' => $event, + 'function' => $function + ); + } + + /** + * Returns a list with filenames and a flag to indicate + * whether to register onload events for this file + * + * @return array + */ + public function getFiles() + { + $retval = array(); + foreach ($this->_files as $file) { + if (strpos($file['filename'], "?") === false) { + if (! $file['conditional_ie'] || PMA_USR_BROWSER_AGENT == 'IE') { + $retval[] = array( + 'name' => $file['filename'], + 'fire' => $file['has_onload'] + ); + } + } + } + return $retval; + } + + /** + * Renders all the JavaScript file inclusions, code and events + * + * @return string + */ + public function getDisplay() + { + $retval = ''; + + if (count($this->_files) > 0) { + $retval .= $this->_includeFiles( + $this->_files + ); + } + + $code = 'AJAX.scriptHandler'; + foreach ($this->_files as $file) { + $code .= sprintf( + '.add("%s",%d)', + PMA_escapeJsString($file['filename']), + $file['has_onload'] ? 1 : 0 + ); + } + $code .= ';'; + $this->addCode($code); + + $code = '$(function() {'; + foreach ($this->_files as $file) { + if ($file['has_onload']) { + $code .= 'AJAX.fireOnload("'; + $code .= PMA_escapeJsString($file['filename']); + $code .= '");'; + } + } + $code .= '});'; + $this->addCode($code); + + $retval .= ''; + + return $retval; + } +} diff --git a/phpMyAdmin/libraries/ServerStatusData.class.php b/phpMyAdmin/libraries/ServerStatusData.class.php new file mode 100644 index 0000000..028eada --- /dev/null +++ b/phpMyAdmin/libraries/ServerStatusData.class.php @@ -0,0 +1,407 @@ +selfUrl = basename($GLOBALS['PMA_PHP_SELF']); + /** + * get status from server + */ + $server_status = $GLOBALS['dbi']->fetchResult('SHOW GLOBAL STATUS', 0, 1); + if (PMA_DRIZZLE) { + // Drizzle doesn't put query statistics into variables, add it + $sql = "SELECT concat('Com_', variable_name), variable_value " + . "FROM data_dictionary.GLOBAL_STATEMENTS"; + $statements = $GLOBALS['dbi']->fetchResult($sql, 0, 1); + $server_status = array_merge($server_status, $statements); + } + + /** + * for some calculations we require also some server settings + */ + $server_variables = $GLOBALS['dbi']->fetchResult( + 'SHOW GLOBAL VARIABLES', 0, 1 + ); + + /** + * cleanup of some deprecated values + */ + $server_status = self::cleanDeprecated($server_status); + + /** + * calculate some values + */ + // Key_buffer_fraction + if (isset($server_status['Key_blocks_unused']) + && isset($server_variables['key_cache_block_size']) + && isset($server_variables['key_buffer_size']) + ) { + $server_status['Key_buffer_fraction_%'] + = 100 + - $server_status['Key_blocks_unused'] + * $server_variables['key_cache_block_size'] + / $server_variables['key_buffer_size'] + * 100; + } elseif (isset($server_status['Key_blocks_used']) + && isset($server_variables['key_buffer_size']) + ) { + $server_status['Key_buffer_fraction_%'] + = $server_status['Key_blocks_used'] + * 1024 + / $server_variables['key_buffer_size']; + } + + // Ratio for key read/write + if (isset($server_status['Key_writes']) + && isset($server_status['Key_write_requests']) + && $server_status['Key_write_requests'] > 0 + ) { + $key_writes = $server_status['Key_writes']; + $key_write_requests = $server_status['Key_write_requests']; + $server_status['Key_write_ratio_%'] + = 100 * $key_writes / $key_write_requests; + } + + if (isset($server_status['Key_reads']) + && isset($server_status['Key_read_requests']) + && $server_status['Key_read_requests'] > 0 + ) { + $key_reads = $server_status['Key_reads']; + $key_read_requests = $server_status['Key_read_requests']; + $server_status['Key_read_ratio_%'] + = 100 * $key_reads / $key_read_requests; + } + + // Threads_cache_hitrate + if (isset($server_status['Threads_created']) + && isset($server_status['Connections']) + && $server_status['Connections'] > 0 + ) { + + $server_status['Threads_cache_hitrate_%'] + = 100 - $server_status['Threads_created'] + / $server_status['Connections'] * 100; + } + + /** + * split variables in sections + */ + $allocations = array( + // variable name => section + // variable names match when they begin with the given string + + 'Com_' => 'com', + 'Innodb_' => 'innodb', + 'Ndb_' => 'ndb', + 'Handler_' => 'handler', + 'Qcache_' => 'qcache', + 'Threads_' => 'threads', + 'Slow_launch_threads' => 'threads', + + 'Binlog_cache_' => 'binlog_cache', + 'Created_tmp_' => 'created_tmp', + 'Key_' => 'key', + + 'Delayed_' => 'delayed', + 'Not_flushed_delayed_rows' => 'delayed', + + 'Flush_commands' => 'query', + 'Last_query_cost' => 'query', + 'Slow_queries' => 'query', + 'Queries' => 'query', + 'Prepared_stmt_count' => 'query', + + 'Select_' => 'select', + 'Sort_' => 'sort', + + 'Open_tables' => 'table', + 'Opened_tables' => 'table', + 'Open_table_definitions' => 'table', + 'Opened_table_definitions' => 'table', + 'Table_locks_' => 'table', + + 'Rpl_status' => 'repl', + 'Slave_' => 'repl', + + 'Tc_' => 'tc', + + 'Ssl_' => 'ssl', + + 'Open_files' => 'files', + 'Open_streams' => 'files', + 'Opened_files' => 'files', + ); + + $sections = array( + // section => section name (description) + 'com' => 'Com', + 'query' => __('SQL query'), + 'innodb' => 'InnoDB', + 'ndb' => 'NDB', + 'handler' => __('Handler'), + 'qcache' => __('Query cache'), + 'threads' => __('Threads'), + 'binlog_cache' => __('Binary log'), + 'created_tmp' => __('Temporary data'), + 'delayed' => __('Delayed inserts'), + 'key' => __('Key cache'), + 'select' => __('Joins'), + 'repl' => __('Replication'), + 'sort' => __('Sorting'), + 'table' => __('Tables'), + 'tc' => __('Transaction coordinator'), + 'files' => __('Files'), + 'ssl' => 'SSL', + 'other' => __('Other') + ); + + /** + * define some needfull links/commands + */ + // variable or section name => (name => url) + $links = array(); + + $links['table'][__('Flush (close) all tables')] = $this->selfUrl + . PMA_URL_getCommon( + array( + 'flush' => 'TABLES' + ) + ); + $links['table'][__('Show open tables')] + = 'sql.php' . PMA_URL_getCommon( + array( + 'sql_query' => 'SHOW OPEN TABLES', + 'goto' => $this->selfUrl, + ) + ); + + if ($GLOBALS['server_master_status']) { + $links['repl'][__('Show slave hosts')] + = 'sql.php' . PMA_URL_getCommon( + array( + 'sql_query' => 'SHOW SLAVE HOSTS', + 'goto' => $this->selfUrl, + ) + ); + $links['repl'][__('Show master status')] = '#replication_master'; + } + if ($GLOBALS['server_slave_status']) { + $links['repl'][__('Show slave status')] = '#replication_slave'; + } + + $links['repl']['doc'] = 'replication'; + + $links['qcache'][__('Flush query cache')] + = $this->selfUrl + . PMA_URL_getCommon( + array( + 'flush' => 'QUERY CACHE' + ) + ); + $links['qcache']['doc'] = 'query_cache'; + + $links['threads']['doc'] = 'mysql_threads'; + + $links['key']['doc'] = 'myisam_key_cache'; + + $links['binlog_cache']['doc'] = 'binary_log'; + + $links['Slow_queries']['doc'] = 'slow_query_log'; + + $links['innodb'][__('Variables')] + = 'server_engines.php?engine=InnoDB&' . PMA_URL_getCommon(); + $links['innodb'][__('InnoDB Status')] + = 'server_engines.php' + . PMA_URL_getCommon( + array( + 'engine' => 'InnoDB', + 'page' => 'Status' + ) + ); + $links['innodb']['doc'] = 'innodb'; + + + // Variable to contain all com_ variables (query statistics) + $used_queries = array(); + + // Variable to map variable names to their respective section name + // (used for js category filtering) + $allocationMap = array(); + + // Variable to mark used sections + $categoryUsed = array(); + + // sort vars into arrays + foreach ($server_status as $name => $value) { + $section_found = false; + foreach ($allocations as $filter => $section) { + if (strpos($name, $filter) !== false) { + $allocationMap[$name] = $section; + $categoryUsed[$section] = true; + $section_found = true; + if ($section == 'com' && $value > 0) { + $used_queries[$name] = $value; + } + break; // Only exits inner loop + } + } + if (!$section_found) { + $allocationMap[$name] = 'other'; + $categoryUsed['other'] = true; + } + } + + if (PMA_DRIZZLE) { + $used_queries = $GLOBALS['dbi']->fetchResult( + 'SELECT * FROM data_dictionary.global_statements', + 0, + 1 + ); + unset($used_queries['admin_commands']); + } else { + // admin commands are not queries (e.g. they include COM_PING, + // which is excluded from $server_status['Questions']) + unset($used_queries['Com_admin_commands']); + } + + // Set all class properties + $this->db_isLocal = false; + if (strtolower($GLOBALS['cfg']['Server']['host']) === 'localhost' + || $GLOBALS['cfg']['Server']['host'] === '127.0.0.1' + || $GLOBALS['cfg']['Server']['host'] === '::1' + ) { + $this->db_isLocal = true; + } + $this->status = $server_status; + $this->sections = $sections; + $this->variables = $server_variables; + $this->used_queries = $used_queries; + $this->allocationMap = $allocationMap; + $this->links = $links; + $this->categoryUsed = $categoryUsed; + } + + /** + * cleanup of some deprecated values + * + * @param array $server_status status array to process + * + * @return array + */ + public static function cleanDeprecated($server_status) + { + $deprecated = array( + 'Com_prepare_sql' => 'Com_stmt_prepare', + 'Com_execute_sql' => 'Com_stmt_execute', + 'Com_dealloc_sql' => 'Com_stmt_close', + ); + foreach ($deprecated as $old => $new) { + if (isset($server_status[$old]) && isset($server_status[$new])) { + unset($server_status[$old]); + } + } + return $server_status; + } + + /** + * cleanup of some deprecated values + * + * @return array + */ + public function getMenuHtml() + { + $url_params = PMA_URL_getCommon(); + $items = array( + array( + 'name' => __('Server'), + 'url' => 'server_status.php' + ), + array( + 'name' => __('Query statistics'), + 'url' => 'server_status_queries.php' + ), + array( + 'name' => __('All status variables'), + 'url' => 'server_status_variables.php' + ), + array( + 'name' => __('Monitor'), + 'url' => 'server_status_monitor.php' + ), + array( + 'name' => __('Advisor'), + 'url' => 'server_status_advisor.php' + ) + ); + + $retval = '
      '; + foreach ($items as $item) { + $class = ''; + if ($item['url'] === $this->selfUrl) { + $class = ' class="tabactive"'; + } + $retval .= '
    • '; + $retval .= ''; + $retval .= $item['name']; + $retval .= ''; + $retval .= '
    • '; + } + $retval .= '
    '; + $retval .= '
    '; + + return $retval; + } +} + +?> diff --git a/phpMyAdmin/libraries/StorageEngine.class.php b/phpMyAdmin/libraries/StorageEngine.class.php index e41f7be..19269d0 100644 --- a/phpMyAdmin/libraries/StorageEngine.class.php +++ b/phpMyAdmin/libraries/StorageEngine.class.php @@ -5,6 +5,9 @@ * * @package PhpMyAdmin */ +if (! defined('PHPMYADMIN')) { + exit; +} /** * defines @@ -20,7 +23,8 @@ define('PMA_ENGINE_DETAILS_TYPE_BOOLEAN', 3); // 'ON' or 'OFF' /** - * base Storage Engine Class + * Base Storage Engine Class + * * @package PhpMyAdmin */ class PMA_StorageEngine @@ -38,7 +42,8 @@ class PMA_StorageEngine /** * @var string engine lang description */ - var $comment = 'If you read this text inside phpMyAdmin, something went wrong...'; + var $comment + = 'If you read this text inside phpMyAdmin, something went wrong...'; /** * @var integer engine supported by current server @@ -51,7 +56,7 @@ class PMA_StorageEngine * @static * @staticvar array $storage_engines storage engines * @access public - * @return array of storage engines + * @return array of storage engines */ static public function getStorageEngines() { @@ -70,9 +75,10 @@ static public function getStorageEngines() JOIN data_dictionary.modules m USING (module_name) WHERE p.plugin_type = 'StorageEngine' AND p.plugin_name NOT IN ('FunctionEngine', 'schema')"; - $storage_engines = PMA_DBI_fetch_result($sql, 'Engine'); + $storage_engines = $GLOBALS['dbi']->fetchResult($sql, 'Engine'); } else { - $storage_engines = PMA_DBI_fetch_result('SHOW STORAGE ENGINES', 'Engine'); + $storage_engines + = $GLOBALS['dbi']->fetchResult('SHOW STORAGE ENGINES', 'Engine'); } } @@ -85,14 +91,16 @@ static public function getStorageEngines() * @param string $name The name of the select form element * @param string $id The ID of the form field * @param string $selected The selected engine - * @param boolean $offerUnavailableEngines Should unavailable storage engines be offered? + * @param boolean $offerUnavailableEngines Should unavailable storage + * engines be offered? * * @static - * @return string html selectbox + * @return string html selectbox */ - static public function getHtmlSelect($name = 'engine', $id = null, - $selected = null, $offerUnavailableEngines = false) - { + static public function getHtmlSelect( + $name = 'engine', $id = null, + $selected = null, $offerUnavailableEngines = false + ) { $selected = strtolower($selected); $output = ''; + + if ($in_fbs) { + $edit_url = 'gis_data_editor.php?' . PMA_URL_getCommon(); + $edit_str = PMA_Util::getIcon('b_edit.png', __('Edit/Insert')); + $html_output .= ''; + $html_output .= PMA_Util::linkOrButton( + $edit_url, $edit_str, array(), false, false, '_blank' + ); + $html_output .= ''; + } + return $html_output; + } + + /** + * Provides html elements for search criteria inputbox + * in case the column is a Foreign Key + * + * @param array $foreignData Foreign keys data + * @param string $column_name Column name + * @param int $column_index Column index + * @param array $titles Selected title + * @param int $foreignMaxLimit Max limit of displaying foreign elements + * @param array $criteriaValues Array of search criteria inputs + * @param string $column_id Column's inputbox's id + * @param bool $in_zoom_search_edit Whether we are in zoom search edit + * + * @return string HTML elements. + */ + private function _getForeignKeyInputBox($foreignData, $column_name, + $column_index, $titles, $foreignMaxLimit, $criteriaValues, $column_id, + $in_zoom_search_edit = false + ) { + $html_output = ''; + if (is_array($foreignData['disp_row'])) { + $html_output .= ''; + + } elseif ($foreignData['foreign_link'] == true) { + $html_output .= ''; + + $html_output .= <<'; + } + return $html_output; + } + + /** + * Provides html elements for search criteria inputbox + * in case the column is of ENUM or SET type + * + * @param int $column_index Column index + * @param array $criteriaValues Array of search criteria inputs + * @param string $column_type Column type + * @param string $column_id Column's inputbox's id + * @param bool $in_zoom_search_edit Whether we are in zoom search edit + * + * @return string HTML elements. + */ + private function _getEnumSetInputBox($column_index, $criteriaValues, + $column_type, $column_id, $in_zoom_search_edit = false + ) { + $html_output = ''; + $value = explode( + ', ', + str_replace("'", '', substr($column_type, 5, -1)) + ); + $cnt_value = count($value); + + /* + * Enum in edit mode --> dropdown + * Enum in search mode --> multiselect + * Set in edit mode --> multiselect + * Set in search mode --> input (skipped here, so the 'else' + * section would handle it) + */ + if ((strncasecmp($column_type, 'enum', 4) && ! $in_zoom_search_edit) + || (strncasecmp($column_type, 'set', 3) && $in_zoom_search_edit) + ) { + $html_output .= ''; + } + + //Add select options + for ($j = 0; $j < $cnt_value; $j++) { + if (isset($criteriaValues[$column_index]) + && is_array($criteriaValues[$column_index]) + && in_array($value[$j], $criteriaValues[$column_index]) + ) { + $html_output .= ''; + } else { + $html_output .= ''; + } + } // end for + $html_output .= ''; + return $html_output; + } + + /** + * Creates the HTML content for: + * 1) Browsing foreign data for a column. + * 2) Creating elements for search criteria input on columns. + * + * @param array $foreignData Foreign keys data + * @param string $column_name Column name + * @param string $column_type Column type + * @param int $column_index Column index + * @param array $titles Selected title + * @param int $foreignMaxLimit Max limit of displaying foreign elements + * @param array $criteriaValues Array of search criteria inputs + * @param bool $in_fbs Whether we are in 'function based search' + * @param bool $in_zoom_search_edit Whether we are in zoom search edit + * + * @return string HTML content for viewing foreign data and elements + * for search criteria input. + */ + private function _getInputbox($foreignData, $column_name, $column_type, + $column_index, $titles, $foreignMaxLimit, $criteriaValues, $in_fbs = false, + $in_zoom_search_edit = false + ) { + $str = ''; + $column_type = (string)$column_type; + $column_id = ($in_zoom_search_edit) ? 'edit_fieldID_' : 'fieldID_'; + + // Get inputbox based on different column types + // (Foreign key, geometrical, enum) + if ($this->_foreigners && isset($this->_foreigners[$column_name])) { + $str .= $this->_getForeignKeyInputBox( + $foreignData, $column_name, $column_index, $titles, + $foreignMaxLimit, $criteriaValues, $column_id + ); + + } elseif (in_array($column_type, PMA_Util::getGISDatatypes())) { + $str .= $this->_getGeometricalInputBox($column_index, $in_fbs); + + } elseif (strncasecmp($column_type, 'enum', 4) == 0 + || (strncasecmp($column_type, 'set', 3) == 0 && $in_zoom_search_edit) + ) { + $str .= $this->_getEnumSetInputBox( + $column_index, $criteriaValues, $column_type, $column_id, + $in_zoom_search_edit = false + ); + + } else { + // other cases + $the_class = 'textfield'; + + if ($column_type == 'date') { + $the_class .= ' datefield'; + } elseif ($column_type == 'datetime' + || substr($column_type, 0, 9) == 'timestamp' + ) { + $the_class .= ' datetimefield'; + } elseif (substr($column_type, 0, 3) == 'bit') { + $the_class .= ' bit'; + } + + $str .= ''; + } + return $str; + } + + /** + * Return the where clause in case column's type is ENUM. + * + * @param mixed $criteriaValues Search criteria input + * @param string $func_type Search function/operator + * + * @return string part of where clause. + */ + private function _getEnumWhereClause($criteriaValues, $func_type) + { + if (! is_array($criteriaValues)) { + $criteriaValues = explode(',', $criteriaValues); + } + $enum_selected_count = count($criteriaValues); + if ($func_type == '=' && $enum_selected_count > 1) { + $func_type = 'IN'; + $parens_open = '('; + $parens_close = ')'; + + } elseif ($func_type == '!=' && $enum_selected_count > 1) { + $func_type = 'NOT IN'; + $parens_open = '('; + $parens_close = ')'; + + } else { + $parens_open = ''; + $parens_close = ''; + } + $enum_where = '\'' + . PMA_Util::sqlAddSlashes($criteriaValues[0]) . '\''; + for ($e = 1; $e < $enum_selected_count; $e++) { + $enum_where .= ', \'' + . PMA_Util::sqlAddSlashes($criteriaValues[$e]) . '\''; + } + + return ' ' . $func_type . ' ' . $parens_open + . $enum_where . $parens_close; + } + + /** + * Return the where clause for a geometrical column. + * + * @param mixed $criteriaValues Search criteria input + * @param string $names Name of the column on which search is submitted + * @param string $func_type Search function/operator + * @param string $types Type of the field + * @param bool $geom_func Whether geometry functions should be applied + * + * @return string part of where clause. + */ + private function _getGeomWhereClause($criteriaValues, $names, + $func_type, $types, $geom_func = null + ) { + $geom_unary_functions = array( + 'IsEmpty' => 1, + 'IsSimple' => 1, + 'IsRing' => 1, + 'IsClosed' => 1, + ); + $where = ''; + + // 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 + // create gis data from the criteria input + $gis_data = PMA_Util::createGISData($criteriaValues); + $where = $geom_func . '(' . PMA_Util::backquote($names) + . ',' . $gis_data . ')'; + return $where; + } + + // If the where clause is something like 'IsEmpty(`spatial_col_name`)' + if (isset($geom_unary_functions[$geom_func]) + && trim($criteriaValues) == '' + ) { + $where = $backquoted_name; + + } elseif (in_array($types, 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; + } + return $where; + } + + /** + * Return the where clause for query generation based on the inputs provided. + * + * @param mixed $criteriaValues Search criteria input + * @param string $names Name of the column on which search is submitted + * @param string $types Type of the field + * @param string $collations Field collation + * @param string $func_type Search function/operator + * @param bool $unaryFlag Whether operator unary or not + * @param bool $geom_func Whether geometry functions should be applied + * + * @return string generated where clause. + */ + private function _getWhereClause($criteriaValues, $names, $types, $collations, + $func_type, $unaryFlag, $geom_func = null + ) { + // If geometry function is set + if ($geom_func != null && trim($geom_func) != '') { + return $this->_getGeomWhereClause( + $criteriaValues, $names, $func_type, $types, $geom_func + ); + } + + $backquoted_name = PMA_Util::backquote($names); + $where = ''; + if ($unaryFlag) { + $criteriaValues = ''; + $where = $backquoted_name . ' ' . $func_type; + + } elseif (strncasecmp($types, 'enum', 4) == 0 && ! empty($criteriaValues)) { + $where = $backquoted_name; + $where .= $this->_getEnumWhereClause($criteriaValues, $func_type); + + } elseif ($criteriaValues != '') { + // For these types we quote the value. Even if it's another type + // (like INT), for a LIKE we always quote the value. MySQL converts + // strings to numbers and numbers to strings as necessary + // during the comparison + if (preg_match('@char|binary|blob|text|set|date|time|year@i', $types) + || strpos(' ' . $func_type, 'LIKE') + ) { + $quot = '\''; + } else { + $quot = ''; + } + + // LIKE %...% + if ($func_type == 'LIKE %...%') { + $func_type = 'LIKE'; + $criteriaValues = '%' . $criteriaValues . '%'; + } + if ($func_type == 'REGEXP ^...$') { + $func_type = 'REGEXP'; + $criteriaValues = '^' . $criteriaValues . '$'; + } + + if ('IN (...)' == $func_type + || 'NOT IN (...)' == $func_type + || 'BETWEEN' == $func_type + || 'NOT BETWEEN' == $func_type + ) { + $func_type = str_replace(' (...)', '', $func_type); + + //Don't explode if this is already an array + //(Case for (NOT) IN/BETWEEN.) + if (is_array($criteriaValues)) { + $values = $criteriaValues; + } else { + $values = explode(',', $criteriaValues); + } + // quote values one by one + $emptyKey = false; + foreach ($values as $key => &$value) { + if ('' === $value) { + $emptyKey = $key; + $value = 'NULL'; + continue; + } + $value = $quot . PMA_Util::sqlAddSlashes(trim($value)) + . $quot; + } + + if ('BETWEEN' == $func_type || 'NOT BETWEEN' == $func_type) { + $where = $backquoted_name . ' ' . $func_type . ' ' + . (isset($values[0]) ? $values[0] : '') + . ' AND ' . (isset($values[1]) ? $values[1] : ''); + } else { //[NOT] IN + if (false !== $emptyKey) { + unset($values[$emptyKey]); + } + $wheres = array(); + if (!empty($values)) { + $wheres[] = $backquoted_name . ' ' . $func_type + . ' (' . implode(',', $values) . ')'; + } + if (false !== $emptyKey) { + $wheres[] = $backquoted_name . ' IS NULL'; + } + $where = implode(' OR ', $wheres); + if (1 < count($wheres)) { + $where = '(' . $where . ')'; + } + } + } else { + if ($func_type == 'LIKE %...%' || $func_type == 'LIKE') { + $where = $backquoted_name . ' ' . $func_type . ' ' . $quot + . PMA_Util::sqlAddSlashes($criteriaValues, true) . $quot; + } else { + $where = $backquoted_name . ' ' . $func_type . ' ' . $quot + . PMA_Util::sqlAddSlashes($criteriaValues) . $quot; + } + } + } // end if + + return $where; + } + + /** + * Builds the sql search query from the post parameters + * + * @return string the generated SQL query + */ + public function buildSqlQuery() + { + $sql_query = 'SELECT '; + + // If only distinct values are needed + $is_distinct = (isset($_POST['distinct'])) ? 'true' : 'false'; + if ($is_distinct == 'true') { + $sql_query .= 'DISTINCT '; + } + + // if all column names were selected to display, we do a 'SELECT *' + // (more efficient and this helps prevent a problem in IE + // if one of the rows is edited and we come back to the Select results) + if (isset($_POST['zoom_submit']) || ! empty($_POST['displayAllColumns'])) { + $sql_query .= '* '; + } else { + $sql_query .= implode( + ', ', + PMA_Util::backquote($_POST['columnsToDisplay']) + ); + } // end if + + $sql_query .= ' FROM ' + . PMA_Util::backquote($_POST['table']); + $whereClause = $this->_generateWhereClause(); + $sql_query .= $whereClause; + + // if the search results are to be ordered + if (isset($_POST['orderByColumn']) && $_POST['orderByColumn'] != '--nil--') { + $sql_query .= ' ORDER BY ' + . PMA_Util::backquote($_POST['orderByColumn']) + . ' ' . $_POST['order']; + } // end if + return $sql_query; + } + + /** + * Generates the where clause for the SQL search query to be executed + * + * @return string the generated where clause + */ + private function _generateWhereClause() + { + if (isset($_POST['customWhereClause']) + && trim($_POST['customWhereClause']) != '' + ) { + return ' WHERE ' . $_POST['customWhereClause']; + } + + // If there are no search criteria set or no unary criteria operators, + // return + if (! isset($_POST['criteriaValues']) + && ! isset($_POST['criteriaColumnOperators']) + ) { + return ''; + } + + // else continue to form the where clause from column criteria values + $fullWhereClause = $charsets = array(); + reset($_POST['criteriaColumnOperators']); + while (list($column_index, $operator) = each( + $_POST['criteriaColumnOperators'] + )) { + list($charsets[$column_index]) = explode( + '_', $_POST['criteriaColumnCollations'][$column_index] + ); + $unaryFlag = $GLOBALS['PMA_Types']->isUnaryOperator($operator); + $tmp_geom_func = isset($geom_func[$column_index]) + ? $geom_func[$column_index] : null; + + $whereClause = $this->_getWhereClause( + $_POST['criteriaValues'][$column_index], + $_POST['criteriaColumnNames'][$column_index], + $_POST['criteriaColumnTypes'][$column_index], + $_POST['criteriaColumnCollations'][$column_index], + $operator, + $unaryFlag, + $tmp_geom_func + ); + + if ($whereClause) { + $fullWhereClause[] = $whereClause; + } + } // end while + + if ($fullWhereClause) { + return ' WHERE ' . implode(' AND ', $fullWhereClause); + } + return ''; + } + + /** + * Generates HTML for a geometrical function column to be displayed in table + * search selection form + * + * @param integer $column_index index of current column in $columnTypes array + * + * @return string the generated HTML + */ + private function _getGeomFuncHtml($column_index) + { + $html_output = ''; + // return if geometrical column is not present + if (! $this->_geomColumnFlag) { + return $html_output; + } + + /** + * Displays 'Function' column if it is present + */ + $html_output .= ''; + $geom_types = PMA_Util::getGISDatatypes(); + // if a geometry column is present + if (in_array($this->_columnTypes[$column_index], $geom_types)) { + $html_output .= ''; + } else { + $html_output .= ' '; + } + $html_output .= ''; + return $html_output; + } + + /** + * Generates formatted HTML for extra search options in table search form + * + * @return string the generated HTML + */ + private function _getOptions() + { + $html_output = ''; + $html_output .= PMA_Util::getDivForSliderEffect( + 'searchoptions', __('Options') + ); + + /** + * Displays columns select list for selecting distinct columns in the search + */ + $html_output .= '
    ' + . '' . __('Select columns (at least one):') . '' + . '' + . '' + . '
    '; + + /** + * Displays input box for custom 'Where' clause to be used in the search + */ + $html_output .= '
    ' + . '' . '' . __('Or') . ' ' + . __('Add search conditions (body of the "where" clause):') . ''; + $html_output .= PMA_Util::showMySQLDocu('Functions'); + $html_output .= ''; + $html_output .= '
    '; + + /** + * Displays option of changing default number of rows displayed per page + */ + $html_output .= '
    ' + . '' . __('Number of rows per page') . '' + . '' + . '
    '; + + /** + * Displays option for ordering search results + * by a column value (Asc or Desc) + */ + $html_output .= '
    ' + . '' . __('Display order:') . '' + . ''; + $choices = array( + 'ASC' => __('Ascending'), + 'DESC' => __('Descending') + ); + $html_output .= PMA_Util::getRadioFields( + 'order', $choices, 'ASC', false, true, "formelement" + ); + unset($choices); + + $html_output .= '

    '; + return $html_output; + } + + /** + * Other search criteria like data label + * (for tbl_zoom_select.php) + * + * @param array $dataLabel Label for points in zoom plot + * + * @return string the generated html + */ + private function _getOptionsZoom($dataLabel) + { + $html_output = ''; + $html_output .= ''; + //Select options for datalabel + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + //Inputbox for changing default maximum rows to plot + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $html_output .= '
    '; + $html_output .= ''; + $html_output .= '
    '; + return $html_output; + } + + /** + * Provides a column's type, collation, operators list, and crietria value + * to display in table search form + * + * @param integer $search_index Row number in table search form + * @param integer $column_index Column index in ColumnNames array + * + * @return array Array contaning column's properties + */ + public function getColumnProperties($search_index, $column_index) + { + $selected_operator = (isset($_POST['criteriaColumnOperators']) + ? $_POST['criteriaColumnOperators'][$search_index] : ''); + $entered_value = (isset($_POST['criteriaValues']) + ? $_POST['criteriaValues'] : ''); + $titles['Browse'] = PMA_Util::getIcon( + 'b_browse.png', __('Browse foreign values') + ); + //Gets column's type and collation + $type = $this->_columnTypes[$column_index]; + $collation = $this->_columnCollations[$column_index]; + //Gets column's comparison operators depending on column type + $func = ''; + //Gets link to browse foreign data(if any) and criteria inputbox + $foreignData = PMA_getForeignData( + $this->_foreigners, $this->_columnNames[$column_index], false, '', '' + ); + $value = $this->_getInputbox( + $foreignData, $this->_columnNames[$column_index], $type, $search_index, + $titles, $GLOBALS['cfg']['ForeignKeyMaxLimit'], $entered_value + ); + return array( + 'type' => $type, + 'collation' => $collation, + 'func' => $func, + 'value' => $value + ); + } + + /** + * Provides the search form's table row in case of Normal Search + * (for tbl_select.php) + * + * @return string the generated table row + */ + private function _getRowsNormal() + { + $odd_row = true; + $html_output = ''; + // for every column present in table + for ( + $column_index = 0; + $column_index < count($this->_columnNames); + $column_index++ + ) { + $html_output .= ''; + $odd_row = !$odd_row; + //If 'Function' column is present + $html_output .= $this->_getGeomFuncHtml($column_index); + //Displays column's name, type, collation and value + $html_output .= '' + . htmlspecialchars($this->_columnNames[$column_index]) . ''; + $properties = $this->getColumnProperties($column_index, $column_index); + $html_output .= '' . $properties['type'] . ''; + $html_output .= '' . $properties['collation'] . ''; + $html_output .= '' . $properties['func'] . ''; + $html_output .= '' . $properties['value'] . ''; + $html_output .= ''; + //Displays hidden fields + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + } // end for + + return $html_output; + } + + /** + * Provides the search form's table row in case of Zoom Search + * (for tbl_zoom_select.php) + * + * @return string the generated table row + */ + private function _getRowsZoom() + { + $odd_row = true; + $html_output = ''; + /** + * Get already set search criteria (if any) + */ + + //Displays column rows for search criteria input + for ($i = 0; $i < 4; $i++) { + //After X-Axis and Y-Axis column rows, display additional criteria + // option + if ($i == 2) { + $html_output .= ''; + $html_output .= __("Additional search criteria"); + $html_output .= ''; + } + $html_output .= ''; + $odd_row = ! $odd_row; + //Select options for column names + $html_output .= ''; + if (isset($_POST['criteriaColumnNames']) + && $_POST['criteriaColumnNames'][$i] != 'pma_null' + ) { + $key = array_search( + $_POST['criteriaColumnNames'][$i], + $this->_columnNames + ); + $properties = $this->getColumnProperties($i, $key); + $type[$i] = $properties['type']; + $collation[$i] = $properties['collation']; + $func[$i] = $properties['func']; + $value[$i] = $properties['value']; + } + //Column type + $html_output .= '' . (isset($type[$i]) ? $type[$i] : '') . ''; + //Column Collation + $html_output .= '' . (isset($collation[$i]) ? $collation[$i] : '') + . ''; + //Select options for column operators + $html_output .= '' . (isset($func[$i]) ? $func[$i] : '') . ''; + //Inputbox for search criteria value + $html_output .= '' . (isset($value[$i]) ? $value[$i] : '') . ''; + $html_output .= ''; + //Displays hidden fields + $html_output .= ''; + $html_output + .= ''; + $html_output .= ''; + }//end for + return $html_output; + } + + /** + * Generates HTML for displaying fields table in search form + * + * @return string the generated HTML + */ + private function _getFieldsTableHtml() + { + $html_output = ''; + $html_output .= '_searchType == 'zoom' ? ' id="tableFieldsId"' : '') . '>'; + $html_output .= $this->_getTableHeader(); + $html_output .= ''; + + if ($this->_searchType == 'zoom') { + $html_output .= $this->_getRowsZoom(); + } else { + $html_output .= $this->_getRowsNormal(); + } + + $html_output .= '
    '; + return $html_output; + } + + /** + * Provides the form tag for table search form + * (normal search or zoom search) + * + * @param string $goto Goto URL + * + * @return string the HTML for form tag + */ + private function _getFormTag($goto) + { + $html_output = ''; + $scriptName = ''; + $formId = ''; + switch ($this->_searchType) { + case 'normal' : + $scriptName = 'tbl_select.php'; + $formId = 'tbl_search_form'; + break; + case 'zoom' : + $scriptName = 'tbl_zoom_select.php'; + $formId = 'zoom_search_form'; + break; + case 'replace' : + $scriptName = 'tbl_find_replace.php'; + $formId = 'find_replace_form'; + break; + } + + $html_output .= '
    '; + + $html_output .= PMA_URL_getHiddenInputs($this->_db, $this->_table); + $html_output .= ''; + $html_output .= ''; + + return $html_output; + } + + /** + * Returns the HTML for secondary levels tabs of the table search page + * + * @return string HTML for secondary levels tabs + */ + public function getSecondaryTabs() + { + $url_params = array(); + $url_params['db'] = $this->_db; + $url_params['table'] = $this->_table; + + $html_output = '
      '; + foreach ($this->_getSubTabs() as $tab) { + $html_output .= PMA_Util::getHtmlTab($tab, $url_params); + } + $html_output .= '
    '; + $html_output .= '
    '; + return $html_output; + } + + /** + * Generates the table search form under table search tab + * + * @param string $goto Goto URL + * @param string $dataLabel Label for points in zoom plot + * + * @return string the generated HTML for table search form + */ + public function getSelectionForm($goto, $dataLabel = null) + { + $html_output = $this->_getFormTag($goto); + + if ($this->_searchType == 'zoom') { + $html_output .= ''; + } else if ($this->_searchType == 'normal') { + $html_output .= ''; + } else if ($this->_searchType == 'replace') { + $html_output .= '
    '; + $html_output .= '
    '; + $html_output .= '' . __('Find and Replace') . ''; + $html_output .= $this->_getSearchAndReplaceHTML(); + $html_output .= '
    '; + $html_output .= '
    '; + } + + /** + * Displays selection form's footer elements + */ + $html_output .= '
    '; + $html_output .= ''; + $html_output .= '
    '; + $html_output .= '
    '; + return $html_output; + } + + /** + * Provides form for displaying point data and also the scatter plot + * (for tbl_zoom_select.php) + * + * @param string $goto Goto URL + * @param array $data Array containing SQL query data + * + * @return string form's html + */ + public function getZoomResultsForm($goto, $data) + { + $html_output = ''; + $titles['Browse'] = PMA_Util::getIcon( + 'b_browse.png', + __('Browse foreign values') + ); + $html_output .= '
    '; + $html_output .= PMA_URL_getHiddenInputs($this->_db, $this->_table); + $html_output .= ''; + $html_output + .= ''; + + $html_output .= '
    '; + $html_output .= '' . __('Browse/Edit the points') . ''; + + //JSON encode the data(query result) + $html_output .= '
    '; + if (isset($_POST['zoom_submit']) && ! empty($data)) { + $html_output .= '
    '; + $html_output .= '
    ' + . __('How to use') . '
    '; + $html_output .= ''; + $html_output .= '
    '; + $html_output .= ''; + $html_output .= '
    '; + } + $html_output .= '
    '; + + //Displays rows in point edit form + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + return $html_output; + } + + /** + * Displays the 'Find and Replace' form + * + * @return string HTML for 'Find and Replace' form + */ + function _getSearchAndReplaceHTML() + { + $htmlOutput = __('Find:') + . ''; + $htmlOutput .= __('Replace with:') + . ''; + + $htmlOutput .= __('Column:') . ''; + return $htmlOutput; + } + + /** + * Returns HTML for prviewing strings found and their replacements + * + * @param int $columnIndex index of the column + * @param string $find string to find in the column + * @param string $replaceWith string to replace with + * @param string $charSet character set of the connection + * + * @return string HTML for prviewing strings found and their replacements + */ + function getReplacePreview($columnIndex, $find, $replaceWith, $charSet) + { + $column = $this->_columnNames[$columnIndex]; + $sql_query = "SELECT " + . PMA_Util::backquote($column) . "," + . " REPLACE(" + . PMA_Util::backquote($column) . ", '" . $find . "', '" . $replaceWith + . "')," + . " COUNT(*)" + . " FROM " . PMA_Util::backquote($this->_db) + . "." . PMA_Util::backquote($this->_table) + . " WHERE " . PMA_Util::backquote($column) + . " LIKE '%" . $find . "%' COLLATE " . $charSet . "_bin"; // here we + // change the collation of the 2nd operand to a case sensitive + // binary collation to make sure that the comparison is case sensitive + $sql_query .= " GROUP BY " . PMA_Util::backquote($column) + . " ORDER BY " . PMA_Util::backquote($column) . " ASC"; + + $rs = $GLOBALS['dbi']->query( + $sql_query, null, PMA_DatabaseInterface::QUERY_STORE + ); + + $htmlOutput = '
    '; + $htmlOutput .= PMA_URL_getHiddenInputs($this->_db, $this->_table); + $htmlOutput .= ''; + $htmlOutput .= ''; + $htmlOutput .= ''; + $htmlOutput .= ''; + + $htmlOutput .= '
    '; + $htmlOutput .= '' . __('Find and replace - preview') . ''; + + $htmlOutput .= '' + . '' + . '' + . '' + . '' + . ''; + + $htmlOutput .= ''; + $odd = true; + while ($row = $GLOBALS['dbi']->fetchRow($rs)) { + $val = $row[0]; + $replaced = $row[1]; + $count = $row[2]; + + $htmlOutput .= ''; + $htmlOutput .= ''; + $htmlOutput .= ''; + $htmlOutput .= ''; + $htmlOutput .= ''; + + $odd = ! $odd; + } + $htmlOutput .= ''; + $htmlOutput .= '
    ' . __('Count') . '' . __('Original string') . '' . __('Replaced string') . '
    ' . htmlspecialchars($count) . '' . htmlspecialchars($val) . '' . htmlspecialchars($replaced) . '
    '; + $htmlOutput .= '
    '; + + $htmlOutput .= '
    '; + $htmlOutput .= ''; + $htmlOutput .= '
    '; + + $htmlOutput .= '
    '; + return $htmlOutput; + } + + /** + * Replaces a given string in a column with a give replacement + * + * @param int $columnIndex index of the column + * @param string $find string to find in the column + * @param string $replaceWith string to replace with + * @param string $charSet character set of the connection + * + * @return void + */ + function replace($columnIndex, $find, $replaceWith, $charSet) + { + $column = $this->_columnNames[$columnIndex]; + $sql_query = "UPDATE " . PMA_Util::backquote($this->_db) + . "." . PMA_Util::backquote($this->_table) + . " SET " . PMA_Util::backquote($column) . " =" + . " REPLACE(" + . PMA_Util::backquote($column) . ", '" . $find . "', '" . $replaceWith + . "')" + . " WHERE " . PMA_Util::backquote($column) + . " LIKE '%" . $find . "%' COLLATE " . $charSet . "_bin"; // here we + // change the collation of the 2nd operand to a case sensitive + // binary collation to make sure that the comparison is case sensitive + $GLOBALS['dbi']->query( + $sql_query, null, PMA_DatabaseInterface::QUERY_STORE + ); + $GLOBALS['sql_query'] = $sql_query; + } +} +?> diff --git a/phpMyAdmin/libraries/Theme.class.php b/phpMyAdmin/libraries/Theme.class.php index 11ebb0d..a6c8a5f 100644 --- a/phpMyAdmin/libraries/Theme.class.php +++ b/phpMyAdmin/libraries/Theme.class.php @@ -5,14 +5,16 @@ * * @package PhpMyAdmin */ +if (! defined('PHPMYADMIN')) { + exit; +} /** * handles theme * - * @todo add the possibility to make a theme depend on another theme and by default on original + * @todo add the possibility to make a theme depend on another theme + * and by default on original * @todo make all components optional - get missing components from 'parent' theme - * @todo make css optionally replacing 'parent' css or extending it (by appending at the end) - * @todo add an optional global css file - which will be used for both frames * * @package PhpMyAdmin */ @@ -48,12 +50,6 @@ class PMA_Theme */ var $img_path = ''; - /** - * @var array valid css types - * @access protected - */ - var $types = array('left', 'right', 'print'); - /** * @var integer last modification time for info file * @access protected @@ -69,8 +65,26 @@ class PMA_Theme var $filesize_info = 0; /** + * @var array List of css files to load + * @access private + */ + private $_cssFiles = array( + 'common', + 'enum_editor', + 'gis', + 'navigation', + 'pmd', + 'rte', + 'codemirror', + 'jqplot', + 'resizable-menu' + ); + + /** + * Loads theme information + * + * @return boolean whether loading them info was successful or not * @access public - * @return boolean whether loading them info was successful or not */ function loadInfo() { @@ -106,10 +120,11 @@ function loadInfo() * returns theme object loaded from given folder * or false if theme is invalid * + * @param string $folder path to theme + * + * @return PMA_Theme|false * @static - * @access public - * @param string $folder path to theme - * @return object PMA_Theme + * @access public */ static public function load($folder) { @@ -127,34 +142,46 @@ static public function load($folder) } /** - * checks image path for existance - if not found use img from original theme + * checks image path for existance - if not found use img from fallback theme * - * @access public + * @access public * @return bool */ - function checkImgPath() + public function checkImgPath() { + // try current theme first if (is_dir($this->getPath() . '/img/')) { $this->setImgPath($this->getPath() . '/img/'); return true; - } elseif (is_dir($GLOBALS['cfg']['ThemePath'] . '/original/img/')) { - $this->setImgPath($GLOBALS['cfg']['ThemePath'] . '/original/img/'); + } + + // try fallback theme + $fallback = $GLOBALS['cfg']['ThemePath'] . '/' + . PMA_Theme_Manager::FALLBACK_THEME + . '/img/'; + if (is_dir($fallback)) { + $this->setImgPath($fallback); return true; - } else { - trigger_error( - sprintf(__('No valid image path for theme %s found!'), $this->getName()), - E_USER_ERROR); - return false; } + + // we failed + trigger_error( + sprintf( + __('No valid image path for theme %s found!'), + $this->getName() + ), + E_USER_ERROR + ); + return false; } /** * returns path to theme * - * @access public - * @return string $path path to theme + * @access public + * @return string path to theme */ - function getPath() + public function getPath() { return $this->path; } @@ -162,10 +189,10 @@ function getPath() /** * returns layout file * - * @access public - * @return string layout file + * @access public + * @return string layout file */ - function getLayoutFile() + public function getLayoutFile() { return $this->getPath() . '/layout.inc.php'; } @@ -173,10 +200,12 @@ function getLayoutFile() /** * set path to theme * - * @access public - * @param string $path path to theme + * @param string $path path to theme + * + * @return void + * @access public */ - function setPath($path) + public function setPath($path) { $this->path = trim($path); } @@ -184,10 +213,12 @@ function setPath($path) /** * sets version * - * @access public - * @param string new version + * @param string $version version to set + * + * @return void + * @access public */ - function setVersion($version) + public function setVersion($version) { $this->version = trim($version); } @@ -195,10 +226,10 @@ function setVersion($version) /** * returns version * - * @access public - * @return string version + * @return string version + * @access public */ - function getVersion() + public function getVersion() { return $this->version; } @@ -207,11 +238,12 @@ function getVersion() * checks theme version agaisnt $version * returns true if theme version is equal or higher to $version * - * @access public - * @param string $version version to compare to - * @return boolean + * @param string $version version to compare to + * + * @return boolean true if theme version is equal or higher to $version + * @access public */ - function checkVersion($version) + public function checkVersion($version) { return version_compare($this->getVersion(), $version, 'lt'); } @@ -219,10 +251,12 @@ function checkVersion($version) /** * sets name * - * @access public - * @param string $name new name + * @param string $name name to set + * + * @return void + * @access public */ - function setName($name) + public function setName($name) { $this->name = trim($name); } @@ -231,9 +265,9 @@ function setName($name) * returns name * * @access public - * @return string name + * @return string name */ - function getName() + public function getName() { return $this->name; } @@ -241,10 +275,12 @@ function getName() /** * sets id * - * @access public - * @param string $id new id + * @param string $id new id + * + * @return void + * @access public */ - function setId($id) + public function setId($id) { $this->id = trim($id); } @@ -252,55 +288,60 @@ function setId($id) /** * returns id * - * @access public - * @return string id + * @return string id + * @access public */ - function getId() + public function getId() { return $this->id; } /** - * @access public - * @param string path to images for this theme + * Sets path to images for the theme + * + * @param string $path path to images for this theme + * + * @return void + * @access public */ - function setImgPath($path) + public function setImgPath($path) { $this->img_path = $path; } /** - * @access public - * @return string image path for this theme + * Returns the path to image for the theme. + * If filename is given, it possibly fallbacks to fallback + * theme for it if image does not exist. + * + * @param string $file file name for image + * + * @access public + * @return string image path for this theme */ - function getImgPath() + public function getImgPath($file = null) { - return $this->img_path; + if (is_null($file)) { + return $this->img_path; + } else { + if (is_readable($this->img_path . $file)) { + return $this->img_path . $file; + } else { + return $GLOBALS['cfg']['ThemePath'] . '/' + . PMA_Theme_Manager::FALLBACK_THEME . '/img/' . $file; + } + } } /** * load css (send to stdout, normally the browser) * - * @access public - * @param string $type left, right or print * @return bool + * @access public */ - function loadCss(&$type) + public function loadCss() { - if (empty($type) || ! in_array($type, $this->types)) { - $type = 'left'; - } - - if ($type == 'right') { - echo PMA_SQP_buildCssData(); - } - - $_css_file = $this->getPath() - . '/css/theme_' . $type . '.css.php'; - - if (! file_exists($_css_file)) { - return false; - } + $success = true; if ($GLOBALS['text_dir'] === 'ltr') { $right = 'right'; @@ -310,51 +351,61 @@ function loadCss(&$type) $left = 'right'; } - include $_css_file; - - if ($type != 'print') { - $_sprites_data_file = $this->getPath() . '/sprites.lib.php'; - $_sprites_css_file = './themes/sprites.css.php'; - if ( (file_exists($_sprites_data_file) && is_readable($_sprites_data_file)) - && (file_exists($_sprites_css_file) && is_readable($_sprites_css_file)) - ) { - include $_sprites_data_file; - include $_sprites_css_file; + foreach ($this->_cssFiles as $file) { + $path = $this->getPath() . "/css/$file.css.php"; + $fallback = "./themes/" + . PMA_Theme_Manager::FALLBACK_THEME . "/css/$file.css.php"; + + if (is_readable($path)) { + echo "\n/* FILE: $file.css.php */\n"; + include $path; + } else if (is_readable($fallback)) { + echo "\n/* FILE: $file.css.php */\n"; + include $fallback; + } else { + $success = false; } } - return true; + include './themes/sprites.css.php'; + + return $success; } /** - * prints out the preview for this theme + * Renders the preview for this theme * - * @access public + * @return string + * @access public */ - function printPreview() + public function getPrintPreview() { - echo ''; + return $retval; } /** @@ -362,12 +413,32 @@ function printPreview() * * @return string CSS code. */ - function getCssIEClearFilter() { - return PMA_USR_BROWSER_AGENT == 'IE' && PMA_USR_BROWSER_VER >= 6 && PMA_USR_BROWSER_VER <= 8 + function getCssIEClearFilter() + { + return PMA_USR_BROWSER_AGENT == 'IE' + && PMA_USR_BROWSER_VER >= 6 + && PMA_USR_BROWSER_VER <= 8 ? 'filter: none' : ''; } + /** + * Gets currently configured font size. + * + * @return String with font size. + */ + function getFontSize() + { + $fs = $GLOBALS['PMA_Config']->get('fontsize'); + if (!is_null($fs)) { + return $fs; + } + if (isset($_COOKIE['pma_fontsize'])) { + return $_COOKIE['pma_fontsize']; + } + return '82%'; + } + /** * Generates code for CSS gradient using various browser extensions. * @@ -380,66 +451,35 @@ function getCssGradient($start_color, $end_color) { $result = array(); // Opera 9.5+, IE 9 - $result[] = 'background-image: url(./themes/svg_gradient.php?from=' . $start_color . '&to=' . $end_color . ');'; + $result[] = 'background-image: url(./themes/svg_gradient.php?from=' + . $start_color . '&to=' . $end_color . ');'; $result[] = 'background-size: 100% 100%;'; // Safari 4-5, Chrome 1-9 - $result[] = 'background: -webkit-gradient(linear, left top, left bottom, from(#' . $start_color . '), to(#' . $end_color . '));'; + $result[] = 'background: ' + . '-webkit-gradient(linear, left top, left bottom, from(#' + . $start_color . '), to(#' . $end_color . '));'; // Safari 5.1, Chrome 10+ - $result[] = 'background: -webkit-linear-gradient(top, #' . $start_color . ', #' . $end_color . ');'; + $result[] = 'background: -webkit-linear-gradient(top, #' + . $start_color . ', #' . $end_color . ');'; // Firefox 3.6+ - $result[] = 'background: -moz-linear-gradient(top, #' . $start_color . ', #' . $end_color . ');'; + $result[] = 'background: -moz-linear-gradient(top, #' + . $start_color . ', #' . $end_color . ');'; // IE 10 - $result[] = 'background: -ms-linear-gradient(top, #' . $start_color . ', #' . $end_color . ');'; + $result[] = 'background: -ms-linear-gradient(top, #' + . $start_color . ', #' . $end_color . ');'; // Opera 11.10 - $result[] = 'background: -o-linear-gradient(top, #' . $start_color . ', #' . $end_color . ');'; + $result[] = 'background: -o-linear-gradient(top, #' + . $start_color . ', #' . $end_color . ');'; // IE 6-8 - if (PMA_USR_BROWSER_AGENT == 'IE' && PMA_USR_BROWSER_VER >= 6 && PMA_USR_BROWSER_VER <= 8) { - $result[] = 'filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#' . $start_color . '", endColorstr="#' . $end_color . '");'; + if (PMA_USR_BROWSER_AGENT == 'IE' + && PMA_USR_BROWSER_VER >= 6 + && PMA_USR_BROWSER_VER <= 8 + ) { + $result[] = 'filter: ' + . 'progid:DXImageTransform.Microsoft.gradient(startColorstr="#' + . $start_color . '", endColorstr="#' . $end_color . '");'; } return implode("\n", $result); } - - /** - * Returns CSS styles for CodeMirror editor based on query formatter colors. - * - * @return string CSS code. - */ - function getCssCodeMirror() - { - $result[] = 'span.cm-keyword, span.cm-statement-verb {'; - $result[] = ' color: ' . $GLOBALS['cfg']['SQP']['fmtColor']['alpha_reservedWord'] . ';'; - $result[] = '}'; - $result[] = 'span.cm-variable {'; - $result[] = ' color: ' . $GLOBALS['cfg']['SQP']['fmtColor']['alpha_identifier'] . ';'; - $result[] = '}'; - $result[] = 'span.cm-comment {'; - $result[] = ' color: ' . $GLOBALS['cfg']['SQP']['fmtColor']['comment'] . ';'; - $result[] = '}'; - $result[] = 'span.cm-mysql-string {'; - $result[] = ' color: ' . $GLOBALS['cfg']['SQP']['fmtColor']['quote'] . ';'; - $result[] = '}'; - $result[] = 'span.cm-operator {'; - $result[] = ' color: ' . $GLOBALS['cfg']['SQP']['fmtColor']['punct'] . ';'; - $result[] = '}'; - $result[] = 'span.cm-mysql-word {'; - $result[] = ' color: ' . $GLOBALS['cfg']['SQP']['fmtColor']['alpha_identifier'] . ';'; - $result[] = '}'; - $result[] = 'span.cm-builtin {'; - $result[] = ' color: ' . $GLOBALS['cfg']['SQP']['fmtColor']['alpha_functionName'] . ';'; - $result[] = '}'; - $result[] = 'span.cm-variable-2 {'; - $result[] = ' color: ' . $GLOBALS['cfg']['SQP']['fmtColor']['alpha_columnType'] . ';'; - $result[] = '}'; - $result[] = 'span.cm-variable-3 {'; - $result[] = ' color: ' . $GLOBALS['cfg']['SQP']['fmtColor']['alpha_columnAttrib'] . ';'; - $result[] = '}'; - $result[] = 'span.cm-separator {'; - $result[] = ' color: ' . $GLOBALS['cfg']['SQP']['fmtColor']['punct'] . ';'; - $result[] = '}'; - $result[] = 'span.cm-number {'; - $result[] = ' color: ' . $GLOBALS['cfg']['SQP']['fmtColor']['digit_integer'] . ';'; - $result[] = '}'; - return implode("\n", $result); - } } ?> diff --git a/phpMyAdmin/libraries/Theme_Manager.class.php b/phpMyAdmin/libraries/Theme_Manager.class.php index 68468e1..d12689e 100644 --- a/phpMyAdmin/libraries/Theme_Manager.class.php +++ b/phpMyAdmin/libraries/Theme_Manager.class.php @@ -1,11 +1,16 @@ init(); } @@ -55,10 +70,12 @@ function __construct() /** * sets path to folder containing the themes * - * @param string $path path to themes folder - * @return boolean success + * @param string $path path to themes folder + * + * @access public + * @return boolean success */ - function setThemesPath($path) + public function setThemesPath($path) { if (! $this->_checkThemeFolder($path)) { return false; @@ -69,10 +86,12 @@ function setThemesPath($path) } /** - * @public - * @return string + * Returns path to folder containing themes + * + * @access public + * @return string theme path */ - function getThemesPath() + public function getThemesPath() { return $this->_themes_path; } @@ -80,17 +99,26 @@ function getThemesPath() /** * sets if there are different themes per server * - * @param boolean $per_server + * @param boolean $per_server Whether to enable per server flag + * + * @access public + * @return void */ - function setThemePerServer($per_server) + public function setThemePerServer($per_server) { $this->per_server = (bool) $per_server; } - function init() + /** + * Initialise the class + * + * @access public + * @return boolean|void + */ + public function init() { $this->themes = array(); - $this->theme_default = 'original'; + $this->theme_default = self::FALLBACK_THEME; $this->active_theme = ''; if (! $this->setThemesPath($GLOBALS['cfg']['ThemePath'])) { @@ -109,9 +137,9 @@ function init() sprintf( __('Default theme %s not found!'), htmlspecialchars($GLOBALS['cfg']['ThemeDefault']) - ), + ), E_USER_ERROR - ); + ); $GLOBALS['cfg']['ThemeDefault'] = false; } @@ -119,21 +147,29 @@ function init() // check if user have a theme cookie if (! $this->getThemeCookie() - || ! $this->setActiveTheme($this->getThemeCookie())) { - // otherwise use default theme + || ! $this->setActiveTheme($this->getThemeCookie()) + ) { if ($GLOBALS['cfg']['ThemeDefault']) { - $this->setActiveTheme($GLOBALS['cfg']['ThemeDefault']); + // otherwise use default theme + $this->setActiveTheme($this->theme_default); } else { - // or original theme - $this->setActiveTheme('original'); + // or fallback theme + $this->setActiveTheme(self::FALLBACK_THEME); } } } - function checkConfig() + /** + * Checks configuration + * + * @access public + * @return void + */ + public function checkConfig() { if ($this->_themes_path != trim($GLOBALS['cfg']['ThemePath']) - || $this->theme_default != $GLOBALS['cfg']['ThemeDefault']) { + || $this->theme_default != $GLOBALS['cfg']['ThemeDefault'] + ) { $this->init(); } else { // at least the theme path needs to be checked every time for new @@ -143,7 +179,15 @@ function checkConfig() } } - function setActiveTheme($theme = null) + /** + * Sets active theme + * + * @param string $theme theme name + * + * @access public + * @return bool true on success + */ + public function setActiveTheme($theme = null) { if (! $this->checkTheme($theme)) { trigger_error( @@ -151,7 +195,8 @@ function setActiveTheme($theme = null) __('Theme %s not found!'), htmlspecialchars($theme) ), - E_USER_ERROR); + E_USER_ERROR + ); return false; } @@ -165,9 +210,12 @@ function setActiveTheme($theme = null) } /** - * @return string cookie name + * Returns name for storing theme + * + * @return string cookie name + * @access public */ - function getThemeCookieName() + public function getThemeCookieName() { // Allow different theme per server if (isset($GLOBALS['server']) && $this->per_server) { @@ -179,9 +227,11 @@ function getThemeCookieName() /** * returns name of theme stored in the cookie - * @return string theme name from cookie + * + * @return string theme name from cookie + * @access public */ - function getThemeCookie() + public function getThemeCookie() { if (isset($_COOKIE[$this->getThemeCookieName()])) { return $_COOKIE[$this->getThemeCookieName()]; @@ -194,11 +244,15 @@ function getThemeCookie() * save theme in cookie * * @return bool true + * @access public */ - function setThemeCookie() + public function setThemeCookie() { - $GLOBALS['PMA_Config']->setCookie($this->getThemeCookieName(), $this->theme->id, - $this->theme_default); + $GLOBALS['PMA_Config']->setCookie( + $this->getThemeCookieName(), + $this->theme->id, + $this->theme_default + ); // force a change of a dummy session variable to avoid problems // with the caching of phpmyadmin.css.php $GLOBALS['PMA_Config']->set('theme-update', $this->theme->id); @@ -206,17 +260,23 @@ function setThemeCookie() } /** - * @private - * @param string $folder - * @return boolean + * Checks whether folder is valid for storing themes + * + * @param string $folder Folder name to test + * + * @return boolean + * @access private */ private function _checkThemeFolder($folder) { if (! is_dir($folder)) { trigger_error( - sprintf(__('Theme path not found for theme %s!'), - htmlspecialchars($folder)), - E_USER_ERROR); + sprintf( + __('Theme path not found for theme %s!'), + htmlspecialchars($folder) + ), + E_USER_ERROR + ); return false; } @@ -227,8 +287,9 @@ private function _checkThemeFolder($folder) * read all themes * * @return bool true + * @access public */ - function loadThemes() + public function loadThemes() { $this->themes = array(); @@ -236,13 +297,18 @@ function loadThemes() // check for themes directory while (false !== ($PMA_Theme = readdir($handleThemes))) { // Skip non dirs, . and .. - if ($PMA_Theme == '.' || $PMA_Theme == '..' || ! is_dir($this->getThemesPath() . '/' . $PMA_Theme)) { + if ($PMA_Theme == '.' + || $PMA_Theme == '..' + || ! is_dir($this->getThemesPath() . '/' . $PMA_Theme) + ) { continue; } if (array_key_exists($PMA_Theme, $this->themes)) { continue; } - $new_theme = PMA_Theme::load($this->getThemesPath() . '/' . $PMA_Theme); + $new_theme = PMA_Theme::load( + $this->getThemesPath() . '/' . $PMA_Theme + ); if ($new_theme) { $new_theme->setId($PMA_Theme); $this->themes[$PMA_Theme] = $new_theme; @@ -251,8 +317,10 @@ function loadThemes() closedir($handleThemes); } else { trigger_error( - 'phpMyAdmin-ERROR: cannot open themes folder: ' . $this->getThemesPath(), - E_USER_WARNING); + 'phpMyAdmin-ERROR: cannot open themes folder: ' + . $this->getThemesPath(), + E_USER_WARNING + ); return false; } // end check for themes directory @@ -263,10 +331,12 @@ function loadThemes() /** * checks if given theme name is a known theme * - * @param string $theme name fo theme to check for + * @param string $theme name fo theme to check for + * * @return bool + * @access public */ - function checkTheme($theme) + public function checkTheme($theme) { if (! array_key_exists($theme, $this->themes)) { return false; @@ -278,35 +348,39 @@ function checkTheme($theme) /** * returns HTML selectbox, with or without form enclosed * - * @param boolean $form whether enclosed by from tags or not + * @param boolean $form whether enclosed by from tags or not + * * @return string + * @access public */ - function getHtmlSelectBox($form = true) + public function getHtmlSelectBox($form = true) { $select_box = ''; if ($form) { - $select_box .= '
    '; - $select_box .= PMA_generate_common_hidden_inputs(); + $select_box .= ''; - $select_box .= $theme_preview_href . __('Theme') . ':' . "\n"; + $theme_preview_href = ''; + $select_box .= $theme_preview_href . __('Theme:') . '' . "\n"; - $select_box .= ''; foreach ($this->themes as $each_theme_id => $each_theme) { $select_box .= ''; + $select_box .= '>' . htmlspecialchars($each_theme->getName()) + . ''; } $select_box .= ''; if ($form) { - $select_box .= ''; $select_box .= '
    '; } @@ -315,8 +389,11 @@ function getHtmlSelectBox($form = true) /** * enables backward compatibility + * + * @return void + * @access public */ - function makeBc() + public function makeBc() { $GLOBALS['theme'] = $this->theme->getId(); $GLOBALS['pmaThemePath'] = $this->theme->getPath(); @@ -328,29 +405,33 @@ function makeBc() if (file_exists($this->theme->getLayoutFile())) { include $this->theme->getLayoutFile(); } - - } /** - * prints out preview for every theme + * Renders the previews for all themes * + * @return string + * @access public */ - function printPreviews() + public function getPrintPreviews() { + $retval = ''; foreach ($this->themes as $each_theme) { - $each_theme->printPreview(); + $retval .= $each_theme->getPrintPreview(); } // end 'open themes' + return $retval; } /** * returns PMA_Theme object for fall back theme - * @return object PMA_Theme + * + * @return PMA_Theme fall back theme + * @access public */ - function getFallBackTheme() + public function getFallBackTheme() { - if (isset($this->themes['original'])) { - return $this->themes['original']; + if (isset($this->themes[self::FALLBACK_THEME])) { + return $this->themes[self::FALLBACK_THEME]; } return false; @@ -359,18 +440,18 @@ function getFallBackTheme() /** * prints css data * - * @param string $type * @return bool + * @access public */ - function printCss($type) + public function printCss() { - if ($this->theme->loadCss($type)) { + if ($this->theme->loadCss()) { return true; } // if loading css for this theme failed, try default theme css $fallback_theme = $this->getFallBackTheme(); - if ($fallback_theme && $fallback_theme->loadCss($type)) { + if ($fallback_theme && $fallback_theme->loadCss()) { return true; } diff --git a/phpMyAdmin/libraries/Tracker.class.php b/phpMyAdmin/libraries/Tracker.class.php index 2f50623..d4dab00 100644 --- a/phpMyAdmin/libraries/Tracker.class.php +++ b/phpMyAdmin/libraries/Tracker.class.php @@ -1,13 +1,16 @@ fetchArray(PMA_queryAsControlUser($sql_query)); if (isset($row['tracking_active']) && $row['tracking_active'] == 1) { return true; @@ -234,15 +250,26 @@ static public function getLogComment() * * @return int result of version insertion */ - static public function createVersion($dbname, $tablename, $version, $tracking_set = '', $is_view = false) - { - global $sql_backquotes; + static public function createVersion($dbname, $tablename, $version, + $tracking_set = '', $is_view = false + ) { + global $sql_backquotes, $export_type; if ($tracking_set == '') { $tracking_set = self::$default_tracking_set; } - include_once './libraries/export/sql.php'; + // get Export SQL instance + include_once "libraries/plugin_interface.lib.php"; + $export_sql_plugin = PMA_getPlugin( + "export", + "sql", + 'libraries/plugins/export/', + array( + 'export_type' => $export_type, + 'single_table' => false, + ) + ); $sql_backquotes = true; @@ -250,7 +277,7 @@ static public function createVersion($dbname, $tablename, $version, $tracking_se // Get data definition snapshot of table - $columns = PMA_DBI_get_columns($dbname, $tablename, null, true); + $columns = $GLOBALS['dbi']->getColumns($dbname, $tablename, null, true); // int indices to reduce size $columns = array_values($columns); // remove Privileges to reduce size @@ -258,7 +285,7 @@ static public function createVersion($dbname, $tablename, $version, $tracking_se unset($columns[$i]['Privileges']); } - $indexes = PMA_DBI_get_table_indexes($dbname, $tablename); + $indexes = $GLOBALS['dbi']->getTableIndexes($dbname, $tablename); $snapshot = array('COLUMNS' => $columns, 'INDEXES' => $indexes); $snapshot = serialize($snapshot); @@ -269,18 +296,18 @@ static public function createVersion($dbname, $tablename, $version, $tracking_se $create_sql = ""; if (self::$add_drop_table == true && $is_view == false) { - $create_sql .= self::getLogComment() . - 'DROP TABLE IF EXISTS ' . PMA_backquote($tablename) . ";\n"; + $create_sql .= self::getLogComment() + . 'DROP TABLE IF EXISTS ' . PMA_Util::backquote($tablename) . ";\n"; } if (self::$add_drop_view == true && $is_view == true) { - $create_sql .= self::getLogComment() . - 'DROP VIEW IF EXISTS ' . PMA_backquote($tablename) . ";\n"; + $create_sql .= self::getLogComment() + . 'DROP VIEW IF EXISTS ' . PMA_Util::backquote($tablename) . ";\n"; } $create_sql .= self::getLogComment() . - PMA_getTableDef($dbname, $tablename, "\n", ""); + $export_sql_plugin->getTableDef($dbname, $tablename, "\n", ""); // Save version @@ -297,17 +324,18 @@ static public function createVersion($dbname, $tablename, $version, $tracking_se "tracking " . ") " . "values ( - '" . PMA_sqlAddSlashes($dbname) . "', - '" . PMA_sqlAddSlashes($tablename) . "', - '" . PMA_sqlAddSlashes($version) . "', - '" . PMA_sqlAddSlashes($date) . "', - '" . PMA_sqlAddSlashes($date) . "', - '" . PMA_sqlAddSlashes($snapshot) . "', - '" . PMA_sqlAddSlashes($create_sql) . "', - '" . PMA_sqlAddSlashes("\n") . "', - '" . PMA_sqlAddSlashes(self::transformTrackingSet($tracking_set)) . "' )"; - - $result = PMA_query_as_controluser($sql_query); + '" . PMA_Util::sqlAddSlashes($dbname) . "', + '" . PMA_Util::sqlAddSlashes($tablename) . "', + '" . PMA_Util::sqlAddSlashes($version) . "', + '" . PMA_Util::sqlAddSlashes($date) . "', + '" . PMA_Util::sqlAddSlashes($date) . "', + '" . PMA_Util::sqlAddSlashes($snapshot) . "', + '" . PMA_Util::sqlAddSlashes($create_sql) . "', + '" . PMA_Util::sqlAddSlashes("\n") . "', + '" . PMA_Util::sqlAddSlashes(self::_transformTrackingSet($tracking_set)) + . "' )"; + + $result = PMA_queryAsControlUser($sql_query); if ($result) { // Deactivate previous version @@ -330,9 +358,13 @@ static public function createVersion($dbname, $tablename, $version, $tracking_se */ static public function deleteTracking($dbname, $tablename) { - $sql_query = "/*NOTRACK*/\n" . - "DELETE FROM " . self::$pma_table . " WHERE `db_name` = '" . PMA_sqlAddSlashes($dbname) . "' AND `table_name` = '" . PMA_sqlAddSlashes($tablename) . "'"; - $result = PMA_query_as_controluser($sql_query); + $sql_query = "/*NOTRACK*/\n" + . "DELETE FROM " . self::$pma_table + . " WHERE `db_name` = '" + . PMA_Util::sqlAddSlashes($dbname) . "'" + . " AND `table_name` = '" + . PMA_Util::sqlAddSlashes($tablename) . "'"; + $result = PMA_queryAsControlUser($sql_query); return $result; } @@ -350,21 +382,20 @@ static public function deleteTracking($dbname, $tablename) * * @return int result of version insertion */ - static public function createDatabaseVersion($dbname, $version, $query, $tracking_set = 'CREATE DATABASE,ALTER DATABASE,DROP DATABASE') - { + static public function createDatabaseVersion($dbname, $version, $query, + $tracking_set = 'CREATE DATABASE,ALTER DATABASE,DROP DATABASE' + ) { $date = date('Y-m-d H:i:s'); if ($tracking_set == '') { $tracking_set = self::$default_tracking_set; } - include_once './libraries/export/sql.php'; - $create_sql = ""; if (self::$add_drop_database == true) { - $create_sql .= self::getLogComment() . - 'DROP DATABASE IF EXISTS ' . PMA_backquote($dbname) . ";\n"; + $create_sql .= self::getLogComment() + . 'DROP DATABASE IF EXISTS ' . PMA_Util::backquote($dbname) . ";\n"; } $create_sql .= self::getLogComment() . $query; @@ -383,17 +414,18 @@ static public function createDatabaseVersion($dbname, $version, $query, $trackin "tracking " . ") " . "values ( - '" . PMA_sqlAddSlashes($dbname) . "', - '" . PMA_sqlAddSlashes('') . "', - '" . PMA_sqlAddSlashes($version) . "', - '" . PMA_sqlAddSlashes($date) . "', - '" . PMA_sqlAddSlashes($date) . "', - '" . PMA_sqlAddSlashes('') . "', - '" . PMA_sqlAddSlashes($create_sql) . "', - '" . PMA_sqlAddSlashes("\n") . "', - '" . PMA_sqlAddSlashes(self::transformTrackingSet($tracking_set)) . "' )"; - - $result = PMA_query_as_controluser($sql_query); + '" . PMA_Util::sqlAddSlashes($dbname) . "', + '" . PMA_Util::sqlAddSlashes('') . "', + '" . PMA_Util::sqlAddSlashes($version) . "', + '" . PMA_Util::sqlAddSlashes($date) . "', + '" . PMA_Util::sqlAddSlashes($date) . "', + '" . PMA_Util::sqlAddSlashes('') . "', + '" . PMA_Util::sqlAddSlashes($create_sql) . "', + '" . PMA_Util::sqlAddSlashes("\n") . "', + '" . PMA_Util::sqlAddSlashes(self::_transformTrackingSet($tracking_set)) + . "' )"; + + $result = PMA_queryAsControlUser($sql_query); return $result; } @@ -412,15 +444,17 @@ static public function createDatabaseVersion($dbname, $version, $query, $trackin * * @return int result of SQL query */ - static private function _changeTracking($dbname, $tablename, $version, $new_state) - { + static private function _changeTracking($dbname, $tablename, + $version, $new_state + ) { + $sql_query = " UPDATE " . self::$pma_table . " SET `tracking_active` = '" . $new_state . "' " . - " WHERE `db_name` = '" . PMA_sqlAddSlashes($dbname) . "' " . - " AND `table_name` = '" . PMA_sqlAddSlashes($tablename) . "' " . - " AND `version` = '" . PMA_sqlAddSlashes($version) . "' "; + " WHERE `db_name` = '" . PMA_Util::sqlAddSlashes($dbname) . "' " . + " AND `table_name` = '" . PMA_Util::sqlAddSlashes($tablename) . "' " . + " AND `version` = '" . PMA_Util::sqlAddSlashes($version) . "' "; - $result = PMA_query_as_controluser($sql_query); + $result = PMA_queryAsControlUser($sql_query); return $result; } @@ -438,8 +472,9 @@ static private function _changeTracking($dbname, $tablename, $version, $new_stat * * @return bool result of change */ - static public function changeTrackingData($dbname, $tablename, $version, $type, $new_data) - { + static public function changeTrackingData($dbname, $tablename, + $version, $type, $new_data + ) { if ($type == 'DDL') { $save_to = 'schema_sql'; } elseif ($type == 'DML') { @@ -453,7 +488,7 @@ static public function changeTrackingData($dbname, $tablename, $version, $type, if (is_array($new_data)) { foreach ($new_data as $data) { $new_data_processed .= '# log ' . $date . ' ' . $data['username'] - . PMA_sqlAddSlashes($data['statement']) . "\n"; + . PMA_Util::sqlAddSlashes($data['statement']) . "\n"; } } else { $new_data_processed = $new_data; @@ -461,11 +496,11 @@ static public function changeTrackingData($dbname, $tablename, $version, $type, $sql_query = " UPDATE " . self::$pma_table . " SET `" . $save_to . "` = '" . $new_data_processed . "' " . - " WHERE `db_name` = '" . PMA_sqlAddSlashes($dbname) . "' " . - " AND `table_name` = '" . PMA_sqlAddSlashes($tablename) . "' " . - " AND `version` = '" . PMA_sqlAddSlashes($version) . "' "; + " WHERE `db_name` = '" . PMA_Util::sqlAddSlashes($dbname) . "' " . + " AND `table_name` = '" . PMA_Util::sqlAddSlashes($tablename) . "' " . + " AND `version` = '" . PMA_Util::sqlAddSlashes($version) . "' "; - $result = PMA_query_as_controluser($sql_query); + $result = PMA_queryAsControlUser($sql_query); return $result; } @@ -519,15 +554,19 @@ static public function deactivateTracking($dbname, $tablename, $version) static public function getVersion($dbname, $tablename, $statement = null) { $sql_query = " SELECT MAX(version) FROM " . self::$pma_table . - " WHERE `db_name` = '" . PMA_sqlAddSlashes($dbname) . "' " . - " AND `table_name` = '" . PMA_sqlAddSlashes($tablename) . "' "; + " WHERE `db_name` = '" . PMA_Util::sqlAddSlashes($dbname) . "' " . + " AND `table_name` = '" . PMA_Util::sqlAddSlashes($tablename) . "' "; if ($statement != "") { - $sql_query .= PMA_DRIZZLE - ? ' AND tracking & ' . self::transformTrackingSet($statement) . ' <> 0' - : " AND FIND_IN_SET('" . $statement . "',tracking) > 0" ; + if (PMA_DRIZZLE) { + $sql_query .= ' AND tracking & ' + . self::_transformTrackingSet($statement) . ' <> 0'; + } else { + $sql_query .= " AND FIND_IN_SET('" + . $statement . "',tracking) > 0" ; + } } - $row = PMA_DBI_fetch_array(PMA_query_as_controluser($sql_query)); + $row = $GLOBALS['dbi']->fetchArray(PMA_queryAsControlUser($sql_query)); return isset($row[0]) ? $row[0] : -1; @@ -543,7 +582,8 @@ static public function getVersion($dbname, $tablename, $statement = null) * * @static * - * @return mixed record DDM log, DDL log, structure snapshot, tracked statements. + * @return mixed record DDM log, DDL log, structure snapshot, tracked + * statements. */ static public function getTrackedData($dbname, $tablename, $version) { @@ -551,14 +591,15 @@ static public function getTrackedData($dbname, $tablename, $version) self::init(); } $sql_query = " SELECT * FROM " . self::$pma_table . - " WHERE `db_name` = '" . PMA_sqlAddSlashes($dbname) . "' "; + " WHERE `db_name` = '" . PMA_Util::sqlAddSlashes($dbname) . "' "; if (! empty($tablename)) { - $sql_query .= " AND `table_name` = '" . PMA_sqlAddSlashes($tablename) ."' "; + $sql_query .= " AND `table_name` = '" + . PMA_Util::sqlAddSlashes($tablename) ."' "; } - $sql_query .= " AND `version` = '" . PMA_sqlAddSlashes($version) ."' ". - " ORDER BY `version` DESC LIMIT 1"; + $sql_query .= " AND `version` = '" . PMA_Util::sqlAddSlashes($version) + . "' " . " ORDER BY `version` DESC LIMIT 1"; - $mixed = PMA_DBI_fetch_assoc(PMA_query_as_controluser($sql_query)); + $mixed = $GLOBALS['dbi']->fetchAssoc(PMA_queryAsControlUser($sql_query)); // Parse log $log_schema_entries = explode('# log ', $mixed['schema_sql']); @@ -588,7 +629,7 @@ static public function getTrackedData($dbname, $tablename, $version) } $date_from = $ddl_date_from; - $date_to = $ddl_date_to = $date; + $ddl_date_to = $date; $dml_date_from = $date_from; @@ -628,7 +669,7 @@ static public function getTrackedData($dbname, $tablename, $version) } $data['ddlog'] = $ddlog; $data['dmlog'] = $dmlog; - $data['tracking'] = self::transformTrackingSet($mixed['tracking']); + $data['tracking'] = self::_transformTrackingSet($mixed['tracking']); $data['schema_snapshot'] = $mixed['schema_snapshot']; return $data; @@ -691,7 +732,9 @@ static public function parseQuery($query) $index = array_search('VIEW', $tokens); - $result['tablename'] = strtolower(self::getTableName($tokens[$index + 1])); + $result['tablename'] = strtolower( + self::getTableName($tokens[$index + 1]) + ); } // Parse ALTER VIEW statement @@ -704,11 +747,15 @@ static public function parseQuery($query) $index = array_search('VIEW', $tokens); - $result['tablename'] = strtolower(self::getTableName($tokens[$index + 1])); + $result['tablename'] = strtolower( + self::getTableName($tokens[$index + 1]) + ); } // Parse DROP VIEW statement - if (! isset($result['identifier']) && substr($query, 0, 10) == 'DROP VIEW ') { + if (! isset($result['identifier']) + && substr($query, 0, 10) == 'DROP VIEW ' + ) { $result['identifier'] = 'DROP VIEW'; $prefix = explode('DROP VIEW ', $query); @@ -721,7 +768,9 @@ static public function parseQuery($query) } // Parse CREATE DATABASE statement - if (! isset($result['identifier']) && substr($query, 0, 15) == 'CREATE DATABASE') { + if (! isset($result['identifier']) + && substr($query, 0, 15) == 'CREATE DATABASE' + ) { $result['identifier'] = 'CREATE DATABASE'; $str = str_replace('CREATE DATABASE', '', $query); $str = str_replace('IF NOT EXISTS', '', $str); @@ -733,13 +782,17 @@ static public function parseQuery($query) } // Parse ALTER DATABASE statement - if (! isset($result['identifier']) && substr($query, 0, 14) == 'ALTER DATABASE') { + if (! isset($result['identifier']) + && substr($query, 0, 14) == 'ALTER DATABASE' + ) { $result['identifier'] = 'ALTER DATABASE'; $result['tablename'] = ''; } // Parse DROP DATABASE statement - if (! isset($result['identifier']) && substr($query, 0, 13) == 'DROP DATABASE') { + if (! isset($result['identifier']) + && substr($query, 0, 13) == 'DROP DATABASE' + ) { $result['identifier'] = 'DROP DATABASE'; $str = str_replace('DROP DATABASE', '', $query); $str = str_replace('IF EXISTS', '', $str); @@ -748,7 +801,9 @@ static public function parseQuery($query) } // Parse CREATE TABLE statement - if (! isset($result['identifier']) && substr($query, 0, 12) == 'CREATE TABLE' ) { + if (! isset($result['identifier']) + && substr($query, 0, 12) == 'CREATE TABLE' + ) { $result['identifier'] = 'CREATE TABLE'; $query = str_replace('IF NOT EXISTS', '', $query); $prefix = explode('CREATE TABLE ', $query); @@ -757,7 +812,9 @@ static public function parseQuery($query) } // Parse ALTER TABLE statement - if (! isset($result['identifier']) && substr($query, 0, 12) == 'ALTER TABLE ') { + if (! isset($result['identifier']) + && substr($query, 0, 12) == 'ALTER TABLE ' + ) { $result['identifier'] = 'ALTER TABLE'; $prefix = explode('ALTER TABLE ', $query); @@ -766,7 +823,9 @@ static public function parseQuery($query) } // Parse DROP TABLE statement - if (! isset($result['identifier']) && substr($query, 0, 11) == 'DROP TABLE ') { + if (! isset($result['identifier']) + && substr($query, 0, 11) == 'DROP TABLE ' + ) { $result['identifier'] = 'DROP TABLE'; $prefix = explode('DROP TABLE ', $query); @@ -791,14 +850,18 @@ static public function parseQuery($query) } // Parse DROP INDEX statement - if (! isset($result['identifier']) && substr($query, 0, 10) == 'DROP INDEX') { + if (! isset($result['identifier']) + && substr($query, 0, 10) == 'DROP INDEX' + ) { $result['identifier'] = 'DROP INDEX'; $prefix = explode('ON ', $query); $result['tablename'] = self::getTableName($prefix[1]); } // Parse RENAME TABLE statement - if (! isset($result['identifier']) && substr($query, 0, 13) == 'RENAME TABLE ') { + if (! isset($result['identifier']) + && substr($query, 0, 13) == 'RENAME TABLE ' + ) { $result['identifier'] = 'RENAME TABLE'; $prefix = explode('RENAME TABLE ', $query); $names = explode(' TO ', $prefix[1]); @@ -814,7 +877,9 @@ static public function parseQuery($query) $result["type"] = 'DML'; } // Parse UPDATE statement - if (! isset($result['identifier']) && substr($query, 0, 6) == 'UPDATE') { + if (! isset($result['identifier']) + && substr($query, 0, 6) == 'UPDATE' + ) { $result['identifier'] = 'UPDATE'; $prefix = explode('UPDATE ', $query); $suffix = explode(' ', $prefix[1]); @@ -822,7 +887,9 @@ static public function parseQuery($query) } // Parse INSERT INTO statement - if (! isset($result['identifier']) && substr($query, 0, 11) == 'INSERT INTO') { + if (! isset($result['identifier']) + && substr($query, 0, 11) == 'INSERT INTO' + ) { $result['identifier'] = 'INSERT'; $prefix = explode('INSERT INTO', $query); $suffix = explode('(', $prefix[1]); @@ -830,7 +897,9 @@ static public function parseQuery($query) } // Parse DELETE statement - if (! isset($result['identifier']) && substr($query, 0, 6) == 'DELETE') { + if (! isset($result['identifier']) + && substr($query, 0, 6) == 'DELETE' + ) { $result['identifier'] = 'DELETE'; $prefix = explode('FROM ', $query); $suffix = explode(' ', $prefix[1]); @@ -838,7 +907,9 @@ static public function parseQuery($query) } // Parse TRUNCATE statement - if (! isset($result['identifier']) && substr($query, 0, 8) == 'TRUNCATE') { + if (! isset($result['identifier']) + && substr($query, 0, 8) == 'TRUNCATE' + ) { $result['identifier'] = 'TRUNCATE'; $prefix = explode('TRUNCATE', $query); $result['tablename'] = self::getTableName($prefix[1]); @@ -855,7 +926,7 @@ static public function parseQuery($query) * * @static * - * @return nothing + * @return void */ static public function handleQuery($query) { @@ -871,16 +942,21 @@ static public function handleQuery($query) $result = self::parseQuery($query); // Get database name - $dbname = trim($GLOBALS['db'], '`'); + $dbname = trim(isset($GLOBALS['db']) ? $GLOBALS['db'] : '', '`'); // $dbname can be empty, for example when coming from Synchronize // and this is a query for the remote server if (empty($dbname)) { return; } + // Remove null bytes (preg_replace() is vulnerable in some + // PHP versions) + $dbname = str_replace("\0", "", $dbname); // If we found a valid statement if (isset($result['identifier'])) { - $version = self::getVersion($dbname, $result['tablename'], $result['identifier']); + $version = self::getVersion( + $dbname, $result['tablename'], $result['identifier'] + ); // If version not exists and auto-creation is enabled if (self::$version_auto_create == true @@ -894,7 +970,9 @@ static public function handleQuery($query) self::createVersion($dbname, $result['tablename'], '1'); break; case 'CREATE VIEW': - self::createVersion($dbname, $result['tablename'], '1', '', true); + self::createVersion( + $dbname, $result['tablename'], '1', '', true + ); break; case 'CREATE DATABASE': self::createDatabaseVersion($dbname, '1', $query); @@ -920,14 +998,19 @@ static public function handleQuery($query) $query = self::getLogComment() . $query ; // Mark it as untouchable - $sql_query = " /*NOTRACK*/\n" . - " UPDATE " . self::$pma_table . - " SET " . PMA_backquote($save_to) ." = CONCAT( " . PMA_backquote($save_to) . ",'\n" - . PMA_sqlAddSlashes($query) . "') ," . " `date_updated` = '" . $date . "' "; - - // If table was renamed we have to change the tablename attribute in pma_tracking too + $sql_query = " /*NOTRACK*/\n" + . " UPDATE " . self::$pma_table + . " SET " . PMA_Util::backquote($save_to) + . " = CONCAT( " . PMA_Util::backquote($save_to) . ",'\n" + . PMA_Util::sqlAddSlashes($query) . "') ," + . " `date_updated` = '" . $date . "' "; + + // If table was renamed we have to change + // the tablename attribute in pma_tracking too if ($result['identifier'] == 'RENAME TABLE') { - $sql_query .= ', `table_name` = \'' . PMA_sqlAddSlashes($result['tablename_after_rename']) . '\' '; + $sql_query .= ', `table_name` = \'' + . PMA_Util::sqlAddSlashes($result['tablename_after_rename']) + . '\' '; } // Save the tracking information only for @@ -937,11 +1020,12 @@ static public function handleQuery($query) // we want to track $sql_query .= " WHERE FIND_IN_SET('" . $result['identifier'] . "',tracking) > 0" . - " AND `db_name` = '" . PMA_sqlAddSlashes($dbname) . "' " . - " AND `table_name` = '" . PMA_sqlAddSlashes($result['tablename']) . "' " . - " AND `version` = '" . PMA_sqlAddSlashes($version) . "' "; + " AND `db_name` = '" . PMA_Util::sqlAddSlashes($dbname) . "' " . + " AND `table_name` = '" + . PMA_Util::sqlAddSlashes($result['tablename']) . "' " . + " AND `version` = '" . PMA_Util::sqlAddSlashes($version) . "' "; - $result = PMA_query_as_controluser($sql_query); + $result = PMA_queryAsControlUser($sql_query); } } } @@ -951,36 +1035,38 @@ static public function handleQuery($query) * * Converts int<>string for Drizzle, does nothing for MySQL * - * @param int|string $tracking_set + * @param int|string $tracking_set Set to convert + * * @return int|string */ - static private function transformTrackingSet($tracking_set) + static private function _transformTrackingSet($tracking_set) { if (!PMA_DRIZZLE) { return $tracking_set; } // init conversion array (key 3 doesn't exist in calculated array) - if (isset(self::$tracking_set_flags[3])) { + if (isset(self::$_tracking_set_flags[3])) { // initialize flags - $set = self::$tracking_set_flags; + $set = self::$_tracking_set_flags; $array = array(); for ($i = 0; $i < count($set); $i++) { $flag = 1 << $i; $array[$flag] = $set[$i]; $array[$set[$i]] = $flag; } - self::$tracking_set_flags = $array; + self::$_tracking_set_flags = $array; } if (is_numeric($tracking_set)) { // int > string conversion $aflags = array(); - // count/2 - conversion table has both int > string and string > int values - for ($i = 0; $i < count(self::$tracking_set_flags)/2; $i++) { + // count/2 - conversion table has both int > string + // and string > int values + for ($i = 0; $i < count(self::$_tracking_set_flags)/2; $i++) { $flag = 1 << $i; if ($tracking_set & $flag) { - $aflags[] = self::$tracking_set_flags[$flag]; + $aflags[] = self::$_tracking_set_flags[$flag]; } } $flags = implode(',', $aflags); @@ -991,7 +1077,7 @@ static private function transformTrackingSet($tracking_set) if ($strflag == '') { continue; } - $flags |= self::$tracking_set_flags[$strflag]; + $flags |= self::$_tracking_set_flags[$strflag]; } } diff --git a/phpMyAdmin/libraries/Types.class.php b/phpMyAdmin/libraries/Types.class.php new file mode 100644 index 0000000..455c27d --- /dev/null +++ b/phpMyAdmin/libraries/Types.class.php @@ -0,0 +1,986 @@ +getUnaryOperators()); + } + + /** + * Returns list of operators checking for NULL. + * + * @return array + */ + public function getNullOperators() + { + return array( + 'IS NULL', + 'IS NOT NULL', + ); + } + + /** + * ENUM search operators + * + * @return array + */ + public function getEnumOperators() + { + return array( + '=', + '!=', + ); + } + + /** + * TEXT search operators + * + * @return array + */ + public function getTextOperators() + { + return array( + 'LIKE', + 'LIKE %...%', + 'NOT LIKE', + '=', + '!=', + 'REGEXP', + 'REGEXP ^...$', + 'NOT REGEXP', + "= ''", + "!= ''", + 'IN (...)', + 'NOT IN (...)', + 'BETWEEN', + 'NOT BETWEEN', + ); + } + + /** + * Number search operators + * + * @return array + */ + public function getNumberOperators() + { + return array( + '=', + '>', + '>=', + '<', + '<=', + '!=', + 'LIKE', + 'LIKE %...%', + 'NOT LIKE', + 'IN (...)', + 'NOT IN (...)', + 'BETWEEN', + 'NOT BETWEEN', + ); + } + + /** + * Returns operators for given type + * + * @param string $type Type of field + * @param boolean $null Whether field can be NULL + * + * @return array + */ + public function getTypeOperators($type, $null) + { + $ret = array(); + $class = $this->getTypeClass($type); + + if (strncasecmp($type, 'enum', 4) == 0) { + $ret = array_merge($ret, $this->getEnumOperators()); + } elseif ($class == 'CHAR') { + $ret = array_merge($ret, $this->getTextOperators()); + } else { + $ret = array_merge($ret, $this->getNumberOperators()); + } + + if ($null) { + $ret = array_merge($ret, $this->getNullOperators()); + } + + return $ret; + } + + /** + * Returns operators for given type as html options + * + * @param string $type Type of field + * @param boolean $null Whether field can be NULL + * @param string $selectedOperator Option to be selected + * + * @return string Generated Html + */ + public function getTypeOperatorsHtml($type, $null, $selectedOperator = null) + { + $html = ''; + + foreach ($this->getTypeOperators($type, $null) as $fc) { + if (isset($selectedOperator) && $selectedOperator == $fc) { + $selected = ' selected="selected"'; + } else { + $selected = ''; + } + $html .= ''; + } + + return $html; + } + + /** + * Returns the data type description. + * + * @param string $type The data type to get a description. + * + * @return string + * + */ + public function getTypeDescription($type) + { + return ''; + } + + /** + * Returns class of a type, used for functions available for type + * or default values. + * + * @param string $type The data type to get a class. + * + * @return string + * + */ + public function getTypeClass($type) + { + return ''; + } + + /** + * Returns array of functions available for a class. + * + * @param string $class The class to get function list. + * + * @return array + * + */ + public function getFunctionsClass($class) + { + return array(); + } + + /** + * Returns array of functions available for a type. + * + * @param string $type The data type to get function list. + * + * @return array + * + */ + public function getFunctions($type) + { + $class = $this->getTypeClass($type); + return $this->getFunctionsClass($class); + } + + /** + * Returns array of all functions available. + * + * @return array + * + */ + public function getAllFunctions() + { + $ret = array_merge( + $this->getFunctionsClass('CHAR'), + $this->getFunctionsClass('NUMBER'), + $this->getFunctionsClass('DATE'), + $this->getFunctionsClass('UUID') + ); + sort($ret); + return $ret; + } + + /** + * Returns array of all attributes available. + * + * @return array + * + */ + public function getAttributes() + { + return array(); + } + + /** + * Returns array of all column types available. + * + * @return array + * + */ + public function getColumns() + { + // most used types + return array( + 'INT', + 'VARCHAR', + 'TEXT', + 'DATE', + ); + } +} + +/** + * Class holding type definitions for MySQL. + * + * @package PhpMyAdmin + */ +class PMA_Types_MySQL extends PMA_Types +{ + /** + * Returns the data type description. + * + * @param string $type The data type to get a description. + * + * @return string + * + */ + public function getTypeDescription($type) + { + $type = strtoupper($type); + switch ($type) { + case 'TINYINT': + return __('A 1-byte integer, signed range is -128 to 127, unsigned range is 0 to 255'); + case 'SMALLINT': + return __('A 2-byte integer, signed range is -32,768 to 32,767, unsigned range is 0 to 65,535'); + case 'MEDIUMINT': + return __('A 3-byte integer, signed range is -8,388,608 to 8,388,607, unsigned range is 0 to 16,777,215'); + case 'INT': + return __('A 4-byte integer, signed range is -2,147,483,648 to 2,147,483,647, unsigned range is 0 to 4,294,967,295'); + case 'BIGINT': + return __('An 8-byte integer, signed range is -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807, unsigned range is 0 to 18,446,744,073,709,551,615'); + case 'DECIMAL': + return __('A fixed-point number (M, D) - the maximum number of digits (M) is 65 (default 10), the maximum number of decimals (D) is 30 (default 0)'); + case 'FLOAT': + return __('A small floating-point number, allowable values are -3.402823466E+38 to -1.175494351E-38, 0, and 1.175494351E-38 to 3.402823466E+38'); + case 'DOUBLE': + return __('A double-precision floating-point number, allowable values are -1.7976931348623157E+308 to -2.2250738585072014E-308, 0, and 2.2250738585072014E-308 to 1.7976931348623157E+308'); + case 'REAL': + return __('Synonym for DOUBLE (exception: in REAL_AS_FLOAT SQL mode it is a synonym for FLOAT)'); + case 'BIT': + return __('A bit-field type (M), storing M of bits per value (default is 1, maximum is 64)'); + case 'BOOLEAN': + return __('A synonym for TINYINT(1), a value of zero is considered false, nonzero values are considered true'); + case 'SERIAL': + return __('An alias for BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE'); + case 'DATE': + return sprintf(__('A date, supported range is %1$s to %2$s'), '1000-01-01', '9999-12-31'); + case 'DATETIME': + return sprintf(__('A date and time combination, supported range is %1$s to %2$s'), '1000-01-01 00:00:00', '9999-12-31 23:59:59'); + case 'TIMESTAMP': + return __('A timestamp, range is 1970-01-01 00:00:01 UTC to 2038-01-09 03:14:07 UTC, stored as the number of seconds since the epoch (1970-01-01 00:00:00 UTC)'); + case 'TIME': + return sprintf(__('A time, range is %1$s to %2$s'), '-838:59:59', '838:59:59'); + case 'YEAR': + return __("A year in four-digit (4, default) or two-digit (2) format, the allowable values are 70 (1970) to 69 (2069) or 1901 to 2155 and 0000"); + case 'CHAR': + return __('A fixed-length (0-255, default 1) string that is always right-padded with spaces to the specified length when stored'); + case 'VARCHAR': + return sprintf(__('A variable-length (%s) string, the effective maximum length is subject to the maximum row size'), '0-65,535'); + case 'TINYTEXT': + return __('A TEXT column with a maximum length of 255 (2^8 - 1) characters, stored with a one-byte prefix indicating the length of the value in bytes'); + case 'TEXT': + return __('A TEXT column with a maximum length of 65,535 (2^16 - 1) characters, stored with a two-byte prefix indicating the length of the value in bytes'); + case 'MEDIUMTEXT': + return __('A TEXT column with a maximum length of 16,777,215 (2^24 - 1) characters, stored with a three-byte prefix indicating the length of the value in bytes'); + case 'LONGTEXT': + return __('A TEXT column with a maximum length of 4,294,967,295 or 4GiB (2^32 - 1) characters, stored with a four-byte prefix indicating the length of the value in bytes'); + case 'BINARY': + return __('Similar to the CHAR type, but stores binary byte strings rather than non-binary character strings'); + case 'VARBINARY': + return __('Similar to the VARCHAR type, but stores binary byte strings rather than non-binary character strings'); + case 'TINYBLOB': + return __('A BLOB column with a maximum length of 255 (2^8 - 1) bytes, stored with a one-byte prefix indicating the length of the value'); + case 'MEDIUMBLOB': + return __('A BLOB column with a maximum length of 16,777,215 (2^24 - 1) bytes, stored with a three-byte prefix indicating the length of the value'); + case 'BLOB': + return __('A BLOB column with a maximum length of 65,535 (2^16 - 1) bytes, stored with a two-byte prefix indicating the length of the value'); + case 'LONGBLOB': + return __('A BLOB column with a maximum length of 4,294,967,295 or 4GiB (2^32 - 1) bytes, stored with a four-byte prefix indicating the length of the value'); + case 'ENUM': + return __("An enumeration, chosen from the list of up to 65,535 values or the special '' error value"); + case 'SET': + return __("A single value chosen from a set of up to 64 members"); + case 'GEOMETRY': + return __('A type that can store a geometry of any type'); + case 'POINT': + return __('A point in 2-dimensional space'); + case 'LINESTRING': + return __('A curve with linear interpolation between points'); + case 'POLYGON': + return __('A polygon'); + case 'MULTIPOINT': + return __('A collection of points'); + case 'MULTILINESTRING': + return __('A collection of curves with linear interpolation between points'); + case 'MULTIPOLYGON': + return __('A collection of polygons'); + case 'GEOMETRYCOLLECTION': + return __('A collection of geometry objects of any type'); + } + return ''; + } + + /** + * Returns class of a type, used for functions available for type + * or default values. + * + * @param string $type The data type to get a class. + * + * @return string + * + */ + public function getTypeClass($type) + { + $type = strtoupper($type); + switch ($type) { + case 'TINYINT': + case 'SMALLINT': + case 'MEDIUMINT': + case 'INT': + case 'BIGINT': + case 'DECIMAL': + case 'FLOAT': + case 'DOUBLE': + case 'REAL': + case 'BIT': + case 'BOOLEAN': + case 'SERIAL': + return 'NUMBER'; + + case 'DATE': + case 'DATETIME': + case 'TIMESTAMP': + case 'TIME': + case 'YEAR': + return 'DATE'; + + case 'CHAR': + case 'VARCHAR': + case 'TINYTEXT': + case 'TEXT': + case 'MEDIUMTEXT': + case 'LONGTEXT': + case 'BINARY': + case 'VARBINARY': + case 'TINYBLOB': + case 'MEDIUMBLOB': + case 'BLOB': + case 'LONGBLOB': + case 'ENUM': + case 'SET': + return 'CHAR'; + + case 'GEOMETRY': + case 'POINT': + case 'LINESTRING': + case 'POLYGON': + case 'MULTIPOINT': + case 'MULTILINESTRING': + case 'MULTIPOLYGON': + case 'GEOMETRYCOLLECTION': + return 'SPATIAL'; + } + + return ''; + } + + /** + * Returns array of functions available for a class. + * + * @param string $class The class to get function list. + * + * @return array + * + */ + public function getFunctionsClass($class) + { + switch ($class) { + case 'CHAR': + return array( + 'AES_ENCRYPT', + 'BIN', + 'CHAR', + 'COMPRESS', + 'CURRENT_USER', + 'DATABASE', + 'DAYNAME', + 'DES_DECRYPT', + 'DES_ENCRYPT', + 'ENCRYPT', + 'HEX', + 'INET_NTOA', + 'LOAD_FILE', + 'LOWER', + 'LTRIM', + 'MD5', + 'MONTHNAME', + 'OLD_PASSWORD', + 'PASSWORD', + 'QUOTE', + 'REVERSE', + 'RTRIM', + 'SHA1', + 'SOUNDEX', + 'SPACE', + 'TRIM', + 'UNCOMPRESS', + 'UNHEX', + 'UPPER', + 'USER', + 'UUID', + 'VERSION', + ); + + case 'DATE': + return array( + 'CURRENT_DATE', + 'CURRENT_TIME', + 'DATE', + 'FROM_DAYS', + 'FROM_UNIXTIME', + 'LAST_DAY', + 'NOW', + 'SEC_TO_TIME', + 'SYSDATE', + 'TIME', + 'TIMESTAMP', + 'UTC_DATE', + 'UTC_TIME', + 'UTC_TIMESTAMP', + 'YEAR', + ); + + case 'NUMBER': + $ret = array( + 'ABS', + 'ACOS', + 'ASCII', + 'ASIN', + 'ATAN', + 'BIT_LENGTH', + 'BIT_COUNT', + 'CEILING', + 'CHAR_LENGTH', + 'CONNECTION_ID', + 'COS', + 'COT', + 'CRC32', + 'DAYOFMONTH', + 'DAYOFWEEK', + 'DAYOFYEAR', + 'DEGREES', + 'EXP', + 'FLOOR', + 'HOUR', + 'INET_ATON', + 'LENGTH', + 'LN', + 'LOG', + 'LOG2', + 'LOG10', + 'MICROSECOND', + 'MINUTE', + 'MONTH', + 'OCT', + 'ORD', + 'PI', + 'QUARTER', + 'RADIANS', + 'RAND', + 'ROUND', + 'SECOND', + 'SIGN', + 'SIN', + 'SQRT', + 'TAN', + 'TO_DAYS', + 'TO_SECONDS', + 'TIME_TO_SEC', + 'UNCOMPRESSED_LENGTH', + 'UNIX_TIMESTAMP', + 'UUID_SHORT', + 'WEEK', + 'WEEKDAY', + 'WEEKOFYEAR', + 'YEARWEEK', + ); + // remove functions that are unavailable on current server + if (PMA_MYSQL_INT_VERSION < 50500) { + $ret = array_diff($ret, array('TO_SECONDS')); + } + if (PMA_MYSQL_INT_VERSION < 50120) { + $ret = array_diff($ret, array('UUID_SHORT')); + } + return $ret; + + case 'SPATIAL': + return array( + 'GeomFromText', + 'GeomFromWKB', + + 'GeomCollFromText', + 'LineFromText', + 'MLineFromText', + 'PointFromText', + 'MPointFromText', + 'PolyFromText', + 'MPolyFromText', + + 'GeomCollFromWKB', + 'LineFromWKB', + 'MLineFromWKB', + 'PointFromWKB', + 'MPointFromWKB', + 'PolyFromWKB', + 'MPolyFromWKB', + ); + } + return array(); + } + + /** + * Returns array of all attributes available. + * + * @return array + * + */ + public function getAttributes() + { + return array( + '', + 'BINARY', + 'UNSIGNED', + 'UNSIGNED ZEROFILL', + 'on update CURRENT_TIMESTAMP', + ); + } + + /** + * Returns array of all column types available. + * + * VARCHAR, TINYINT, TEXT and DATE are listed first, based on + * estimated popularity. + * + * @return array + * + */ + public function getColumns() + { + $ret = parent::getColumns(); + // numeric + $ret[_pgettext('numeric types', 'Numeric')] = array( + 'TINYINT', + 'SMALLINT', + 'MEDIUMINT', + 'INT', + 'BIGINT', + '-', + 'DECIMAL', + 'FLOAT', + 'DOUBLE', + 'REAL', + '-', + 'BIT', + 'BOOLEAN', + 'SERIAL', + ); + + + // Date/Time + $ret[_pgettext('date and time types', 'Date and time')] = array( + 'DATE', + 'DATETIME', + 'TIMESTAMP', + 'TIME', + 'YEAR', + ); + + // Text + $ret[_pgettext('string types', 'String')] = array( + 'CHAR', + 'VARCHAR', + '-', + 'TINYTEXT', + 'TEXT', + 'MEDIUMTEXT', + 'LONGTEXT', + '-', + 'BINARY', + 'VARBINARY', + '-', + 'TINYBLOB', + 'MEDIUMBLOB', + 'BLOB', + 'LONGBLOB', + '-', + 'ENUM', + 'SET', + ); + + $ret[_pgettext('spatial types', 'Spatial')] = array( + 'GEOMETRY', + 'POINT', + 'LINESTRING', + 'POLYGON', + 'MULTIPOINT', + 'MULTILINESTRING', + 'MULTIPOLYGON', + 'GEOMETRYCOLLECTION', + ); + + return $ret; + } +} + +/** + * Class holding type definitions for Drizzle. + * + * @package PhpMyAdmin + */ +class PMA_Types_Drizzle extends PMA_Types +{ + /** + * Returns the data type description. + * + * @param string $type The data type to get a description. + * + * @return string + * + */ + public function getTypeDescription($type) + { + $type = strtoupper($type); + switch ($type) { + case 'INTEGER': + return __('A 4-byte integer, range is -2,147,483,648 to 2,147,483,647'); + case 'BIGINT': + return __('An 8-byte integer, range is -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807'); + case 'DECIMAL': + return __('A fixed-point number (M, D) - the maximum number of digits (M) is 65 (default 10), the maximum number of decimals (D) is 30 (default 0)'); + case 'DOUBLE': + return __("A system's default double-precision floating-point number"); + case 'BOOLEAN': + return __('True or false'); + case 'SERIAL': + return __('An alias for BIGINT NOT NULL AUTO_INCREMENT UNIQUE'); + case 'UUID': + return __('Stores a Universally Unique Identifier (UUID)'); + case 'DATE': + return sprintf(__('A date, supported range is %1$s to %2$s'), '0001-01-01', '9999-12-31'); + case 'DATETIME': + return sprintf(__('A date and time combination, supported range is %1$s to %2$s'), '0001-01-01 00:00:0', '9999-12-31 23:59:59'); + case 'TIMESTAMP': + return __("A timestamp, range is '0001-01-01 00:00:00' UTC to '9999-12-31 23:59:59' UTC; TIMESTAMP(6) can store microseconds"); + case 'TIME': + return sprintf(__('A time, range is %1$s to %2$s'), '00:00:00', '23:59:59'); + case 'VARCHAR': + return sprintf(__('A variable-length (%s) string, the effective maximum length is subject to the maximum row size'), '0-16,383'); + case 'TEXT': + return __('A TEXT column with a maximum length of 65,535 (2^16 - 1) characters, stored with a two-byte prefix indicating the length of the value in bytes'); + case 'VARBINARY': + return __('A variable-length (0-65,535) string, uses binary collation for all comparisons'); + case 'BLOB': + return __('A BLOB column with a maximum length of 65,535 (2^16 - 1) bytes, stored with a two-byte prefix indicating the length of the value'); + case 'ENUM': + return __("An enumeration, chosen from the list of defined values"); + } + return ''; + } + + /** + * Returns class of a type, used for functions available for type + * or default values. + * + * @param string $type The data type to get a class. + * + * @return string + * + */ + public function getTypeClass($type) + { + $type = strtoupper($type); + switch ($type) { + case 'INTEGER': + case 'BIGINT': + case 'DECIMAL': + case 'DOUBLE': + case 'BOOLEAN': + case 'SERIAL': + return 'NUMBER'; + + case 'DATE': + case 'DATETIME': + case 'TIMESTAMP': + case 'TIME': + return 'DATE'; + + case 'VARCHAR': + case 'TEXT': + case 'VARBINARY': + case 'BLOB': + case 'ENUM': + return 'CHAR'; + + case 'UUID': + return 'UUID'; + } + return ''; + } + + /** + * Returns array of functions available for a class. + * + * @param string $class The class to get function list. + * + * @return array + * + */ + public function getFunctionsClass($class) + { + switch ($class) { + case 'CHAR': + $ret = array( + 'BIN', + 'CHAR', + 'COMPRESS', + 'CURRENT_USER', + 'DATABASE', + 'DAYNAME', + 'HEX', + 'LOAD_FILE', + 'LOWER', + 'LTRIM', + 'MD5', + 'MONTHNAME', + 'QUOTE', + 'REVERSE', + 'RTRIM', + 'SCHEMA', + 'SPACE', + 'TRIM', + 'UNCOMPRESS', + 'UNHEX', + 'UPPER', + 'USER', + 'UUID', + 'VERSION', + ); + + // check for some functions known to be in modules + $functions = array( + 'MYSQL_PASSWORD', + 'ROT13', + ); + + // add new functions + $sql = "SELECT upper(plugin_name) f + FROM data_dictionary.plugins + WHERE plugin_name IN ('" . implode("','", $functions) . "') + AND plugin_type = 'Function' + AND is_active"; + $drizzle_functions = $GLOBALS['dbi']->fetchResult($sql, 'f', 'f'); + if (count($drizzle_functions) > 0) { + $ret = array_merge($ret, $drizzle_functions); + sort($ret); + } + + return $ret; + + case 'UUID': + return array( + 'UUID', + ); + + case 'DATE': + return array( + 'CURRENT_DATE', + 'CURRENT_TIME', + 'DATE', + 'FROM_DAYS', + 'FROM_UNIXTIME', + 'LAST_DAY', + 'NOW', + 'SYSDATE', + //'TIME', // https://bugs.launchpad.net/drizzle/+bug/804571 + 'TIMESTAMP', + 'UTC_DATE', + 'UTC_TIME', + 'UTC_TIMESTAMP', + 'YEAR', + ); + + case 'NUMBER': + return array( + 'ABS', + 'ACOS', + 'ASCII', + 'ASIN', + 'ATAN', + 'BIT_COUNT', + 'CEILING', + 'CHAR_LENGTH', + 'CONNECTION_ID', + 'COS', + 'COT', + 'CRC32', + 'DAYOFMONTH', + 'DAYOFWEEK', + 'DAYOFYEAR', + 'DEGREES', + 'EXP', + 'FLOOR', + 'HOUR', + 'LENGTH', + 'LN', + 'LOG', + 'LOG2', + 'LOG10', + 'MICROSECOND', + 'MINUTE', + 'MONTH', + 'OCT', + 'ORD', + 'PI', + 'QUARTER', + 'RADIANS', + 'RAND', + 'ROUND', + 'SECOND', + 'SIGN', + 'SIN', + 'SQRT', + 'TAN', + 'TO_DAYS', + 'TIME_TO_SEC', + 'UNCOMPRESSED_LENGTH', + 'UNIX_TIMESTAMP', + //'WEEK', // same as TIME + 'WEEKDAY', + 'WEEKOFYEAR', + 'YEARWEEK', + ); + } + return array(); + } + + /** + * Returns array of all attributes available. + * + * @return array + * + */ + public function getAttributes() + { + return array( + '', + 'on update CURRENT_TIMESTAMP', + ); + } + + /** + * Returns array of all column types available. + * + * @return array + * + */ + public function getColumns() + { + $types_num = array( + 'INTEGER', + 'BIGINT', + '-', + 'DECIMAL', + 'DOUBLE', + '-', + 'BOOLEAN', + 'SERIAL', + 'UUID', + ); + $types_date = array( + 'DATE', + 'DATETIME', + 'TIMESTAMP', + 'TIME', + ); + $types_string = array( + 'VARCHAR', + 'TEXT', + '-', + 'VARBINARY', + 'BLOB', + '-', + 'ENUM', + ); + if (PMA_MYSQL_INT_VERSION >= 20120130) { + $types_string[] = '-'; + $types_string[] = 'IPV6'; + } + + $ret = parent::getColumns(); + // numeric + $ret[_pgettext('numeric types', 'Numeric')] = $types_num; + + // Date/Time + $ret[_pgettext('date and time types', 'Date and time')] = $types_date; + + // Text + $ret[_pgettext('string types', 'String')] = $types_string; + + return $ret; + } +} diff --git a/phpMyAdmin/libraries/Util.class.php b/phpMyAdmin/libraries/Util.class.php new file mode 100644 index 0000000..8a8fddc --- /dev/null +++ b/phpMyAdmin/libraries/Util.class.php @@ -0,0 +1,4366 @@ +'; + if ($include_icon) { + $button .= self::getImage($icon, $alternate); + } + if ($include_icon && $include_text) { + $button .= ' '; + } + if ($include_text) { + $button .= $alternate; + } + $button .= $menu_icon ? '' : ''; + + return $button; + } + + /** + * Returns an HTML IMG tag for a particular image from a theme, + * which may be an actual file or an icon from a sprite + * + * @param string $image The name of the file to get + * @param string $alternate Used to set 'alt' and 'title' attributes + * of the image + * @param array $attributes An associative array of other attributes + * + * @return string an html IMG tag + */ + public static function getImage($image, $alternate = '', $attributes = array()) + { + static $sprites; // cached list of available sprites (if any) + if (defined('TESTSUITE')) { + // prevent caching in testsuite + unset($sprites); + } + + $url = ''; + $is_sprite = false; + $alternate = htmlspecialchars($alternate); + + // If it's the first time this function is called + if (! isset($sprites)) { + // Try to load the list of sprites + $sprite_file = $_SESSION['PMA_Theme']->getPath() . '/sprites.lib.php'; + if (is_readable($sprite_file)) { + include_once $sprite_file; + $sprites = PMA_sprites(); + } else { + // No sprites are available for this theme + $sprites = array(); + } + } + + // Check if we have the requested image as a sprite + // and set $url accordingly + $class = str_replace(array('.gif','.png'), '', $image); + if (array_key_exists($class, $sprites)) { + $is_sprite = true; + $url = (defined('PMA_TEST_THEME') ? '../' : '') . 'themes/dot.gif'; + } else { + $url = $GLOBALS['pmaThemeImage'] . $image; + } + + // set class attribute + if ($is_sprite) { + if (isset($attributes['class'])) { + $attributes['class'] = "icon ic_$class " . $attributes['class']; + } else { + $attributes['class'] = "icon ic_$class"; + } + } + + // set all other attributes + $attr_str = ''; + foreach ($attributes as $key => $value) { + if (! in_array($key, array('alt', 'title'))) { + $attr_str .= " $key=\"$value\""; + } + } + + // override the alt attribute + if (isset($attributes['alt'])) { + $alt = $attributes['alt']; + } else { + $alt = $alternate; + } + + // override the title attribute + if (isset($attributes['title'])) { + $title = $attributes['title']; + } else { + $title = $alternate; + } + + // generate the IMG tag + $template = '%s'; + $retval = sprintf($template, $url, $title, $alt, $attr_str); + + return $retval; + } + + /** + * Returns the formatted maximum size for an upload + * + * @param integer $max_upload_size the size + * + * @return string the message + * + * @access public + */ + public static function getFormattedMaximumUploadSize($max_upload_size) + { + // I have to reduce the second parameter (sensitiveness) from 6 to 4 + // to avoid weird results like 512 kKib + list($max_size, $max_unit) = self::formatByteDown($max_upload_size, 4); + return '(' . sprintf(__('Max: %s%s'), $max_size, $max_unit) . ')'; + } + + /** + * Generates a hidden field which should indicate to the browser + * the maximum size for upload + * + * @param integer $max_size the size + * + * @return string the INPUT field + * + * @access public + */ + public static function generateHiddenMaxFileSize($max_size) + { + return ''; + } + + /** + * Add slashes before "'" and "\" characters so a value containing them can + * be used in a sql comparison. + * + * @param string $a_string the string to slash + * @param bool $is_like whether the string will be used in a 'LIKE' clause + * (it then requires two more escaped sequences) or not + * @param bool $crlf whether to treat cr/lfs as escape-worthy entities + * (converts \n to \\n, \r to \\r) + * @param bool $php_code whether this function is used as part of the + * "Create PHP code" dialog + * + * @return string the slashed string + * + * @access public + */ + public static function sqlAddSlashes( + $a_string = '', $is_like = false, $crlf = false, $php_code = false + ) { + if ($is_like) { + $a_string = str_replace('\\', '\\\\\\\\', $a_string); + } else { + $a_string = str_replace('\\', '\\\\', $a_string); + } + + if ($crlf) { + $a_string = strtr( + $a_string, + array("\n" => '\n', "\r" => '\r', "\t" => '\t') + ); + } + + if ($php_code) { + $a_string = str_replace('\'', '\\\'', $a_string); + } else { + $a_string = str_replace('\'', '\'\'', $a_string); + } + + return $a_string; + } // end of the 'sqlAddSlashes()' function + + /** + * Add slashes before "_" and "%" characters for using them in MySQL + * database, table and field names. + * Note: This function does not escape backslashes! + * + * @param string $name the string to escape + * + * @return string the escaped string + * + * @access public + */ + public static function escapeMysqlWildcards($name) + { + return strtr($name, array('_' => '\\_', '%' => '\\%')); + } // end of the 'escapeMysqlWildcards()' function + + /** + * removes slashes before "_" and "%" characters + * Note: This function does not unescape backslashes! + * + * @param string $name the string to escape + * + * @return string the escaped string + * + * @access public + */ + public static function unescapeMysqlWildcards($name) + { + return strtr($name, array('\\_' => '_', '\\%' => '%')); + } // end of the 'unescapeMysqlWildcards()' function + + /** + * removes quotes (',",`) from a quoted string + * + * checks if the string is quoted and removes this quotes + * + * @param string $quoted_string string to remove quotes from + * @param string $quote type of quote to remove + * + * @return string unqoted string + */ + public static function unQuote($quoted_string, $quote = null) + { + $quotes = array(); + + if ($quote === null) { + $quotes[] = '`'; + $quotes[] = '"'; + $quotes[] = "'"; + } else { + $quotes[] = $quote; + } + + foreach ($quotes as $quote) { + if (substr($quoted_string, 0, 1) === $quote + && substr($quoted_string, -1, 1) === $quote + ) { + $unquoted_string = substr($quoted_string, 1, -1); + // replace escaped quotes + $unquoted_string = str_replace( + $quote . $quote, + $quote, + $unquoted_string + ); + return $unquoted_string; + } + } + + return $quoted_string; + } + + /** + * format sql strings + * + * @param string $sql_query raw SQL string + * @param boolean $truncate truncate the query if it is too long + * + * @return string the formatted sql + * + * @global array $cfg the configuration array + * + * @access public + * @todo move into PMA_Sql + */ + public static function formatSql($sql_query, $truncate = false) + { + global $cfg; + if ($truncate + && strlen($sql_query) > $cfg['MaxCharactersInDisplayedSQL'] + ) { + $sql_query = $GLOBALS['PMA_String']->substr( + $sql_query, + 0, + $cfg['MaxCharactersInDisplayedSQL'] + ) . '[...]'; + } + return '
    ' . "\n"
    +            . htmlspecialchars($sql_query) . "\n"
    +            . '
    '; + } // end of the "formatSql()" function + + /** + * Displays a link to the documentation as an icon + * + * @param string $link documentation link + * @param string $target optional link target + * + * @return string the html link + * + * @access public + */ + public static function showDocLink($link, $target = 'documentation') + { + return '' + . self::getImage('b_help.png', __('Documentation')) + . ''; + } // end of the 'showDocLink()' function + + /** + * Get a URL link to the official MySQL documentation + * + * @param string $link contains name of page/anchor that is being linked + * @param string $anchor anchor to page part + * + * @return string the URL link + * + * @access public + */ + public static function getMySQLDocuURL($link, $anchor = '') + { + global $cfg; + + // Fixup for newly used names: + $link = str_replace('_', '-', strtolower($link)); + + if (empty($link)) { + $link = 'index'; + } + $mysql = '5.5'; + $lang = 'en'; + if (defined('PMA_MYSQL_INT_VERSION')) { + if (PMA_MYSQL_INT_VERSION >= 50600) { + $mysql = '5.6'; + } else if (PMA_MYSQL_INT_VERSION >= 50500) { + $mysql = '5.5'; + } else if (PMA_MYSQL_INT_VERSION >= 50100) { + $mysql = '5.1'; + } else { + $mysql = '5.0'; + } + } + $url = 'http://dev.mysql.com/doc/refman/' + . $mysql . '/' . $lang . '/' . $link . '.html'; + if (! empty($anchor)) { + $url .= '#' . $anchor; + } + + return PMA_linkURL($url); + } + + /** + * Displays a link to the official MySQL documentation + * + * @param string $link contains name of page/anchor that is being linked + * @param bool $big_icon whether to use big icon (like in left frame) + * @param string $anchor anchor to page part + * @param bool $just_open whether only the opening tag should be returned + * + * @return string the html link + * + * @access public + */ + public static function showMySQLDocu( + $link, $big_icon = false, $anchor = '', $just_open = false + ) { + $url = self::getMySQLDocuURL($link, $anchor); + $open_link = ''; + if ($just_open) { + return $open_link; + } elseif ($big_icon) { + return $open_link + . self::getImage('b_sqlhelp.png', __('Documentation')) . ''; + } else { + return self::showDocLink($url, 'mysql_doc'); + } + } // end of the 'showMySQLDocu()' function + + /** + * Returns link to documentation. + * + * @param string $page Page in documentation + * @param string $anchor Optional anchor in page + * + * @return string URL + */ + public static function getDocuLink($page, $anchor = '') + { + /* Construct base URL */ + $url = $page . '.html'; + if (!empty($anchor)) { + $url .= '#' . $anchor; + } + + /* Check if we have built local documentation */ + if (defined('TESTSUITE')) { + /* Provide consistent URL for testsuite */ + return PMA_linkURL('http://docs.phpmyadmin.net/en/latest/' . $url); + } else if (file_exists('doc/html/index.html')) { + if (defined('PMA_SETUP')) { + return '../doc/html/' . $url; + } else { + return './doc/html/' . $url; + } + } else { + /* TODO: Should link to correct branch for released versions */ + return PMA_linkURL('http://docs.phpmyadmin.net/en/latest/' . $url); + } + } + + /** + * Displays a link to the phpMyAdmin documentation + * + * @param string $page Page in documentation + * @param string $anchor Optional anchor in page + * + * @return string the html link + * + * @access public + */ + public static function showDocu($page, $anchor = '') + { + return self::showDocLink(self::getDocuLink($page, $anchor)); + } // end of the 'showDocu()' function + + /** + * Displays a link to the PHP documentation + * + * @param string $target anchor in documentation + * + * @return string the html link + * + * @access public + */ + public static function showPHPDocu($target) + { + $url = PMA_getPHPDocLink($target); + + return self::showDocLink($url); + } // end of the 'showPHPDocu()' function + + /** + * Returns HTML code for a tooltip + * + * @param string $message the message for the tooltip + * + * @return string + * + * @access public + */ + public static function showHint($message) + { + if ($GLOBALS['cfg']['ShowHint']) { + $classClause = ' class="pma_hint"'; + } else { + $classClause = ''; + } + return '' + . self::getImage('b_help.png') + . '' . $message . '' + . ''; + } + + /** + * Displays a MySQL error message in the main panel when $exit is true. + * Returns the error message otherwise. + * + * @param string $error_message the error message + * @param string $the_query the sql query that failed + * @param bool $is_modify_link whether to show a "modify" link or not + * @param string $back_url the "back" link url (full path is not required) + * @param bool $exit EXIT the page? + * + * @return mixed + * + * @global string $table the curent table + * @global string $db the current db + * + * @access public + */ + public static function mysqlDie( + $error_message = '', $the_query = '', + $is_modify_link = true, $back_url = '', $exit = true + ) { + global $table, $db; + + $error_msg = ''; + + if (! $error_message) { + $error_message = $GLOBALS['dbi']->getError(); + } + if (! $the_query && ! empty($GLOBALS['sql_query'])) { + $the_query = $GLOBALS['sql_query']; + } + + // --- Added to solve bug #641765 + if (! function_exists('PMA_SQP_isError') || PMA_SQP_isError()) { + $formatted_sql = htmlspecialchars($the_query); + } elseif (empty($the_query) || (trim($the_query) == '')) { + $formatted_sql = ''; + } else { + $formatted_sql = self::formatSql($the_query, true); + } + // --- + $error_msg .= "\n" . '' . "\n"; + $error_msg .= '

    ' . __('Error') + . '

    ' . "\n"; + // if the config password is wrong, or the MySQL server does not + // respond, do not show the query that would reveal the + // username/password + if (! empty($the_query) && ! strstr($the_query, 'connect')) { + // --- Added to solve bug #641765 + if (function_exists('PMA_SQP_isError') && PMA_SQP_isError()) { + $error_msg .= PMA_SQP_getErrorString() . "\n"; + $error_msg .= '
    ' . "\n"; + } + // --- + // modified to show the help on sql errors + $error_msg .= '

    ' . __('SQL query:') . '' . "\n"; + if (strstr(strtolower($formatted_sql), 'select')) { + // please show me help to the error on select + $error_msg .= self::showMySQLDocu('SELECT'); + } + if ($is_modify_link) { + $_url_params = array( + 'sql_query' => $the_query, + 'show_query' => 1, + ); + if (strlen($table)) { + $_url_params['db'] = $db; + $_url_params['table'] = $table; + $doedit_goto = ''; + } elseif (strlen($db)) { + $_url_params['db'] = $db; + $doedit_goto = ''; + } else { + $doedit_goto = ''; + } + + $error_msg .= $doedit_goto + . self::getIcon('b_edit.png', __('Edit')) + . ''; + } // end if + $error_msg .= '

    ' . "\n" + .'

    ' . "\n" + . $formatted_sql . "\n" + . '

    ' . "\n"; + } // end if + + if (! empty($error_message)) { + $error_message = preg_replace( + "@((\015\012)|(\015)|(\012)){3,}@", + "\n\n", + $error_message + ); + } + // modified to show the help on error-returns + // (now error-messages-server) + $error_msg .= '

    ' . "\n" + . ' ' . __('MySQL said: ') . '' + . self::showMySQLDocu('Error-messages-server') + . "\n" + . '

    ' . "\n"; + + // The error message will be displayed within a CODE segment. + // To preserve original formatting, but allow wordwrapping, + // we do a couple of replacements + + // Replace all non-single blanks with their HTML-counterpart + $error_message = str_replace(' ', '  ', $error_message); + // Replace TAB-characters with their HTML-counterpart + $error_message = str_replace( + "\t", '    ', $error_message + ); + // Replace linebreaks + $error_message = nl2br($error_message); + + $error_msg .= '' . "\n" + . $error_message . "\n" + . '
    ' . "\n"; + $error_msg .= '
    '; + + $_SESSION['Import_message']['message'] = $error_msg; + + if ($exit) { + /** + * If in an Ajax request + * - avoid displaying a Back link + * - use PMA_Response() to transmit the message and exit + */ + if (isset($GLOBALS['is_ajax_request']) + && $GLOBALS['is_ajax_request'] == true + ) { + $response = PMA_Response::getInstance(); + $response->isSuccess(false); + $response->addJSON('message', $error_msg); + exit; + } + if (! empty($back_url)) { + if (strstr($back_url, '?')) { + $back_url .= '&no_history=true'; + } else { + $back_url .= '?no_history=true'; + } + + $_SESSION['Import_message']['go_back_url'] = $back_url; + + $error_msg .= '
    ' + . '[ ' . __('Back') . ' ]' + . '
    ' . "\n\n"; + } + echo $error_msg; + exit; + } else { + return $error_msg; + } + } // end of the 'mysqlDie()' function + + /** + * returns array with tables of given db with extended information and grouped + * + * @param string $db name of db + * @param string $tables name of tables + * @param integer $limit_offset list offset + * @param int|bool $limit_count max tables to return + * + * @return array (recursive) grouped table list + */ + public static function getTableList( + $db, $tables = null, $limit_offset = 0, $limit_count = false + ) { + $sep = $GLOBALS['cfg']['NavigationTreeTableSeparator']; + + if ($tables === null) { + $tables = $GLOBALS['dbi']->getTablesFull( + $db, false, false, null, $limit_offset, $limit_count + ); + if ($GLOBALS['cfg']['NaturalOrder']) { + uksort($tables, 'strnatcasecmp'); + } + } + + if (count($tables) < 1) { + return $tables; + } + + $default = array( + 'Name' => '', + 'Rows' => 0, + 'Comment' => '', + 'disp_name' => '', + ); + + $table_groups = array(); + + foreach ($tables as $table_name => $table) { + // check for correct row count + if ($table['Rows'] === null) { + // Do not check exact row count here, + // if row count is invalid possibly the table is defect + // and this would break left frame; + // but we can check row count if this is a view or the + // information_schema database + // since PMA_Table::countRecords() returns a limited row count + // in this case. + + // set this because PMA_Table::countRecords() can use it + $tbl_is_view = $table['TABLE_TYPE'] == 'VIEW'; + + if ($tbl_is_view || $GLOBALS['dbi']->isSystemSchema($db)) { + $table['Rows'] = PMA_Table::countRecords( + $db, + $table['Name'], + false, + true + ); + } + } + + // in $group we save the reference to the place in $table_groups + // where to store the table info + if ($GLOBALS['cfg']['NavigationTreeEnableGrouping'] + && $sep && strstr($table_name, $sep) + ) { + $parts = explode($sep, $table_name); + + $group =& $table_groups; + $i = 0; + $group_name_full = ''; + $parts_cnt = count($parts) - 1; + + while (($i < $parts_cnt) + && ($i < $GLOBALS['cfg']['NavigationTreeTableLevel']) + ) { + $group_name = $parts[$i] . $sep; + $group_name_full .= $group_name; + + if (! isset($group[$group_name])) { + $group[$group_name] = array(); + $group[$group_name]['is' . $sep . 'group'] = true; + $group[$group_name]['tab' . $sep . 'count'] = 1; + $group[$group_name]['tab' . $sep . 'group'] + = $group_name_full; + + } elseif (! isset($group[$group_name]['is' . $sep . 'group'])) { + $table = $group[$group_name]; + $group[$group_name] = array(); + $group[$group_name][$group_name] = $table; + unset($table); + $group[$group_name]['is' . $sep . 'group'] = true; + $group[$group_name]['tab' . $sep . 'count'] = 1; + $group[$group_name]['tab' . $sep . 'group'] + = $group_name_full; + + } else { + $group[$group_name]['tab' . $sep . 'count']++; + } + + $group =& $group[$group_name]; + $i++; + } + + } else { + if (! isset($table_groups[$table_name])) { + $table_groups[$table_name] = array(); + } + $group =& $table_groups; + } + + $table['disp_name'] = $table['Name']; + $group[$table_name] = array_merge($default, $table); + } + + return $table_groups; + } + + /* ----------------------- Set of misc functions ----------------------- */ + + /** + * Adds backquotes on both sides of a database, table or field name. + * and escapes backquotes inside the name with another backquote + * + * example: + * + * echo backquote('owner`s db'); // `owner``s db` + * + * + * + * @param mixed $a_name the database, table or field name to "backquote" + * or array of it + * @param boolean $do_it a flag to bypass this function (used by dump + * functions) + * + * @return mixed the "backquoted" database, table or field name + * + * @access public + */ + public static function backquote($a_name, $do_it = true) + { + if (is_array($a_name)) { + foreach ($a_name as &$data) { + $data = self::backquote($data, $do_it); + } + return $a_name; + } + + if (! $do_it) { + global $PMA_SQPdata_forbidden_word; + if (! in_array(strtoupper($a_name), $PMA_SQPdata_forbidden_word)) { + return $a_name; + } + } + + // '0' is also empty for php :-( + if (strlen($a_name) && $a_name !== '*') { + return '`' . str_replace('`', '``', $a_name) . '`'; + } else { + return $a_name; + } + } // end of the 'backquote()' function + + /** + * Adds quotes on both sides of a database, table or field name. + * in compatibility mode + * + * example: + * + * echo backquote('owner`s db'); // `owner``s db` + * + * + * + * @param mixed $a_name the database, table or field name to + * "backquote" or array of it + * @param string $compatibility string compatibility mode (used by dump + * functions) + * @param boolean $do_it a flag to bypass this function (used by dump + * functions) + * + * @return mixed the "backquoted" database, table or field name + * + * @access public + */ + public static function backquoteCompat( + $a_name, $compatibility = 'MSSQL', $do_it = true + ) { + if (is_array($a_name)) { + foreach ($a_name as &$data) { + $data = self::backquoteCompat($data, $compatibility, $do_it); + } + return $a_name; + } + + if (! $do_it) { + global $PMA_SQPdata_forbidden_word; + if (! in_array(strtoupper($a_name), $PMA_SQPdata_forbidden_word)) { + return $a_name; + } + } + + // @todo add more compatibility cases (ORACLE for example) + switch ($compatibility) { + case 'MSSQL': + $quote = '"'; + break; + default: + (isset($GLOBALS['sql_backquotes'])) ? $quote = "`" : $quote = ''; + break; + } + + // '0' is also empty for php :-( + if (strlen($a_name) && $a_name !== '*') { + return $quote . $a_name . $quote; + } else { + return $a_name; + } + } // end of the 'backquoteCompat()' function + + /** + * Defines the value depending on the user OS. + * + * @return string the value to use + * + * @access public + */ + public static function whichCrlf() + { + // The 'PMA_USR_OS' constant is defined in "libraries/Config.class.php" + // Win case + if (PMA_USR_OS == 'Win') { + $the_crlf = "\r\n"; + } else { + // Others + $the_crlf = "\n"; + } + + return $the_crlf; + } // end of the 'whichCrlf()' function + + /** + * Prepare the message and the query + * usually the message is the result of the query executed + * + * @param string $message the message to display + * @param string $sql_query the query to display + * @param string $type the type (level) of the message + * @param boolean $is_view is this a message after a VIEW operation? + * + * @return string + * + * @access public + */ + public static function getMessage( + $message, $sql_query = null, $type = 'notice', $is_view = false + ) { + global $cfg; + $retval = ''; + + if (null === $sql_query) { + if (! empty($GLOBALS['display_query'])) { + $sql_query = $GLOBALS['display_query']; + } elseif (! empty($GLOBALS['unparsed_sql'])) { + $sql_query = $GLOBALS['unparsed_sql']; + } elseif (! empty($GLOBALS['sql_query'])) { + $sql_query = $GLOBALS['sql_query']; + } else { + $sql_query = ''; + } + } + + if (isset($GLOBALS['using_bookmark_message'])) { + $retval .= $GLOBALS['using_bookmark_message']->getDisplay(); + unset($GLOBALS['using_bookmark_message']); + } + + // In an Ajax request, $GLOBALS['cell_align_left'] may not be defined. Hence, + // check for it's presence before using it + $retval .= '
    ' . "\n"; + + if ($message instanceof PMA_Message) { + if (isset($GLOBALS['special_message'])) { + $message->addMessage($GLOBALS['special_message']); + unset($GLOBALS['special_message']); + } + $retval .= $message->getDisplay(); + } else { + $retval .= '
    '; + $retval .= PMA_sanitize($message); + if (isset($GLOBALS['special_message'])) { + $retval .= PMA_sanitize($GLOBALS['special_message']); + unset($GLOBALS['special_message']); + } + $retval .= '
    '; + } + + if ($cfg['ShowSQL'] == true && ! empty($sql_query)) { + // Html format the query to be displayed + // If we want to show some sql code it is easiest to create it here + /* SQL-Parser-Analyzer */ + + if (! empty($GLOBALS['show_as_php'])) { + $new_line = '\\n"
    ' . "\n" + . '    . "'; + $query_base = htmlspecialchars(addslashes($sql_query)); + $query_base = preg_replace( + '/((\015\012)|(\015)|(\012))/', $new_line, $query_base + ); + } else { + $query_base = $sql_query; + } + + $query_too_big = false; + + if (strlen($query_base) > $cfg['MaxCharactersInDisplayedSQL']) { + // when the query is large (for example an INSERT of binary + // data), the parser chokes; so avoid parsing the query + $query_too_big = true; + $shortened_query_base = nl2br( + htmlspecialchars( + substr($sql_query, 0, $cfg['MaxCharactersInDisplayedSQL']) + . '[...]' + ) + ); + } elseif (! empty($GLOBALS['parsed_sql']) + && $query_base == $GLOBALS['parsed_sql']['raw'] + ) { + // (here, use "! empty" because when deleting a bookmark, + // $GLOBALS['parsed_sql'] is set but empty + $parsed_sql = $GLOBALS['parsed_sql']; + } else { + // Parse SQL if needed + $parsed_sql = PMA_SQP_parse($query_base); + } + + // Analyze it + if (isset($parsed_sql) && ! PMA_SQP_isError()) { + $analyzed_display_query = PMA_SQP_analyze($parsed_sql); + + // Same as below (append LIMIT), append the remembered ORDER BY + if ($GLOBALS['cfg']['RememberSorting'] + && isset($analyzed_display_query[0]['queryflags']['select_from']) + && isset($GLOBALS['sql_order_to_append']) + ) { + $query_base = $analyzed_display_query[0]['section_before_limit'] + . "\n" . $GLOBALS['sql_order_to_append'] + . $analyzed_display_query[0]['limit_clause'] . ' ' + . $analyzed_display_query[0]['section_after_limit']; + + // Need to reparse query + $parsed_sql = PMA_SQP_parse($query_base); + // update the $analyzed_display_query + $analyzed_display_query[0]['section_before_limit'] + .= $GLOBALS['sql_order_to_append']; + $analyzed_display_query[0]['order_by_clause'] + = $GLOBALS['sorted_col']; + } + + // Here we append the LIMIT added for navigation, to + // enable its display. Adding it higher in the code + // to $sql_query would create a problem when + // using the Refresh or Edit links. + + // Only append it on SELECTs. + + /** + * @todo what would be the best to do when someone hits Refresh: + * use the current LIMITs ? + */ + + if (isset($analyzed_display_query[0]['queryflags']['select_from']) + && ! empty($GLOBALS['sql_limit_to_append']) + ) { + $query_base = $analyzed_display_query[0]['section_before_limit'] + . "\n" . $GLOBALS['sql_limit_to_append'] + . $analyzed_display_query[0]['section_after_limit']; + // Need to reparse query + $parsed_sql = PMA_SQP_parse($query_base); + } + } + + if (! empty($GLOBALS['show_as_php'])) { + $query_base = '$sql = "' . $query_base; + } elseif (! empty($GLOBALS['validatequery'])) { + try { + $query_base = PMA_validateSQL($query_base); + } catch (Exception $e) { + $retval .= PMA_Message::error( + __('Failed to connect to SQL validator!') + )->getDisplay(); + } + } elseif (isset($query_base)) { + $query_base = self::formatSql($query_base); + } + + // Prepares links that may be displayed to edit/explain the query + // (don't go to default pages, we must go to the page + // where the query box is available) + + // Basic url query part + $url_params = array(); + if (! isset($GLOBALS['db'])) { + $GLOBALS['db'] = ''; + } + if (strlen($GLOBALS['db'])) { + $url_params['db'] = $GLOBALS['db']; + if (strlen($GLOBALS['table'])) { + $url_params['table'] = $GLOBALS['table']; + $edit_link = 'tbl_sql.php'; + } else { + $edit_link = 'db_sql.php'; + } + } else { + $edit_link = 'server_sql.php'; + } + + // Want to have the query explained + // but only explain a SELECT (that has not been explained) + /* SQL-Parser-Analyzer */ + $explain_link = ''; + $is_select = preg_match('@^SELECT[[:space:]]+@i', $sql_query); + if (! empty($cfg['SQLQuery']['Explain']) && ! $query_too_big) { + $explain_params = $url_params; + // Detect if we are validating as well + // To preserve the validate uRL data + if (! empty($GLOBALS['validatequery'])) { + $explain_params['validatequery'] = 1; + } + if ($is_select) { + $explain_params['sql_query'] = 'EXPLAIN ' . $sql_query; + $_message = __('Explain SQL'); + } elseif ( + preg_match( + '@^EXPLAIN[[:space:]]+SELECT[[:space:]]+@i', $sql_query + ) + ) { + $explain_params['sql_query'] = substr($sql_query, 8); + $_message = __('Skip Explain SQL'); + } + if (isset($explain_params['sql_query'])) { + $explain_link = 'import.php' + . PMA_URL_getCommon($explain_params); + $explain_link = ' [' + . self::linkOrButton($explain_link, $_message) . ']'; + } + } //show explain + + $url_params['sql_query'] = $sql_query; + $url_params['show_query'] = 1; + + // even if the query is big and was truncated, offer the chance + // to edit it (unless it's enormous, see linkOrButton() ) + if (! empty($cfg['SQLQuery']['Edit'])) { + if ($cfg['EditInWindow'] == true) { + $onclick = 'PMA_querywindow.focus(\'' + . PMA_jsFormat($sql_query, false) . '\'); return false;'; + } else { + $onclick = ''; + } + + $edit_link .= PMA_URL_getCommon($url_params) . '#querybox'; + $edit_link = ' [' + . self::linkOrButton( + $edit_link, __('Edit'), + array('onclick' => $onclick, 'class' => 'disableAjax') + ) + . ']'; + } else { + $edit_link = ''; + } + + // Also we would like to get the SQL formed in some nice + // php-code + if (! empty($cfg['SQLQuery']['ShowAsPHP']) && ! $query_too_big) { + $php_params = $url_params; + + if (! empty($GLOBALS['show_as_php'])) { + $_message = __('Without PHP Code'); + } else { + $php_params['show_as_php'] = 1; + $_message = __('Create PHP Code'); + } + + $php_link = 'import.php' . PMA_URL_getCommon($php_params); + $php_link = ' [' . self::linkOrButton($php_link, $_message) . ']'; + + if (isset($GLOBALS['show_as_php'])) { + + $runquery_link = 'import.php' + . PMA_URL_getCommon($url_params); + + $php_link .= ' [' + . self::linkOrButton($runquery_link, __('Submit Query')) + . ']'; + } + } else { + $php_link = ''; + } //show as php + + // Refresh query + if (! empty($cfg['SQLQuery']['Refresh']) + && ! isset($GLOBALS['show_as_php']) // 'Submit query' does the same + && preg_match('@^(SELECT|SHOW)[[:space:]]+@i', $sql_query) + ) { + $refresh_link = 'import.php' . PMA_URL_getCommon($url_params); + $refresh_link = ' [' + . self::linkOrButton($refresh_link, __('Refresh')) . ']'; + } else { + $refresh_link = ''; + } //refresh + + if (! empty($cfg['SQLValidator']['use']) + && ! empty($cfg['SQLQuery']['Validate']) + ) { + $validate_params = $url_params; + if (! empty($GLOBALS['validatequery'])) { + $validate_message = __('Skip Validate SQL'); + } else { + $validate_params['validatequery'] = 1; + $validate_message = __('Validate SQL'); + } + + $validate_link = 'import.php' + . PMA_URL_getCommon($validate_params); + $validate_link = ' [' + . self::linkOrButton($validate_link, $validate_message) . ']'; + } else { + $validate_link = ''; + } //validator + + if (! empty($GLOBALS['validatequery'])) { + $retval .= '
    '; + } else { + $retval .= '
    '; + } + if ($query_too_big) { + $retval .= $shortened_query_base; + } else { + $retval .= $query_base; + } + + //Clean up the end of the PHP + if (! empty($GLOBALS['show_as_php'])) { + $retval .= '";'; + } + $retval .= '
    '; + + $retval .= '
    '; + $retval .= '
    '; + $retval .= PMA_URL_getHiddenInputs( + $GLOBALS['db'], $GLOBALS['table'] + ); + $retval .= ''; + + // avoid displaying a Profiling checkbox that could + // be checked, which would reexecute an INSERT, for example + if (! empty($refresh_link) && self::profilingSupported()) { + $retval .= ''; + $retval .= self::getCheckbox( + 'profiling', __('Profiling'), isset($_SESSION['profiling']), true + ); + } + $retval .= '
    '; + + /** + * TODO: Should we have $cfg['SQLQuery']['InlineEdit']? + */ + if (! empty($cfg['SQLQuery']['Edit']) && ! $query_too_big) { + $inline_edit_link = ' [' + . self::linkOrButton( + '#', + _pgettext('Inline edit query', 'Inline'), + array('class' => 'inline_edit_sql') + ) + . ']'; + } else { + $inline_edit_link = ''; + } + $retval .= $inline_edit_link . $edit_link . $explain_link . $php_link + . $refresh_link . $validate_link; + $retval .= '
    '; + } + + $retval .= '
    '; + if ($GLOBALS['is_ajax_request'] === false) { + $retval .= '
    '; + } + + return $retval; + } // end of the 'getMessage()' function + + /** + * Verifies if current MySQL server supports profiling + * + * @access public + * + * @return boolean whether profiling is supported + */ + public static function profilingSupported() + { + if (!self::cacheExists('profiling_supported', true)) { + // 5.0.37 has profiling but for example, 5.1.20 does not + // (avoid a trip to the server for MySQL before 5.0.37) + // and do not set a constant as we might be switching servers + if (defined('PMA_MYSQL_INT_VERSION') + && (PMA_MYSQL_INT_VERSION >= 50037) + && $GLOBALS['dbi']->fetchValue("SHOW VARIABLES LIKE 'profiling'") + ) { + self::cacheSet('profiling_supported', true, true); + } else { + self::cacheSet('profiling_supported', false, true); + } + } + + return self::cacheGet('profiling_supported', true); + } + + /** + * Formats $value to byte view + * + * @param double $value the value to format + * @param int $limes the sensitiveness + * @param int $comma the number of decimals to retain + * + * @return array the formatted value and its unit + * + * @access public + */ + public static function formatByteDown($value, $limes = 6, $comma = 0) + { + if ($value === null) { + return null; + } + + $byteUnits = array( + /* l10n: shortcuts for Byte */ + __('B'), + /* l10n: shortcuts for Kilobyte */ + __('KiB'), + /* l10n: shortcuts for Megabyte */ + __('MiB'), + /* l10n: shortcuts for Gigabyte */ + __('GiB'), + /* l10n: shortcuts for Terabyte */ + __('TiB'), + /* l10n: shortcuts for Petabyte */ + __('PiB'), + /* l10n: shortcuts for Exabyte */ + __('EiB') + ); + + $dh = self::pow(10, $comma); + $li = self::pow(10, $limes); + $unit = $byteUnits[0]; + + for ($d = 6, $ex = 15; $d >= 1; $d--, $ex-=3) { + if (isset($byteUnits[$d]) && ($value >= $li * self::pow(10, $ex))) { + // use 1024.0 to avoid integer overflow on 64-bit machines + $value = round($value / (self::pow(1024, $d) / $dh)) /$dh; + $unit = $byteUnits[$d]; + break 1; + } // end if + } // end for + + if ($unit != $byteUnits[0]) { + // if the unit is not bytes (as represented in current language) + // reformat with max length of 5 + // 4th parameter=true means do not reformat if value < 1 + $return_value = self::formatNumber($value, 5, $comma, true); + } else { + // do not reformat, just handle the locale + $return_value = self::formatNumber($value, 0); + } + + return array(trim($return_value), $unit); + } // end of the 'formatByteDown' function + + /** + * Changes thousands and decimal separators to locale specific values. + * + * @param string $value the value + * + * @return string + */ + public static function localizeNumber($value) + { + return str_replace( + array(',', '.'), + array( + /* l10n: Thousands separator */ + __(','), + /* l10n: Decimal separator */ + __('.'), + ), + $value + ); + } + + /** + * Formats $value to the given length and appends SI prefixes + * with a $length of 0 no truncation occurs, number is only formated + * to the current locale + * + * examples: + * + * echo formatNumber(123456789, 6); // 123,457 k + * echo formatNumber(-123456789, 4, 2); // -123.46 M + * echo formatNumber(-0.003, 6); // -3 m + * echo formatNumber(0.003, 3, 3); // 0.003 + * echo formatNumber(0.00003, 3, 2); // 0.03 m + * echo formatNumber(0, 6); // 0 + * + * + * @param double $value the value to format + * @param integer $digits_left number of digits left of the comma + * @param integer $digits_right number of digits right of the comma + * @param boolean $only_down do not reformat numbers below 1 + * @param boolean $noTrailingZero removes trailing zeros right of the comma + * (default: true) + * + * @return string the formatted value and its unit + * + * @access public + */ + public static function formatNumber( + $value, $digits_left = 3, $digits_right = 0, + $only_down = false, $noTrailingZero = true + ) { + if ($value == 0) { + return '0'; + } + + $originalValue = $value; + //number_format is not multibyte safe, str_replace is safe + if ($digits_left === 0) { + $value = number_format($value, $digits_right); + if (($originalValue != 0) && (floatval($value) == 0)) { + $value = ' <' . (1 / self::pow(10, $digits_right)); + } + return self::localizeNumber($value); + } + + // this units needs no translation, ISO + $units = array( + -8 => 'y', + -7 => 'z', + -6 => 'a', + -5 => 'f', + -4 => 'p', + -3 => 'n', + -2 => 'µ', + -1 => 'm', + 0 => ' ', + 1 => 'k', + 2 => 'M', + 3 => 'G', + 4 => 'T', + 5 => 'P', + 6 => 'E', + 7 => 'Z', + 8 => 'Y' + ); + + // check for negative value to retain sign + if ($value < 0) { + $sign = '-'; + $value = abs($value); + } else { + $sign = ''; + } + + $dh = self::pow(10, $digits_right); + + /* + * This gives us the right SI prefix already, + * but $digits_left parameter not incorporated + */ + $d = floor(log10($value) / 3); + /* + * Lowering the SI prefix by 1 gives us an additional 3 zeros + * So if we have 3,6,9,12.. free digits ($digits_left - $cur_digits) + * to use, then lower the SI prefix + */ + $cur_digits = floor(log10($value / self::pow(1000, $d, 'pow'))+1); + if ($digits_left > $cur_digits) { + $d -= floor(($digits_left - $cur_digits)/3); + } + + if ($d < 0 && $only_down) { + $d = 0; + } + + $value = round($value / (self::pow(1000, $d, 'pow') / $dh)) /$dh; + $unit = $units[$d]; + + // If we dont want any zeros after the comma just add the thousand separator + if ($noTrailingZero) { + $value = self::localizeNumber( + preg_replace('/(?<=\d)(?=(\d{3})+(?!\d))/', ',', $value) + ); + } else { + //number_format is not multibyte safe, str_replace is safe + $value = self::localizeNumber(number_format($value, $digits_right)); + } + + if ($originalValue != 0 && floatval($value) == 0) { + return ' <' . (1 / self::pow(10, $digits_right)) . ' ' . $unit; + } + + return $sign . $value . ' ' . $unit; + } // end of the 'formatNumber' function + + /** + * Returns the number of bytes when a formatted size is given + * + * @param string $formatted_size the size expression (for example 8MB) + * + * @return integer The numerical part of the expression (for example 8) + */ + public static function extractValueFromFormattedSize($formatted_size) + { + $return_value = -1; + + if (preg_match('/^[0-9]+GB$/', $formatted_size)) { + $return_value = substr($formatted_size, 0, -2) * self::pow(1024, 3); + } elseif (preg_match('/^[0-9]+MB$/', $formatted_size)) { + $return_value = substr($formatted_size, 0, -2) * self::pow(1024, 2); + } elseif (preg_match('/^[0-9]+K$/', $formatted_size)) { + $return_value = substr($formatted_size, 0, -1) * self::pow(1024, 1); + } + return $return_value; + }// end of the 'extractValueFromFormattedSize' function + + /** + * Writes localised date + * + * @param string $timestamp the current timestamp + * @param string $format format + * + * @return string the formatted date + * + * @access public + */ + public static function localisedDate($timestamp = -1, $format = '') + { + $month = array( + /* l10n: Short month name */ + __('Jan'), + /* l10n: Short month name */ + __('Feb'), + /* l10n: Short month name */ + __('Mar'), + /* l10n: Short month name */ + __('Apr'), + /* l10n: Short month name */ + _pgettext('Short month name', 'May'), + /* l10n: Short month name */ + __('Jun'), + /* l10n: Short month name */ + __('Jul'), + /* l10n: Short month name */ + __('Aug'), + /* l10n: Short month name */ + __('Sep'), + /* l10n: Short month name */ + __('Oct'), + /* l10n: Short month name */ + __('Nov'), + /* l10n: Short month name */ + __('Dec')); + $day_of_week = array( + /* l10n: Short week day name */ + _pgettext('Short week day name', 'Sun'), + /* l10n: Short week day name */ + __('Mon'), + /* l10n: Short week day name */ + __('Tue'), + /* l10n: Short week day name */ + __('Wed'), + /* l10n: Short week day name */ + __('Thu'), + /* l10n: Short week day name */ + __('Fri'), + /* l10n: Short week day name */ + __('Sat')); + + if ($format == '') { + /* l10n: See http://www.php.net/manual/en/function.strftime.php */ + $format = __('%B %d, %Y at %I:%M %p'); + } + + if ($timestamp == -1) { + $timestamp = time(); + } + + $date = preg_replace( + '@%[aA]@', + $day_of_week[(int)strftime('%w', $timestamp)], + $format + ); + $date = preg_replace( + '@%[bB]@', + $month[(int)strftime('%m', $timestamp)-1], + $date + ); + + return strftime($date, $timestamp); + } // end of the 'localisedDate()' function + + /** + * returns a tab for tabbed navigation. + * If the variables $link and $args ar left empty, an inactive tab is created + * + * @param array $tab array with all options + * @param array $url_params tab specific URL parameters + * + * @return string html code for one tab, a link if valid otherwise a span + * + * @access public + */ + public static function getHtmlTab($tab, $url_params = array()) + { + // default values + $defaults = array( + 'text' => '', + 'class' => '', + 'active' => null, + 'link' => '', + 'sep' => '?', + 'attr' => '', + 'args' => '', + 'warning' => '', + 'fragment' => '', + 'id' => '', + ); + + $tab = array_merge($defaults, $tab); + + // determine additionnal style-class + if (empty($tab['class'])) { + if (! empty($tab['active']) + || PMA_isValid($GLOBALS['active_page'], 'identical', $tab['link']) + ) { + $tab['class'] = 'active'; + } elseif (is_null($tab['active']) && empty($GLOBALS['active_page']) + && (basename($GLOBALS['PMA_PHP_SELF']) == $tab['link']) + ) { + $tab['class'] = 'active'; + } + } + + // If there are any tab specific URL parameters, merge those with + // the general URL parameters + if (! empty($tab['url_params']) && is_array($tab['url_params'])) { + $url_params = array_merge($url_params, $tab['url_params']); + } + + // build the link + if (! empty($tab['link'])) { + $tab['link'] = htmlentities($tab['link']); + $tab['link'] = $tab['link'] . PMA_URL_getCommon($url_params); + if (! empty($tab['args'])) { + foreach ($tab['args'] as $param => $value) { + $tab['link'] .= PMA_URL_getArgSeparator('html') + . urlencode($param) . '=' . urlencode($value); + } + } + } + + if (! empty($tab['fragment'])) { + $tab['link'] .= $tab['fragment']; + } + + // display icon + if (isset($tab['icon'])) { + // avoid generating an alt tag, because it only illustrates + // the text that follows and if browser does not display + // images, the text is duplicated + $tab['text'] = self::getIcon( + $tab['icon'], + $tab['text'], + false, + true, + 'TabsMode' + ); + + } elseif (empty($tab['text'])) { + // check to not display an empty link-text + $tab['text'] = '?'; + trigger_error( + 'empty linktext in function ' . __FUNCTION__ . '()', + E_USER_NOTICE + ); + } + + //Set the id for the tab, if set in the params + $id_string = ( empty($tab['id']) ? '' : ' id="'.$tab['id'].'" ' ); + $out = ''; + + if (! empty($tab['link'])) { + $out .= '' + . $tab['text'] . ''; + } else { + $out .= '' . $tab['text'] . ''; + } + + $out .= ''; + return $out; + } // end of the 'getHtmlTab()' function + + /** + * returns html-code for a tab navigation + * + * @param array $tabs one element per tab + * @param string $url_params additional URL parameters + * @param string $menu_id HTML id attribute for the menu container + * @param bool $resizable whether to add a "resizable" class + * + * @return string html-code for tab-navigation + */ + public static function getHtmlTabs($tabs, $url_params, $menu_id, + $resizable = false + ) { + $class = ''; + if ($resizable) { + $class = ' class="resizable-menu"'; + } + + $tab_navigation = '' . "\n"; + + return $tab_navigation; + } + + /** + * Displays a link, or a button if the link's URL is too large, to + * accommodate some browsers' limitations + * + * @param string $url the URL + * @param string $message the link message + * @param mixed $tag_params string: js confirmation + * array: additional tag params (f.e. style="") + * @param boolean $new_form we set this to false when we are already in + * a form, to avoid generating nested forms + * @param boolean $strip_img whether to strip the image + * @param string $target target + * + * @return string the results to be echoed or saved in an array + */ + public static function linkOrButton( + $url, $message, $tag_params = array(), + $new_form = true, $strip_img = false, $target = '' + ) { + $url_length = strlen($url); + // with this we should be able to catch case of image upload + // into a (MEDIUM) BLOB; not worth generating even a form for these + if ($url_length > $GLOBALS['cfg']['LinkLengthLimit'] * 100) { + return ''; + } + + if (! is_array($tag_params)) { + $tmp = $tag_params; + $tag_params = array(); + if (! empty($tmp)) { + $tag_params['onclick'] = 'return confirmLink(this, \'' + . PMA_escapeJsString($tmp) . '\')'; + } + unset($tmp); + } + if (! empty($target)) { + $tag_params['target'] = htmlentities($target); + } + + $tag_params_strings = array(); + foreach ($tag_params as $par_name => $par_value) { + // htmlspecialchars() only on non javascript + $par_value = substr($par_name, 0, 2) == 'on' + ? $par_value + : htmlspecialchars($par_value); + $tag_params_strings[] = $par_name . '="' . $par_value . '"'; + } + + $displayed_message = ''; + // Add text if not already added + if (stristr($message, ''; + } + + // Suhosin: Check that each query parameter is not above maximum + $in_suhosin_limits = true; + if ($url_length <= $GLOBALS['cfg']['LinkLengthLimit']) { + $suhosin_get_MaxValueLength = ini_get('suhosin.get.max_value_length'); + if ($suhosin_get_MaxValueLength) { + $query_parts = self::splitURLQuery($url); + foreach ($query_parts as $query_pair) { + list($eachvar, $eachval) = explode('=', $query_pair); + if (strlen($eachval) > $suhosin_get_MaxValueLength) { + $in_suhosin_limits = false; + break; + } + } + } + } + + if (($url_length <= $GLOBALS['cfg']['LinkLengthLimit']) + && $in_suhosin_limits + ) { + // no whitespace within an else Safari will make it part of the link + $ret = "\n" . '' + . $message . $displayed_message . '' . "\n"; + } else { + // no spaces (linebreaks) at all + // or after the hidden fields + // IE will display them all + + // add class=link to submit button + if (empty($tag_params['class'])) { + $tag_params['class'] = 'link'; + } + + if (! isset($query_parts)) { + $query_parts = self::splitURLQuery($url); + } + $url_parts = parse_url($url); + + if ($new_form) { + $ret = ''; + } + } // end if... else... + + return $ret; + } // end of the 'linkOrButton()' function + + /** + * Splits a URL string by parameter + * + * @param string $url the URL + * + * @return array the parameter/value pairs, for example [0] db=sakila + */ + public static function splitURLQuery($url) + { + // decode encoded url separators + $separator = PMA_URL_getArgSeparator(); + // on most places separator is still hard coded ... + if ($separator !== '&') { + // ... so always replace & with $separator + $url = str_replace(htmlentities('&'), $separator, $url); + $url = str_replace('&', $separator, $url); + } + + $url = str_replace(htmlentities($separator), $separator, $url); + // end decode + + $url_parts = parse_url($url); + + return explode($separator, $url_parts['query']); + } + + /** + * Returns a given timespan value in a readable format. + * + * @param int $seconds the timespan + * + * @return string the formatted value + */ + public static function timespanFormat($seconds) + { + $days = floor($seconds / 86400); + if ($days > 0) { + $seconds -= $days * 86400; + } + + $hours = floor($seconds / 3600); + if ($days > 0 || $hours > 0) { + $seconds -= $hours * 3600; + } + + $minutes = floor($seconds / 60); + if ($days > 0 || $hours > 0 || $minutes > 0) { + $seconds -= $minutes * 60; + } + + return sprintf( + __('%s days, %s hours, %s minutes and %s seconds'), + (string)$days, (string)$hours, (string)$minutes, (string)$seconds + ); + } + + /** + * Takes a string and outputs each character on a line for itself. Used + * mainly for horizontalflipped display mode. + * Takes care of special html-characters. + * Fulfills https://sourceforge.net/p/phpmyadmin/feature-requests/164/ + * + * @param string $string The string + * @param string $Separator The Separator (defaults to "
    \n") + * + * @access public + * @todo add a multibyte safe function $GLOBALS['PMA_String']->split() + * + * @return string The flipped string + */ + public static function flipstring($string, $Separator = "
    \n") + { + $format_string = ''; + $charbuff = false; + + for ($i = 0, $str_len = strlen($string); $i < $str_len; $i++) { + $char = $string{$i}; + $append = false; + + if ($char == '&') { + $format_string .= $charbuff; + $charbuff = $char; + } elseif ($char == ';' && ! empty($charbuff)) { + $format_string .= $charbuff . $char; + $charbuff = false; + $append = true; + } elseif (! empty($charbuff)) { + $charbuff .= $char; + } else { + $format_string .= $char; + $append = true; + } + + // do not add separator after the last character + if ($append && ($i != $str_len - 1)) { + $format_string .= $Separator; + } + } + + return $format_string; + } + + /** + * Function added to avoid path disclosures. + * Called by each script that needs parameters, it displays + * an error message and, by default, stops the execution. + * + * Not sure we could use a strMissingParameter message here, + * would have to check if the error message file is always available + * + * @param array $params The names of the parameters needed by the calling script + * @param bool $request Whether to include this list in checking for + * special params + * + * @return void + * + * @global boolean $checked_special flag whether any special variable was required + * + * @access public + */ + public static function checkParameters($params, $request = true) + { + global $checked_special; + + if (! isset($checked_special)) { + $checked_special = false; + } + + $reported_script_name = basename($GLOBALS['PMA_PHP_SELF']); + $found_error = false; + $error_message = ''; + + foreach ($params as $param) { + if ($request && ($param != 'db') && ($param != 'table')) { + $checked_special = true; + } + + if (! isset($GLOBALS[$param])) { + $error_message .= $reported_script_name + . ': ' . __('Missing parameter:') . ' ' + . $param + . self::showDocu('faq', 'faqmissingparameters') + . '
    '; + $found_error = true; + } + } + if ($found_error) { + PMA_fatalError($error_message, null, false); + } + } // end function + + /** + * Function to generate unique condition for specified row. + * + * @param resource $handle current query result + * @param integer $fields_cnt number of fields + * @param array $fields_meta meta information about fields + * @param array $row current row + * @param boolean $force_unique generate condition only on pk or unique + * + * @access public + * + * @return array the calculated condition and whether condition is unique + */ + public static function getUniqueCondition( + $handle, $fields_cnt, $fields_meta, $row, $force_unique = false + ) { + $primary_key = ''; + $unique_key = ''; + $nonprimary_condition = ''; + $preferred_condition = ''; + $primary_key_array = array(); + $unique_key_array = array(); + $nonprimary_condition_array = array(); + $condition_array = array(); + + for ($i = 0; $i < $fields_cnt; ++$i) { + + $condition = ''; + $con_key = ''; + $con_val = ''; + $field_flags = $GLOBALS['dbi']->fieldFlags($handle, $i); + $meta = $fields_meta[$i]; + + // do not use a column alias in a condition + if (! isset($meta->orgname) || ! strlen($meta->orgname)) { + $meta->orgname = $meta->name; + + if (isset($GLOBALS['analyzed_sql'][0]['select_expr']) + && is_array($GLOBALS['analyzed_sql'][0]['select_expr']) + ) { + foreach ( + $GLOBALS['analyzed_sql'][0]['select_expr'] as $select_expr + ) { + // need (string) === (string) + // '' !== 0 but '' == 0 + if ((string)$select_expr['alias'] === (string)$meta->name) { + $meta->orgname = $select_expr['column']; + break; + } // end if + } // end foreach + } + } + + // Do not use a table alias in a condition. + // Test case is: + // select * from galerie x WHERE + //(select count(*) from galerie y where y.datum=x.datum)>1 + // + // But orgtable is present only with mysqli extension so the + // fix is only for mysqli. + // Also, do not use the original table name if we are dealing with + // a view because this view might be updatable. + // (The isView() verification should not be costly in most cases + // because there is some caching in the function). + if (isset($meta->orgtable) + && ($meta->table != $meta->orgtable) + && ! PMA_Table::isView($GLOBALS['db'], $meta->table) + ) { + $meta->table = $meta->orgtable; + } + + // to fix the bug where float fields (primary or not) + // can't be matched because of the imprecision of + // floating comparison, use CONCAT + // (also, the syntax "CONCAT(field) IS NULL" + // that we need on the next "if" will work) + if ($meta->type == 'real') { + $con_key = 'CONCAT(' . self::backquote($meta->table) . '.' + . self::backquote($meta->orgname) . ')'; + } else { + $con_key = self::backquote($meta->table) . '.' + . self::backquote($meta->orgname); + } // end if... else... + $condition = ' ' . $con_key . ' '; + + if (! isset($row[$i]) || is_null($row[$i])) { + $con_val = 'IS NULL'; + } else { + // timestamp is numeric on some MySQL 4.1 + // for real we use CONCAT above and it should compare to string + if ($meta->numeric + && ($meta->type != 'timestamp') + && ($meta->type != 'real') + ) { + $con_val = '= ' . $row[$i]; + } elseif ((($meta->type == 'blob') || ($meta->type == 'string')) + && stristr($field_flags, 'BINARY') + && ! empty($row[$i]) + ) { + // hexify only if this is a true not empty BLOB or a BINARY + + // do not waste memory building a too big condition + if (strlen($row[$i]) < 1000) { + // use a CAST if possible, to avoid problems + // if the field contains wildcard characters % or _ + $con_val = '= CAST(0x' . bin2hex($row[$i]) . ' AS BINARY)'; + } else if ($fields_cnt == 1) { + // when this blob is the only field present + // try settling with length comparison + $condition = ' CHAR_LENGTH(' . $con_key . ') '; + $con_val = ' = ' . strlen($row[$i]); + } else { + // this blob won't be part of the final condition + $con_val = null; + } + } elseif (in_array($meta->type, self::getGISDatatypes()) + && ! empty($row[$i]) + ) { + // do not build a too big condition + if (strlen($row[$i]) < 5000) { + $condition .= '=0x' . bin2hex($row[$i]) . ' AND'; + } else { + $condition = ''; + } + } elseif ($meta->type == 'bit') { + $con_val = "= b'" + . self::printableBitValue($row[$i], $meta->length) . "'"; + } else { + $con_val = '= \'' + . self::sqlAddSlashes($row[$i], false, true) . '\''; + } + } + + if ($con_val != null) { + + $condition .= $con_val . ' AND'; + + if ($meta->primary_key > 0) { + $primary_key .= $condition; + $primary_key_array[$con_key] = $con_val; + } elseif ($meta->unique_key > 0) { + $unique_key .= $condition; + $unique_key_array[$con_key] = $con_val; + } + + $nonprimary_condition .= $condition; + $nonprimary_condition_array[$con_key] = $con_val; + } + } // end for + + // Correction University of Virginia 19991216: + // prefer primary or unique keys for condition, + // but use conjunction of all values if no primary key + $clause_is_unique = true; + + if ($primary_key) { + $preferred_condition = $primary_key; + $condition_array = $primary_key_array; + + } elseif ($unique_key) { + $preferred_condition = $unique_key; + $condition_array = $unique_key_array; + + } elseif (! $force_unique) { + $preferred_condition = $nonprimary_condition; + $condition_array = $nonprimary_condition_array; + $clause_is_unique = false; + } + + $where_clause = trim(preg_replace('|\s?AND$|', '', $preferred_condition)); + return(array($where_clause, $clause_is_unique, $condition_array)); + } // end function + + /** + * Generate a button or image tag + * + * @param string $button_name name of button element + * @param string $button_class class of button or image element + * @param string $image_name name of image element + * @param string $text text to display + * @param string $image image to display + * @param string $value value + * + * @return string html content + * + * @access public + */ + public static function getButtonOrImage( + $button_name, $button_class, $image_name, $text, $image, $value = '' + ) { + if ($value == '') { + $value = $text; + } + + if ($GLOBALS['cfg']['ActionLinksMode'] == 'text') { + return ' ' . "\n"; + } + + /* Opera has trouble with */ + /* IE (before version 9) has trouble with ' . "\n"; + } + } // end function + + /** + * Generate a pagination selector for browsing resultsets + * + * @param string $name The name for the request parameter + * @param int $rows Number of rows in the pagination set + * @param int $pageNow current page number + * @param int $nbTotalPage number of total pages + * @param int $showAll If the number of pages is lower than this + * variable, no pages will be omitted in pagination + * @param int $sliceStart How many rows at the beginning should always + * be shown? + * @param int $sliceEnd How many rows at the end should always be shown? + * @param int $percent Percentage of calculation page offsets to hop to a + * next page + * @param int $range Near the current page, how many pages should + * be considered "nearby" and displayed as well? + * @param string $prompt The prompt to display (sometimes empty) + * + * @return string + * + * @access public + */ + public static function pageselector( + $name, $rows, $pageNow = 1, $nbTotalPage = 1, $showAll = 200, + $sliceStart = 5, + $sliceEnd = 5, $percent = 20, $range = 10, $prompt = '' + ) { + $increment = floor($nbTotalPage / $percent); + $pageNowMinusRange = ($pageNow - $range); + $pageNowPlusRange = ($pageNow + $range); + + $gotopage = $prompt . ' '; + + return $gotopage; + } // end function + + /** + * Prepare navigation for a list + * + * @param int $count number of elements in the list + * @param int $pos current position in the list + * @param array $_url_params url parameters + * @param string $script script name for form target + * @param string $frame target frame + * @param int $max_count maximum number of elements to display from the list + * @param string $name the name for the request parameter + * @param array $classes additional classes for the container + * + * @return string $list_navigator_html the html content + * + * @access public + * + * @todo use $pos from $_url_params + */ + public static function getListNavigator( + $count, $pos, $_url_params, $script, $frame, $max_count, $name = 'pos', + $classes = array() + ) { + + $class = $frame == 'frame_navigation' ? ' class="ajax"' : ''; + + $list_navigator_html = ''; + + if ($max_count < $count) { + + $classes[] = 'pageselector'; + $list_navigator_html .= '
    '; + + if ($frame != 'frame_navigation') { + $list_navigator_html .= __('Page number:'); + } + + // Move to the beginning or to the previous page + if ($pos > 0) { + if (self::showIcons('TableNavigationLinksMode')) { + $caption1 = '<<'; + $caption2 = ' < '; + $title1 = ' title="' . _pgettext('First page', 'Begin') . '"'; + $title2 = ' title="' + . _pgettext('Previous page', 'Previous') . '"'; + } else { + $caption1 = _pgettext('First page', 'Begin') . ' <<'; + $caption2 = _pgettext('Previous page', 'Previous') . ' <'; + $title1 = ''; + $title2 = ''; + } // end if... else... + + $_url_params[$name] = 0; + $list_navigator_html .= '' . $caption1 + . ''; + + $_url_params[$name] = $pos - $max_count; + $list_navigator_html .= '' . $caption2 + . ''; + } + + $list_navigator_html .= '
    '; + + $list_navigator_html .= PMA_URL_getHiddenInputs($_url_params); + $list_navigator_html .= self::pageselector( + $name, + $max_count, + floor(($pos + 1) / $max_count) + 1, + ceil($count / $max_count) + ); + $list_navigator_html .= '
    '; + + if ($pos + $max_count < $count) { + if ( self::showIcons('TableNavigationLinksMode')) { + $caption3 = ' > '; + $caption4 = '>>'; + $title3 = ' title="' . _pgettext('Next page', 'Next') . '"'; + $title4 = ' title="' . _pgettext('Last page', 'End') . '"'; + } else { + $caption3 = '> ' . _pgettext('Next page', 'Next'); + $caption4 = '>> ' . _pgettext('Last page', 'End'); + $title3 = ''; + $title4 = ''; + } // end if... else... + + $_url_params[$name] = $pos + $max_count; + $list_navigator_html .= '' . $caption3 + . ''; + + $_url_params[$name] = floor($count / $max_count) * $max_count; + if ($_url_params[$name] == $count) { + $_url_params[$name] = $count - $max_count; + } + + $list_navigator_html .= '' . $caption4 + . ''; + } + $list_navigator_html .= '
    ' . "\n"; + } + + return $list_navigator_html; + } + + /** + * replaces %u in given path with current user name + * + * example: + * + * $user_dir = userDir('/var/pma_tmp/%u/'); // '/var/pma_tmp/root/' + * + * + * + * @param string $dir with wildcard for user + * + * @return string per user directory + */ + public static function userDir($dir) + { + // add trailing slash + if (substr($dir, -1) != '/') { + $dir .= '/'; + } + + return str_replace('%u', $GLOBALS['cfg']['Server']['user'], $dir); + } + + /** + * returns html code for db link to default db page + * + * @param string $database database + * + * @return string html link to default db page + */ + public static function getDbLink($database = null) + { + if (! strlen($database)) { + if (! strlen($GLOBALS['db'])) { + return ''; + } + $database = $GLOBALS['db']; + } else { + $database = self::unescapeMysqlWildcards($database); + } + + return '' . htmlspecialchars($database) . ''; + } + + /** + * Prepare a lightbulb hint explaining a known external bug + * that affects a functionality + * + * @param string $functionality localized message explaining the func. + * @param string $component 'mysql' (eventually, 'php') + * @param string $minimum_version of this component + * @param string $bugref bug reference for this component + * + * @return String + */ + public static function getExternalBug( + $functionality, $component, $minimum_version, $bugref + ) { + $ext_but_html = ''; + if (($component == 'mysql') && (PMA_MYSQL_INT_VERSION < $minimum_version)) { + $ext_but_html .= self::showHint( + sprintf( + __('The %s functionality is affected by a known bug, see %s'), + $functionality, + PMA_linkURL('http://bugs.mysql.com/') . $bugref + ) + ); + } + return $ext_but_html; + } + + /** + * Returns a HTML checkbox + * + * @param string $html_field_name the checkbox HTML field + * @param string $label label for checkbox + * @param boolean $checked is it initially checked? + * @param boolean $onclick should it submit the form on click? + * + * @return string HTML for the checkbox + */ + public static function getCheckbox($html_field_name, $label, $checked, $onclick) + { + return ''; + } + + /** + * Generates a set of radio HTML fields + * + * @param string $html_field_name the radio HTML field + * @param array $choices the choices values and labels + * @param string $checked_choice the choice to check by default + * @param boolean $line_break whether to add HTML line break after a choice + * @param boolean $escape_label whether to use htmlspecialchars() on label + * @param string $class enclose each choice with a div of this class + * + * @return string set of html radio fiels + */ + public static function getRadioFields( + $html_field_name, $choices, $checked_choice = '', + $line_break = true, $escape_label = true, $class = '' + ) { + $radio_html = ''; + + foreach ($choices as $choice_value => $choice_label) { + + if (! empty($class)) { + $radio_html .= '
    '; + } + + $html_field_id = $html_field_name . '_' . $choice_value; + $radio_html .= '' + . ($escape_label + ? htmlspecialchars($choice_label) + : $choice_label) + . ''; + + if ($line_break) { + $radio_html .= '
    '; + } + + if (! empty($class)) { + $radio_html .= '
    '; + } + $radio_html .= "\n"; + } + + return $radio_html; + } + + /** + * Generates and returns an HTML dropdown + * + * @param string $select_name name for the select element + * @param array $choices choices values + * @param string $active_choice the choice to select by default + * @param string $id id of the select element; can be different in + * case the dropdown is present more than once + * on the page + * @param string $class class for the select element + * + * @return string html content + * + * @todo support titles + */ + public static function getDropdown( + $select_name, $choices, $active_choice, $id, $class = '' + ) { + $result = ''; + + foreach ($choices as $one_choice_value => $one_choice_label) { + $result .= '
    ' + . '
    '; + + return $html_output; +} + diff --git a/phpMyAdmin/libraries/information_schema_relations.lib.php b/phpMyAdmin/libraries/information_schema_relations.lib.php index 68ba11c..d153207 100644 --- a/phpMyAdmin/libraries/information_schema_relations.lib.php +++ b/phpMyAdmin/libraries/information_schema_relations.lib.php @@ -1,9 +1,13 @@ 'information_schema', 'foreign_table' => 'COLLATIONS', 'foreign_field' => 'COLLATION_NAME' + ), + 'CHARACTER_SET_NAME' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'CHARACTER_SETS', + 'foreign_field' => 'CHARACTER_SET_NAME' ) ), 'COLLATIONS' => array( @@ -59,6 +68,50 @@ 'foreign_field' => 'SCHEMA_NAME' ) ), + 'EVENTS' => array( + 'EVENT_SCHEMA' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'SCHEMATA', + 'foreign_field' => 'SCHEMA_NAME' + ), + 'CHARACTER_SET_CLIENT' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'CHARACTER_SETS', + 'foreign_field' => 'CHARACTER_SET_NAME' + ), + 'COLLATION_CONNECTION' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'COLLATIONS', + 'foreign_field' => 'COLLATION_NAME' + ), + 'DATABASE_COLLATION' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'COLLATIONS', + 'foreign_field' => 'COLLATION_NAME' + ) + ), + 'FILES' => array( + 'TABLESPACE_NAME' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'TABLESPACES', + 'foreign_field' => 'TABLESPACE_NAME' + ), + 'TABLE_SCHEMA' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'SCHEMATA', + 'foreign_field' => 'SCHEMA_NAME' + ), + 'COLLATION_CONNECTION' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'COLLATIONS', + 'foreign_field' => 'COLLATION_NAME' + ), + 'ENGINE' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'ENGINES', + 'foreign_field' => 'ENGINE' + ) + ), 'KEY_COLUMN_USAGE' => array( 'CONSTRAINT_SCHEMA' => array( 'foreign_db' => 'information_schema', @@ -69,6 +122,59 @@ 'foreign_db' => 'information_schema', 'foreign_table' => 'SCHEMATA', 'foreign_field' => 'SCHEMA_NAME' + ), + 'REFERENCED_TABLE_SCHEMA' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'SCHEMATA', + 'foreign_field' => 'SCHEMA_NAME' + ) + ), + 'PARAMETERS' => array( + 'SPECIFIC_SCHEMA' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'SCHEMATA', + 'foreign_field' => 'SCHEMA_NAME' + ), + 'CHARACTER_SET_NAME' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'CHARACTER_SETS', + 'foreign_field' => 'CHARACTER_SET_NAME' + ), + 'COLLATION_NAME' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'COLLATIONS', + 'foreign_field' => 'COLLATION_NAME' + ) + ), + 'PARTITIONS' => array( + 'TABLE_SCHEMA' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'SCHEMATA', + 'foreign_field' => 'SCHEMA_NAME' + ), + 'TABLESPACE_NAME' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'TABLESPACES', + 'foreign_field' => 'TABLESPACE_NAME' + ) + ), + 'PROCESSLIST' => array( + 'DB' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'SCHEMATA', + 'foreign_field' => 'SCHEMA_NAME' + ) + ), + 'REFERENTIAL_CONSTRAINTS' => array( + 'CONSTRAINT_SCHEMA' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'SCHEMATA', + 'foreign_field' => 'SCHEMA_NAME' + ), + 'UNIQUE_CONSTRAINT_SCHEMA' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'SCHEMATA', + 'foreign_field' => 'SCHEMA_NAME' ) ), 'ROUTINES' => array( @@ -76,6 +182,31 @@ 'foreign_db' => 'information_schema', 'foreign_table' => 'SCHEMATA', 'foreign_field' => 'SCHEMA_NAME' + ), + 'CHARACTER_SET_NAME' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'CHARACTER_SETS', + 'foreign_field' => 'CHARACTER_SET_NAME' + ), + 'COLLATION_NAME' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'COLLATIONS', + 'foreign_field' => 'COLLATION_NAME' + ), + 'CHARACTER_SET_CLIENT' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'CHARACTER_SETS', + 'foreign_field' => 'CHARACTER_SET_NAME' + ), + 'COLLATION_CONNECTION' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'COLLATIONS', + 'foreign_field' => 'COLLATION_NAME' + ), + 'DATABASE_COLLATION' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'COLLATIONS', + 'foreign_field' => 'COLLATION_NAME' ) ), 'SCHEMATA' => array( @@ -83,6 +214,11 @@ 'foreign_db' => 'information_schema', 'foreign_table' => 'CHARACTER_SETS', 'foreign_field' => 'CHARACTER_SET_NAME' + ), + 'DEFAULT_COLLATION_NAME' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'COLLATIONS', + 'foreign_field' => 'COLLATION_NAME' ) ), 'SCHEMA_PRIVILEGES' => array( @@ -92,6 +228,18 @@ 'foreign_field' => 'SCHEMA_NAME' ) ), + 'STATISTICS' => array( + 'TABLE_SCHEMA' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'SCHEMATA', + 'foreign_field' => 'SCHEMA_NAME' + ), + 'INDEX_SCHEMA' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'SCHEMATA', + 'foreign_field' => 'SCHEMA_NAME' + ) + ), 'TABLES' => array( 'TABLE_SCHEMA' => array( 'foreign_db' => 'information_schema', @@ -102,6 +250,18 @@ 'foreign_db' => 'information_schema', 'foreign_table' => 'COLLATIONS', 'foreign_field' => 'COLLATION_NAME' + ), + 'ENGINE' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'ENGINES', + 'foreign_field' => 'ENGINE' + ), + ), + 'TABLESAPCES' => array( + 'ENGINE' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'ENGINES', + 'foreign_field' => 'ENGINE' ) ), 'TABLE_CONSTRAINTS' => array( @@ -123,11 +283,48 @@ 'foreign_field' => 'SCHEMA_NAME' ) ), + 'TRIGGERS' => array( + 'TRIGGER_SCHEMA' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'SCHEMATA', + 'foreign_field' => 'SCHEMA_NAME' + ), + 'EVENT_OBJECT_SCHEMA' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'SCHEMATA', + 'foreign_field' => 'SCHEMA_NAME' + ), + 'CHARACTER_SET_CLIENT' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'CHARACTER_SETS', + 'foreign_field' => 'CHARACTER_SET_NAME' + ), + 'COLLATION_CONNECTION' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'COLLATIONS', + 'foreign_field' => 'COLLATION_NAME' + ), + 'DATABASE_COLLATION' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'COLLATIONS', + 'foreign_field' => 'COLLATION_NAME' + ) + ), 'VIEWS' => array( 'TABLE_SCHEMA' => array( 'foreign_db' => 'information_schema', 'foreign_table' => 'SCHEMATA', 'foreign_field' => 'SCHEMA_NAME' + ), + 'CHARACTER_SET_CLIENT' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'CHARACTER_SETS', + 'foreign_field' => 'CHARACTER_SET_NAME' + ), + 'COLLATION_CONNECTION' => array( + 'foreign_db' => 'information_schema', + 'foreign_table' => 'COLLATIONS', + 'foreign_field' => 'COLLATION_NAME' ) ) ); diff --git a/phpMyAdmin/libraries/insert_edit.lib.php b/phpMyAdmin/libraries/insert_edit.lib.php new file mode 100644 index 0000000..54bcdfd --- /dev/null +++ b/phpMyAdmin/libraries/insert_edit.lib.php @@ -0,0 +1,2920 @@ + $db, + 'table' => $table, + 'goto' => $GLOBALS['goto'], + 'err_url' => $err_url, + 'sql_query' => $_REQUEST['sql_query'], + ); + if (isset($where_clauses)) { + foreach ($where_clause_array as $key_id => $where_clause) { + $_form_params['where_clause[' . $key_id . ']'] = trim($where_clause); + } + } + if (isset($_REQUEST['clause_is_unique'])) { + $_form_params['clause_is_unique'] = $_REQUEST['clause_is_unique']; + } + return $_form_params; +} + +/** + * Creates array of where clauses + * + * @param array $where_clause where clause + * + * @return array|void whereClauseArray array of where clauses + */ +function PMA_getWhereClauseArray($where_clause) +{ + if (isset ($where_clause)) { + if (is_array($where_clause)) { + return $where_clause; + } else { + return array(0 => $where_clause); + } + } +} + +/** + * Analysing where clauses array + * + * @param array $where_clause_array array of where clauses + * @param string $table name of the table + * @param string $db name of the database + * + * @return array $where_clauses, $result, $rows + */ +function PMA_analyzeWhereClauses( + $where_clause_array, $table, $db +) { + $rows = array(); + $result = array(); + $where_clauses = array(); + $found_unique_key = false; + foreach ($where_clause_array as $key_id => $where_clause) { + + $local_query = 'SELECT * FROM ' + . PMA_Util::backquote($db) . '.' + . PMA_Util::backquote($table) + . ' WHERE ' . $where_clause . ';'; + $result[$key_id] = $GLOBALS['dbi']->query( + $local_query, null, PMA_DatabaseInterface::QUERY_STORE + ); + $rows[$key_id] = $GLOBALS['dbi']->fetchAssoc($result[$key_id]); + + $where_clauses[$key_id] = str_replace('\\', '\\\\', $where_clause); + $has_unique_condition = PMA_showEmptyResultMessageOrSetUniqueCondition( + $rows, $key_id, $where_clause_array, $local_query, $result + ); + if ($has_unique_condition) { + $found_unique_key = true; + } + } + return array($where_clauses, $result, $rows, $found_unique_key); +} + +/** + * Show message for empty result or set the unique_condition + * + * @param array $rows MySQL returned rows + * @param string $key_id ID in current key + * @param array $where_clause_array array of where clauses + * @param string $local_query query performed + * @param array $result MySQL result handle + * + * @return boolean $has_unique_condition + */ +function PMA_showEmptyResultMessageOrSetUniqueCondition($rows, $key_id, + $where_clause_array, $local_query, $result +) { + $has_unique_condition = false; + + // No row returned + if (! $rows[$key_id]) { + unset($rows[$key_id], $where_clause_array[$key_id]); + PMA_Response::getInstance()->addHtml( + PMA_Util::getMessage( + __('MySQL returned an empty result set (i.e. zero rows).'), + $local_query + ) + ); + /** + * @todo not sure what should be done at this point, but we must not + * exit if we want the message to be displayed + */ + } else {// end if (no row returned) + $meta = $GLOBALS['dbi']->getFieldsMeta($result[$key_id]); + + list($unique_condition, $tmp_clause_is_unique) + = PMA_Util::getUniqueCondition( + $result[$key_id], count($meta), $meta, $rows[$key_id], true + ); + + if (! empty($unique_condition)) { + $has_unique_condition = true; + } + unset($unique_condition, $tmp_clause_is_unique); + } + return $has_unique_condition; +} + +/** + * No primary key given, just load first row + * + * @param string $table name of the table + * @param string $db name of the database + * + * @return array containing $result and $rows arrays + */ +function PMA_loadFirstRow($table, $db) +{ + $result = $GLOBALS['dbi']->query( + 'SELECT * FROM ' . PMA_Util::backquote($db) + . '.' . PMA_Util::backquote($table) . ' LIMIT 1;', + null, + PMA_DatabaseInterface::QUERY_STORE + ); + $rows = array_fill(0, $GLOBALS['cfg']['InsertRows'], false); + return array($result, $rows); +} + +/** + * Add some url parameters + * + * @param array $url_params containing $db and $table as url parameters + * @param array $where_clause_array where clauses array + * @param string $where_clause where clause + * + * @return array Add some url parameters to $url_params array and return it + */ +function PMA_urlParamsInEditMode($url_params, $where_clause_array, $where_clause) +{ + if (isset($where_clause)) { + foreach ($where_clause_array as $where_clause) { + $url_params['where_clause'] = trim($where_clause); + } + } + if (! empty($_REQUEST['sql_query'])) { + $url_params['sql_query'] = $_REQUEST['sql_query']; + } + return $url_params; +} + +/** + * Show function fields in data edit view in pma + * + * @param array $url_params containing url parameters + * @param boolean $showFuncFields whether to show function field + * + * @return string an html snippet + */ +function PMA_showFunctionFieldsInEditMode($url_params, $showFuncFields) +{ + $params = array(); + if (! $showFuncFields) { + $params['ShowFunctionFields'] = 1; + } else { + $params['ShowFunctionFields'] = 0; + } + $params['ShowFieldTypesInDataEditView'] + = $GLOBALS['cfg']['ShowFieldTypesInDataEditView']; + $params['goto'] = 'sql.php'; + $this_url_params = array_merge($url_params, $params); + if (! $showFuncFields) { + return ' : ' + . __('Function') + . '' . "\n"; + } + return '' + . __('Function') + . '' . "\n"; +} + +/** + * Show field types in data edit view in pma + * + * @param array $url_params containing url parameters + * @param boolean $showColumnType whether to show column type + * + * @return string an html snippet + */ +function PMA_showColumnTypesInDataEditView($url_params, $showColumnType) +{ + $params = array(); + if (! $showColumnType) { + $params['ShowFieldTypesInDataEditView'] = 1; + } else { + $params['ShowFieldTypesInDataEditView'] = 0; + } + $params['ShowFunctionFields'] = $GLOBALS['cfg']['ShowFunctionFields']; + $params['goto'] = 'sql.php'; + $this_other_url_params = array_merge($url_params, $params); + if (! $showColumnType) { + return ' : ' + . __('Type') . '' . "\n"; + } + return '' . __('Type') . '' . "\n"; + +} + +/** + * Retrieve the default for datetime data type + * + * @param array $column containing column type, Default and null + * + * @return void + */ +function PMA_getDefaultForDatetime($column) +{ + // d a t e t i m e + // + // Current date should not be set as default if the field is NULL + // for the current row, but do not put here the current datetime + // if there is a default value (the real default value will be set + // in the Default value logic below) + + // Note: (tested in MySQL 4.0.16): when lang is some UTF-8, + // $column['Default'] is not set if it contains NULL: + // Array ([Field] => d [Type] => datetime [Null] => YES [Key] => + // [Extra] => [True_Type] => datetime) + // but, look what we get if we switch to iso: (Default is NULL) + // Array ([Field] => d [Type] => datetime [Null] => YES [Key] => + // [Default] => [Extra] => [True_Type] => datetime) + // so I force a NULL into it (I don't think it's possible + // to have an empty default value for DATETIME) + // then, the "if" after this one will work + if ($column['Type'] == 'datetime' + && ! isset($column['Default']) + && isset($column['Null']) + && $column['Null'] == 'YES' + ) { + $column['Default'] = null; + } +} + + /** + * Analyze the table column array + * + * @param array $column description of column in given table + * @param array $comments_map comments for every column that has a comment + * @param boolean $timestamp_seen whether a timestamp has been seen + * + * @return array description of column in given table + */ +function PMA_analyzeTableColumnsArray($column, $comments_map, $timestamp_seen) +{ + $column['Field_html'] = htmlspecialchars($column['Field']); + $column['Field_md5'] = md5($column['Field']); + // True_Type contains only the type (stops at first bracket) + $column['True_Type'] = preg_replace('@\(.*@s', '', $column['Type']); + PMA_getDefaultForDatetime($column); + $column['len'] = preg_match('@float|double@', $column['Type']) ? 100 : -1; + $column['Field_title'] = PMA_getColumnTitle($column, $comments_map); + $column['is_binary'] = PMA_isColumnBinary($column); + $column['is_blob'] = PMA_isColumnBlob($column); + $column['is_char'] = PMA_isColumnChar($column); + list($column['pma_type'], $column['wrap'], $column['first_timestamp']) + = PMA_getEnumSetAndTimestampColumns($column, $timestamp_seen); + + return $column; +} + + /** + * Retrieve the column title + * + * @param array $column description of column in given table + * @param array $comments_map comments for every column that has a comment + * + * @return string column title + */ +function PMA_getColumnTitle($column, $comments_map) +{ + if (isset($comments_map[$column['Field']])) { + return '' + . $column['Field_html'] . ''; + } else { + return $column['Field_html']; + } +} + + /** + * check whether the column is a bainary + * + * @param array $column description of column in given table + * + * @return boolean If check to ensure types such as "enum('one','two','binary',..)" + * or "enum('one','two','varbinary',..)" are not categorized as + * binary. + */ +function PMA_isColumnBinary($column) +{ + // The type column. + // Fix for bug #3152931 'ENUM and SET cannot have "Binary" option' + if (stripos($column['Type'], 'binary') === 0 + || stripos($column['Type'], 'varbinary') === 0 + ) { + return stristr($column['Type'], 'binary'); + } else { + return false; + } + +} + + /** + * check whether the column is a blob + * + * @param array $column description of column in given table + * + * @return boolean If check to ensure types such as "enum('one','two','blob',..)" + * or "enum('one','two','tinyblob',..)" etc. are not categorized + * as blob. + */ +function PMA_isColumnBlob($column) +{ + if (stripos($column['Type'], 'blob') === 0 + || stripos($column['Type'], 'tinyblob') === 0 + || stripos($column['Type'], 'mediumblob') === 0 + || stripos($column['Type'], 'longblob') === 0 + ) { + return stristr($column['Type'], 'blob'); + } else { + return false; + } +} + +/** + * check is table column char + * + * @param array $column description of column in given table + * + * @return boolean If check to ensure types such as "enum('one','two','char',..)" or + * "enum('one','two','varchar',..)" are not categorized as char. + */ +function PMA_isColumnChar($column) +{ + if (stripos($column['Type'], 'char') === 0 + || stripos($column['Type'], 'varchar') === 0 + ) { + return stristr($column['Type'], 'char'); + } else { + return false; + } +} +/** + * Retrieve set, enum, timestamp table columns + * + * @param array $column description of column in given table + * @param boolean $timestamp_seen whether a timestamp has been seen + * + * @return array $column['pma_type'], $column['wrap'], $column['first_timestamp'] + */ +function PMA_getEnumSetAndTimestampColumns($column, $timestamp_seen) +{ + $column['first_timestamp'] = false; + switch ($column['True_Type']) { + case 'set': + $column['pma_type'] = 'set'; + $column['wrap'] = ''; + break; + case 'enum': + $column['pma_type'] = 'enum'; + $column['wrap'] = ''; + break; + case 'timestamp': + if (! $timestamp_seen) { // can only occur once per table + $timestamp_seen = true; + $column['first_timestamp'] = true; + } + $column['pma_type'] = $column['Type']; + $column['wrap'] = ' nowrap'; + break; + + default: + $column['pma_type'] = $column['Type']; + $column['wrap'] = ' nowrap'; + break; + } + return array($column['pma_type'], $column['wrap'], $column['first_timestamp']); +} + +/** + * The function column + * We don't want binary data to be destroyed + * Note: from the MySQL manual: "BINARY doesn't affect how the column is + * stored or retrieved" so it does not mean that the contents is binary + * + * @param array $column description of column in given table + * @param boolean $is_upload upload or no + * @param string $column_name_appendix the name atttibute + * @param string $unnullify_trigger validation string + * @param array $no_support_types list of datatypes that are not (yet) + * handled by PMA + * @param integer $tabindex_for_function +3000 + * @param integer $tabindex tab index + * @param integer $idindex id index + * @param boolean $insert_mode insert mode or edit mode + * + * @return string an html sippet + */ +function PMA_getFunctionColumn($column, $is_upload, $column_name_appendix, + $unnullify_trigger, $no_support_types, $tabindex_for_function, + $tabindex, $idindex, $insert_mode +) { + $html_output = ''; + if (($GLOBALS['cfg']['ProtectBinary'] && $column['is_blob'] && ! $is_upload) + || ($GLOBALS['cfg']['ProtectBinary'] === 'all' && $column['is_binary']) + || ($GLOBALS['cfg']['ProtectBinary'] === 'noblob' && ! $column['is_blob']) + ) { + $html_output .= '' . __('Binary') . '' . "\n"; + } elseif (strstr($column['True_Type'], 'enum') + || strstr($column['True_Type'], 'set') + || in_array($column['pma_type'], $no_support_types) + ) { + $html_output .= '--' . "\n"; + } else { + $html_output .= '' . "\n"; + + $html_output .= '' . "\n"; + $html_output .= '' . "\n"; + } + return $html_output; +} + +/** + * The null column + * + * @param array $column description of column in given table + * @param string $column_name_appendix the name atttibute + * @param array $real_null_value is column value null or not null + * @param integer $tabindex tab index + * @param integer $tabindex_for_null +6000 + * @param integer $idindex id index + * @param array $vkey [multi_edit]['row_id'] + * @param array $foreigners keys into foreign fields + * @param array $foreignData data about the foreign keys + * + * @return string an html snippet + */ +function PMA_getNullColumn($column, $column_name_appendix, $real_null_value, + $tabindex, $tabindex_for_null, $idindex, $vkey, $foreigners, $foreignData +) { + if ($column['Null'] != 'YES') { + return "\n"; + } + $html_output = ''; + $html_output .= '' . "\n"; + $html_output .= ''; + + // nullify_code is needed by the js nullify() function + $nullify_code = PMA_getNullifyCodeForNullColumn( + $column, $foreigners, $foreignData + ); + // to be able to generate calls to nullify() in jQuery + $html_output .= ''; + $html_output .= ''; + $html_output .= ''; + $html_output .= '' . "\n"; + + return $html_output; +} + +/** + * Retrieve the nullify code for the null column + * + * @param array $column description of column in given table + * @param array $foreigners keys into foreign fields + * @param array $foreignData data about the foreign keys + * + * @return integer $nullify_code + */ +function PMA_getNullifyCodeForNullColumn($column, $foreigners, $foreignData) +{ + if (strstr($column['True_Type'], 'enum')) { + if (strlen($column['Type']) > 20) { + $nullify_code = '1'; + } else { + $nullify_code = '2'; + } + } elseif (strstr($column['True_Type'], 'set')) { + $nullify_code = '3'; + } elseif ($foreigners + && isset($foreigners[$column['Field']]) + && $foreignData['foreign_link'] == false + ) { + // foreign key in a drop-down + $nullify_code = '4'; + } elseif ($foreigners + && isset($foreigners[$column['Field']]) + && $foreignData['foreign_link'] == true + ) { + // foreign key with a browsing icon + $nullify_code = '6'; + } else { + $nullify_code = '5'; + } + return $nullify_code; +} + +/** + * Get the HTML elements for value column in insert form + * (here, "column" is used in the sense of HTML column in HTML table) + * + * @param array $column description of column in given table + * @param string $backup_field hidden input field + * @param string $column_name_appendix the name atttibute + * @param string $unnullify_trigger validation string + * @param integer $tabindex tab index + * @param integer $tabindex_for_value offset for the values tabindex + * @param integer $idindex id index + * @param array $data description of the column field + * @param array $special_chars special characters + * @param array $foreignData data about the foreign keys + * @param boolean $odd_row whether row is odd + * @param array $paramTableDbArray array containing $table and $db + * @param array $rownumber the row number + * @param array $titles An HTML IMG tag for a particular icon from + * a theme, which may be an actual file or + * an icon from a sprite + * @param array $text_dir text direction + * @param string $special_chars_encoded replaced char if the string starts + * with a \r\n pair (0x0d0a) add an extra \n + * @param string $vkey [multi_edit]['row_id'] + * @param boolean $is_upload is upload or not + * @param integer $biggest_max_file_size 0 intger + * @param string $default_char_editing default char editing mode which is stroe + * in the config.inc.php script + * @param array $no_support_types list of datatypes that are not (yet) + * handled by PMA + * @param array $gis_data_types list of GIS data types + * @param array $extracted_columnspec associative array containing type, + * spec_in_brackets and possibly + * enum_set_values (another array) + * + * @return string an html snippet + */ +function PMA_getValueColumn($column, $backup_field, $column_name_appendix, + $unnullify_trigger, $tabindex, $tabindex_for_value, $idindex, $data, + $special_chars, $foreignData, $odd_row, $paramTableDbArray, $rownumber, + $titles, $text_dir, $special_chars_encoded, $vkey, + $is_upload, $biggest_max_file_size, + $default_char_editing, $no_support_types, $gis_data_types, $extracted_columnspec +) { + $html_output = ''; + + if ($foreignData['foreign_link'] == true) { + $html_output .= PMA_getForeignLink( + $column, $backup_field, $column_name_appendix, + $unnullify_trigger, $tabindex, $tabindex_for_value, $idindex, $data, + $paramTableDbArray, $rownumber, $titles + ); + + } elseif (is_array($foreignData['disp_row'])) { + $html_output .= PMA_dispRowForeignData( + $backup_field, $column_name_appendix, + $unnullify_trigger, $tabindex, $tabindex_for_value, + $idindex, $data, $foreignData + ); + + } elseif ($GLOBALS['cfg']['LongtextDoubleTextarea'] + && strstr($column['pma_type'], 'longtext') + ) { + $html_output = ' '; + $html_output .= ''; + $html_output .= '' + . ''; + $html_output .= PMA_getTextarea( + $column, $backup_field, $column_name_appendix, $unnullify_trigger, + $tabindex, $tabindex_for_value, $idindex, $text_dir, + $special_chars_encoded + ); + + } elseif (strstr($column['pma_type'], 'text')) { + + $html_output .= PMA_getTextarea( + $column, $backup_field, $column_name_appendix, $unnullify_trigger, + $tabindex, $tabindex_for_value, $idindex, $text_dir, + $special_chars_encoded + ); + $html_output .= "\n"; + if (strlen($special_chars) > 32000) { + $html_output .= "\n"; + $html_output .= '' . __( + 'Because of its length,
    this column might not be editable' + ); + } + + } elseif ($column['pma_type'] == 'enum') { + $html_output .= PMA_getPmaTypeEnum( + $column, $backup_field, $column_name_appendix, $extracted_columnspec, + $unnullify_trigger, $tabindex, $tabindex_for_value, $idindex, $data + ); + + } elseif ($column['pma_type'] == 'set') { + $html_output .= PMA_getPmaTypeSet( + $column, $extracted_columnspec, $backup_field, + $column_name_appendix, $unnullify_trigger, $tabindex, + $tabindex_for_value, $idindex, $data + ); + + } elseif ($column['is_binary'] || $column['is_blob']) { + $html_output .= PMA_getBinaryAndBlobColumn( + $column, $data, $special_chars, $biggest_max_file_size, + $backup_field, $column_name_appendix, $unnullify_trigger, $tabindex, + $tabindex_for_value, $idindex, $text_dir, $special_chars_encoded, + $vkey, $is_upload + ); + + } elseif (! in_array($column['pma_type'], $no_support_types)) { + $html_output .= PMA_getValueColumnForOtherDatatypes( + $column, $default_char_editing, $backup_field, + $column_name_appendix, $unnullify_trigger, $tabindex, $special_chars, + $tabindex_for_value, $idindex, $text_dir, $special_chars_encoded, + $data, $extracted_columnspec + ); + } + + if (in_array($column['pma_type'], $gis_data_types)) { + $html_output .= PMA_getHTMLforGisDataTypes(); + } + + return $html_output; +} + +/** + * Get HTML for foreign link in insert form + * + * @param array $column description of column in given table + * @param string $backup_field hidden input field + * @param string $column_name_appendix the name atttibute + * @param string $unnullify_trigger validation string + * @param integer $tabindex tab index + * @param integer $tabindex_for_value offset for the values tabindex + * @param integer $idindex id index + * @param array $data data to edit + * @param array $paramTableDbArray array containing $table and $db + * @param array $rownumber the row number + * @param array $titles An HTML IMG tag for a particular icon from + * a theme, which may be an actual file or + * an icon from a sprite + * + * @return string an html snippet + */ +function PMA_getForeignLink($column, $backup_field, $column_name_appendix, + $unnullify_trigger, $tabindex, $tabindex_for_value, $idindex, $data, + $paramTableDbArray, $rownumber, $titles +) { + list($table, $db) = $paramTableDbArray; + $html_output = ''; + $html_output .= $backup_field . "\n"; + + $html_output .= ''; + + $html_output .= ''; + + $html_output .= '' + . str_replace("'", "\'", $titles['Browse']) . ''; + return $html_output; +} + +/** + * Get HTML to display foreign data + * + * @param string $backup_field hidden input field + * @param string $column_name_appendix the name atttibute + * @param string $unnullify_trigger validation string + * @param integer $tabindex tab index + * @param integer $tabindex_for_value offset for the values tabindex + * @param integer $idindex id index + * @param array $data data to edit + * @param array $foreignData data about the foreign keys + * + * @return string an html snippet + */ +function PMA_dispRowForeignData($backup_field, $column_name_appendix, + $unnullify_trigger, $tabindex, $tabindex_for_value, $idindex, $data, + $foreignData +) { + $html_output = ''; + $html_output .= $backup_field . "\n"; + $html_output .= ''; + + $html_output .= ''; + + return $html_output; +} + +/** + * Get HTML textarea for insert form + * + * @param array $column column information + * @param string $backup_field hidden input field + * @param string $column_name_appendix the name atttibute + * @param string $unnullify_trigger validation string + * @param integer $tabindex tab index + * @param integer $tabindex_for_value offset for the values tabindex + * @param integer $idindex id index + * @param array $text_dir text direction + * @param array $special_chars_encoded replaced char if the string starts + * with a \r\n pair (0x0d0a) add an extra \n + * + * @return string an html snippet + */ +function PMA_getTextarea($column, $backup_field, $column_name_appendix, + $unnullify_trigger, + $tabindex, $tabindex_for_value, $idindex, $text_dir, $special_chars_encoded +) { + $the_class = ''; + $textAreaRows = $GLOBALS['cfg']['TextareaRows']; + $textareaCols = $GLOBALS['cfg']['TextareaCols']; + + if ($column['is_char']) { + /** + * @todo clarify the meaning of the "textfield" class and explain + * why character columns have the "char" class instead + */ + $the_class = 'char'; + $textAreaRows = $GLOBALS['cfg']['CharTextareaRows']; + $textareaCols = $GLOBALS['cfg']['CharTextareaCols']; + } elseif ($GLOBALS['cfg']['LongtextDoubleTextarea'] + && strstr($column['pma_type'], 'longtext') + ) { + $textAreaRows = $GLOBALS['cfg']['TextareaRows'] * 2; + $textareaCols = $GLOBALS['cfg']['TextareaCols'] * 2; + } + $html_output = $backup_field . "\n" + . ''; + + return $html_output; +} + +/** + * Get HTML for enum type + * + * @param type $column description of column in given table + * @param type $backup_field hidden input field + * @param type $column_name_appendix the name atttibute + * @param type $extracted_columnspec associative array containing type, + * spec_in_brackets and possibly + * enum_set_values (another array) + * @param type $unnullify_trigger validation string + * @param type $tabindex tab index + * @param type $tabindex_for_value offset for the values tabindex + * @param type $idindex id index + * @param type $data data to edit + * + * @return string an html snippet + */ +function PMA_getPmaTypeEnum($column, $backup_field, $column_name_appendix, + $extracted_columnspec, $unnullify_trigger, $tabindex, $tabindex_for_value, + $idindex, $data +) { + $html_output = ''; + if (! isset($column['values'])) { + $column['values'] = PMA_getColumnEnumValues( + $column, $extracted_columnspec + ); + } + $column_enum_values = $column['values']; + $html_output .= ''; + $html_output .= ''; + $html_output .= "\n" . ' ' . $backup_field . "\n"; + if (strlen($column['Type']) > 20) { + $html_output .= PMA_getDropDownDependingOnLength( + $column, $column_name_appendix, $unnullify_trigger, + $tabindex, $tabindex_for_value, $idindex, $data, $column_enum_values + ); + } else { + $html_output .= PMA_getRadioButtonDependingOnLength( + $column_name_appendix, $unnullify_trigger, + $tabindex, $column, $tabindex_for_value, + $idindex, $data, $column_enum_values + ); + } + return $html_output; +} + +/** + * Get column values + * + * @param array $column description of column in given table + * @param array $extracted_columnspec associative array containing type, + * spec_in_brackets and possibly enum_set_values + * (another array) + * + * @return array column values as an associative array + */ +function PMA_getColumnEnumValues($column, $extracted_columnspec) +{ + $column['values'] = array(); + foreach ($extracted_columnspec['enum_set_values'] as $val) { + $column['values'][] = array( + 'plain' => $val, + 'html' => htmlspecialchars($val), + ); + } + return $column['values']; +} + +/** + * Get HTML drop down for more than 20 string length + * + * @param array $column description of column in given table + * @param string $column_name_appendix the name atttibute + * @param string $unnullify_trigger validation string + * @param integer $tabindex tab index + * @param integer $tabindex_for_value offset for the values tabindex + * @param integer $idindex id index + * @param array $data data to edit + * @param array $column_enum_values $column['values'] + * + * @return string an html snippet + */ +function PMA_getDropDownDependingOnLength( + $column, $column_name_appendix, $unnullify_trigger, + $tabindex, $tabindex_for_value, $idindex, $data, $column_enum_values +) { + $html_output = ''; + return $html_output; +} + +/** + * Get HTML radio button for less than 20 string length + * + * @param string $column_name_appendix the name atttibute + * @param string $unnullify_trigger validation string + * @param integer $tabindex tab index + * @param array $column description of column in given table + * @param integer $tabindex_for_value offset for the values tabindex + * @param integer $idindex id index + * @param array $data data to edit + * @param array $column_enum_values $column['values'] + * + * @return string an html snippet + */ +function PMA_getRadioButtonDependingOnLength( + $column_name_appendix, $unnullify_trigger, + $tabindex, $column, $tabindex_for_value, $idindex, $data, $column_enum_values +) { + $j = 0; + $html_output = ''; + foreach ($column_enum_values as $enum_value) { + $html_output .= ' ' + . ''; + $html_output .= '' . "\n"; + $j++; + } + return $html_output; +} + +/** + * Get the HTML for 'set' pma type + * + * @param array $column description of column in given table + * @param array $extracted_columnspec associative array containing type, + * spec_in_brackets and possibly + * enum_set_values (another array) + * @param string $backup_field hidden input field + * @param string $column_name_appendix the name atttibute + * @param string $unnullify_trigger validation string + * @param integer $tabindex tab index + * @param integer $tabindex_for_value offset for the values tabindex + * @param integer $idindex id index + * @param array $data description of the column field + * + * @return string an html snippet + */ +function PMA_getPmaTypeSet( + $column, $extracted_columnspec, $backup_field, + $column_name_appendix, $unnullify_trigger, $tabindex, + $tabindex_for_value, $idindex, $data +) { + list($column_set_values, $select_size) = PMA_getColumnSetValueAndSelectSize( + $column, $extracted_columnspec + ); + $vset = array_flip(explode(',', $data)); + $html_output = $backup_field . "\n"; + $html_output .= ''; + $html_output .= ''; + return $html_output; +} + +/** + * Retrieve column 'set' value and select size + * + * @param array $column description of column in given table + * @param array $extracted_columnspec associative array containing type, + * spec_in_brackets and possibly enum_set_values + * (another array) + * + * @return array $column['values'], $column['select_size'] + */ +function PMA_getColumnSetValueAndSelectSize($column, $extracted_columnspec) +{ + if (! isset($column['values'])) { + $column['values'] = array(); + foreach ($extracted_columnspec['enum_set_values'] as $val) { + $column['values'][] = array( + 'plain' => $val, + 'html' => htmlspecialchars($val), + ); + } + $column['select_size'] = min(4, count($column['values'])); + } + return array($column['values'], $column['select_size']); +} + +/** + * Get HTML for binary and blob column + * + * @param array $column description of column in given table + * @param array $data data to edit + * @param array $special_chars special characters + * @param integer $biggest_max_file_size biggest max file size for uploading + * @param string $backup_field hidden input field + * @param string $column_name_appendix the name atttibute + * @param string $unnullify_trigger validation string + * @param integer $tabindex tab index + * @param integer $tabindex_for_value offset for the values tabindex + * @param integer $idindex id index + * @param string $text_dir text direction + * @param string $special_chars_encoded replaced char if the string starts + * with a \r\n pair (0x0d0a) add an extra \n + * @param string $vkey [multi_edit]['row_id'] + * @param boolean $is_upload is upload or not + * + * @return string an html snippet + */ +function PMA_getBinaryAndBlobColumn( + $column, $data, $special_chars, $biggest_max_file_size, + $backup_field, $column_name_appendix, $unnullify_trigger, $tabindex, + $tabindex_for_value, $idindex, $text_dir, $special_chars_encoded, + $vkey, $is_upload +) { + $html_output = ''; + if (($GLOBALS['cfg']['ProtectBinary'] && $column['is_blob']) + || ($GLOBALS['cfg']['ProtectBinary'] == 'all' && $column['is_binary']) + || ($GLOBALS['cfg']['ProtectBinary'] == 'noblob' && !$column['is_blob']) + ) { + $html_output .= __('Binary - do not edit'); + if (isset($data)) { + $data_size = PMA_Util::formatByteDown( + strlen(stripslashes($data)), 3, 1 + ); + $html_output .= ' ('. $data_size[0] . ' ' . $data_size[1] . ')'; + unset($data_size); + } + $html_output .= '' + . ''; + } elseif ($column['is_blob'] + || ($column['len'] > $GLOBALS['cfg']['LimitChars']) + ) { + $html_output .= "\n" . PMA_getTextarea( + $column, $backup_field, $column_name_appendix, $unnullify_trigger, + $tabindex, $tabindex_for_value, $idindex, $text_dir, + $special_chars_encoded + ); + } else { + // field size should be at least 4 and max $GLOBALS['cfg']['LimitChars'] + $fieldsize = min(max($column['len'], 4), $GLOBALS['cfg']['LimitChars']); + $html_output .= "\n" . $backup_field . "\n" . PMA_getHTMLinput( + $column, $column_name_appendix, $special_chars, $fieldsize, + $unnullify_trigger, $tabindex, $tabindex_for_value, $idindex + ); + } + + if ($is_upload && $column['is_blob']) { + $html_output .= '
    ' + . ' '; + list($html_out, $biggest_max_file_size) = PMA_getMaxUploadSize( + $column, $biggest_max_file_size + ); + $html_output .= $html_out; + } + + if (!empty($GLOBALS['cfg']['UploadDir'])) { + $html_output .= PMA_getSelectOptionForUpload($vkey, $column); + } + + return $html_output; +} + +/** + * Get HTML input type + * + * @param array $column description of column in given table + * @param string $column_name_appendix the name attribute + * @param array $special_chars special characters + * @param integer $fieldsize html field size + * @param string $unnullify_trigger validation string + * @param integer $tabindex tab index + * @param integer $tabindex_for_value offset for the values tabindex + * @param integer $idindex id index + * + * @return string an html snippet + */ +function PMA_getHTMLinput($column, $column_name_appendix, $special_chars, + $fieldsize, $unnullify_trigger, $tabindex, $tabindex_for_value, $idindex +) { + static $min_max_data = array( + 'unsigned' => array( + 'tinyint' => array('0', '255'), + 'smallint' => array('0', '65535'), + 'mediumint' => array('0', '16777215'), + 'int' => array('0', '4294967295'), + 'bigint' => array('0', '18446744073709551615') + ), + 'signed' => array( + 'tinyint' => array('-128', '127'), + 'smallint' => array('-32768', '32767'), + 'mediumint' => array('-8388608', '8388607'), + 'int' => array('-2147483648', '2147483647'), + 'bigint' => array('-9223372036854775808', '9223372036854775807') + ) + ); + + $input_type = 'text'; + // do not use the 'date' or 'time' types here; they have no effect on some + // browsers and create side effects (see bug #4218) + + $the_class = 'textfield'; + // verify True_Type which does not contain the parentheses and length + if ($column['True_Type'] === 'date') { + $the_class .= ' datefield'; + } elseif ($column['True_Type'] === 'datetime' + || $column['True_Type'] === 'timestamp' + ) { + $the_class .= ' datetimefield'; + } + $input_min_max = false; + if (in_array( + $column['True_Type'], + array('tinyint', 'smallint', 'mediumint', 'int', 'bigint') + )) { + $input_type = 'number'; + $is_unsigned = substr($column['pma_type'], -9) === ' unsigned'; + $min_max_values + = $min_max_data[$is_unsigned ? 'unsigned' : 'signed'] + [$column['True_Type']]; + $input_min_max = 'min="' . $min_max_values[0] . '" ' + . 'max="' . $min_max_values[1] . '" '; + } + return ''; +} + +/** + * Get HTML select option for upload + * + * @param string $vkey [multi_edit]['row_id'] + * @param array $column description of column in given table + * + * @return string|void an html snippet + */ +function PMA_getSelectOptionForUpload($vkey, $column) +{ + $files = PMA_getFileSelectOptions( + PMA_Util::userDir($GLOBALS['cfg']['UploadDir']) + ); + + if ($files === false) { + return '' . __('Error') . '
    ' . "\n" + . __('The directory you set for upload work cannot be reached.') . "\n"; + } elseif (!empty($files)) { + return "
    \n" + . '' . __('Or') . '' . ' ' + . __('web server upload directory:') . '
    ' . "\n" + . '' . "\n"; + } +} + +/** + * Retrieve the maximum upload file size + * + * @param array $column description of column in given table + * @param integer $biggest_max_file_size biggest max file size for uploading + * + * @return array an html snippet and $biggest_max_file_size + */ +function PMA_getMaxUploadSize($column, $biggest_max_file_size) +{ + // find maximum upload size, based on field type + /** + * @todo with functions this is not so easy, as you can basically + * process any data with function like MD5 + */ + global $max_upload_size; + $max_field_sizes = array( + 'tinyblob' => '256', + 'blob' => '65536', + 'mediumblob' => '16777216', + 'longblob' => '4294967296' // yeah, really + ); + + $this_field_max_size = $max_upload_size; // from PHP max + if ($this_field_max_size > $max_field_sizes[$column['pma_type']]) { + $this_field_max_size = $max_field_sizes[$column['pma_type']]; + } + $html_output + = PMA_Util::getFormattedMaximumUploadSize( + $this_field_max_size + ) . "\n"; + // do not generate here the MAX_FILE_SIZE, because we should + // put only one in the form to accommodate the biggest field + if ($this_field_max_size > $biggest_max_file_size) { + $biggest_max_file_size = $this_field_max_size; + } + return array($html_output, $biggest_max_file_size); +} + +/** + * Get HTML for the Value column of other datatypes + * (here, "column" is used in the sense of HTML column in HTML table) + * + * @param array $column description of column in given table + * @param string $default_char_editing default char editing mode which is stroe + * in the config.inc.php script + * @param string $backup_field hidden input field + * @param string $column_name_appendix the name atttibute + * @param string $unnullify_trigger validation string + * @param integer $tabindex tab index + * @param array $special_chars special characters + * @param integer $tabindex_for_value offset for the values tabindex + * @param integer $idindex id index + * @param string $text_dir text direction + * @param array $special_chars_encoded replaced char if the string starts + * with a \r\n pair (0x0d0a) add an extra \n + * @param strign $data data to edit + * @param array $extracted_columnspec associative array containing type, + * spec_in_brackets and possibly + * enum_set_values (another array) + * + * @return string an html snippet + */ +function PMA_getValueColumnForOtherDatatypes($column, $default_char_editing, + $backup_field, + $column_name_appendix, $unnullify_trigger, $tabindex, $special_chars, + $tabindex_for_value, $idindex, $text_dir, $special_chars_encoded, $data, + $extracted_columnspec +) { + $fieldsize = PMA_getColumnSize($column, $extracted_columnspec); + $html_output = $backup_field . "\n"; + if ($column['is_char'] + && ($GLOBALS['cfg']['CharEditing'] == 'textarea' + || strpos($data, "\n") !== false) + ) { + $html_output .= "\n"; + $GLOBALS['cfg']['CharEditing'] = $default_char_editing; + $html_output .= PMA_getTextarea( + $column, $backup_field, $column_name_appendix, $unnullify_trigger, + $tabindex, $tabindex_for_value, $idindex, $text_dir, + $special_chars_encoded + ); + } else { + $html_output .= PMA_getHTMLinput( + $column, $column_name_appendix, $special_chars, + $fieldsize, $unnullify_trigger, $tabindex, $tabindex_for_value, $idindex + ); + + if ($column['Extra'] == 'auto_increment') { + $html_output .= ''; + } + if (substr($column['pma_type'], 0, 9) == 'timestamp') { + $html_output .= ''; + } + if (substr($column['pma_type'], 0, 8) == 'datetime') { + $html_output .= ''; + } + if ($column['True_Type'] == 'bit') { + $html_output .= ''; + } + if ($column['pma_type'] == 'date' + || $column['pma_type'] == 'datetime' + || substr($column['pma_type'], 0, 9) == 'timestamp' + ) { + // the _3 suffix points to the date field + // the _2 suffix points to the corresponding NULL checkbox + // in dateFormat, 'yy' means the year with 4 digits + } + } + return $html_output; +} + +/** + * Get the field size + * + * @param array $column description of column in given table + * @param array $extracted_columnspec associative array containing type, + * spec_in_brackets and possibly enum_set_values + * (another array) + * + * @return integer field size + */ +function PMA_getColumnSize($column, $extracted_columnspec) +{ + if ($column['is_char']) { + $fieldsize = $extracted_columnspec['spec_in_brackets']; + if ($fieldsize > $GLOBALS['cfg']['MaxSizeForInputField']) { + /** + * This case happens for CHAR or VARCHAR columns which have + * a size larger than the maximum size for input field. + */ + $GLOBALS['cfg']['CharEditing'] = 'textarea'; + } + } else { + /** + * This case happens for example for INT or DATE columns; + * in these situations, the value returned in $column['len'] + * seems appropriate. + */ + $fieldsize = $column['len']; + } + return min( + max($fieldsize, $GLOBALS['cfg']['MinSizeForInputField']), + $GLOBALS['cfg']['MaxSizeForInputField'] + ); +} + +/** + * Get HTML for gis data types + * + * @return string an html snippet + */ +function PMA_getHTMLforGisDataTypes() +{ + $edit_str = PMA_Util::getIcon('b_edit.png', __('Edit/Insert')); + return '' + . PMA_Util::linkOrButton( + '#', $edit_str, array(), false, false, '_blank' + ) + . ''; +} + +/** + * get html for continue insertion form + * + * @param string $table name of the table + * @param string $db name of the database + * @param array $where_clause_array array of where clauses + * @param string $err_url error url + * + * @return string an html snippet + */ +function PMA_getContinueInsertionForm($table, $db, $where_clause_array, $err_url) +{ + $html_output = '
    ' + . PMA_URL_getHiddenInputs($db, $table) + . '' + . '' + . ''; + + if (isset($_REQUEST['where_clause'])) { + foreach ($where_clause_array as $key_id => $where_clause) { + + $html_output .= ''. "\n"; + } + } + $tmp = '' . "\n"; + $html_output .= "\n" . sprintf(__('Continue insertion with %s rows'), $tmp); + unset($tmp); + $html_output .= '
    ' . "\n"; + return $html_output; +} + +/** + * Get action panel + * + * @param array $where_clause where clause + * @param string $after_insert insert mode, e.g. new_insert, same_insert + * @param integer $tabindex tab index + * @param integer $tabindex_for_value offset for the values tabindex + * @param boolean $found_unique_key boolean variable for unique key + * + * @return string an html snippet + */ +function PMA_getActionsPanel($where_clause, $after_insert, $tabindex, + $tabindex_for_value, $found_unique_key +) { + $html_output = '
    ' + . '' + . '' + . '' + . '' + . '' + . ''; + $html_output .='' + . PMA_getSumbitAndResetButtonForActionsPanel($tabindex, $tabindex_for_value) + . '' + . '
    ' + . PMA_getSubmitTypeDropDown($where_clause, $tabindex, $tabindex_for_value) + . "\n"; + + $html_output .= '' + . '   ' + . __('and then') . '   ' + . '' + . PMA_getAfterInsertDropDown( + $where_clause, $after_insert, $found_unique_key + ) + . '
    ' + . '
    '; + return $html_output; +} + +/** + * Get a HTML drop down for submit types + * + * @param array $where_clause where clause + * @param integer $tabindex tab index + * @param integer $tabindex_for_value offset for the values tabindex + * + * @return string an html snippet + */ +function PMA_getSubmitTypeDropDown($where_clause, $tabindex, $tabindex_for_value) +{ + $html_output = ''; + return $html_output; +} + +/** + * Get HTML drop down for after insert + * + * @param array $where_clause where clause + * @param string $after_insert insert mode, e.g. new_insert, same_insert + * @param boolean $found_unique_key boolean variable for unique key + * + * @return string an html snippet + */ +function PMA_getAfterInsertDropDown($where_clause, $after_insert, $found_unique_key) +{ + $html_output = ''; + return $html_output; + +} + +/** + * get Submit button and Reset button for action panel + * + * @param integer $tabindex tab index + * @param integer $tabindex_for_value offset for the values tabindex + * + * @return string an html snippet + */ +function PMA_getSumbitAndResetButtonForActionsPanel($tabindex, $tabindex_for_value) +{ + return '' + . PMA_Util::showHint( + __( + 'Use TAB key to move from value to value,' + . ' or CTRL+arrows to move anywhere' + ) + ) + . '' + . '' + . '' + . '' + . ''; +} + +/** + * Get table head and table foot for insert row table + * + * @param array $url_params url parameters + * + * @return string an html snippet + */ +function PMA_getHeadAndFootOfInsertRowTable($url_params) +{ + $html_output = '' + . '' + . '' + . ''; + + if ($GLOBALS['cfg']['ShowFieldTypesInDataEditView']) { + $html_output .= PMA_showColumnTypesInDataEditView($url_params, true); + } + if ($GLOBALS['cfg']['ShowFunctionFields']) { + $html_output .= PMA_showFunctionFieldsInEditMode($url_params, true); + } + + $html_output .= '' + . '' + . '' + . '' + . ' ' + . '' + . '' + . '' + . ''; + return $html_output; +} + +/** + * Prepares the field value and retrieve special chars, backup field and data array + * + * @param array $current_row a row of the table + * @param array $column description of column in given table + * @param array $extracted_columnspec associative array containing type, + * spec_in_brackets and possibly + * enum_set_values (another array) + * @param boolean $real_null_value whether column value null or not null + * @param array $gis_data_types list of GIS data types + * @param string $column_name_appendix string to append to column name in input + * + * @return array $real_null_value, $data, $special_chars, $backup_field, + * $special_chars_encoded + */ +function PMA_getSpecialCharsAndBackupFieldForExistingRow( + $current_row, $column, $extracted_columnspec, + $real_null_value, $gis_data_types, $column_name_appendix +) { + $special_chars_encoded = ''; + $data = null; + // (we are editing) + if (is_null($current_row[$column['Field']])) { + $real_null_value = true; + $current_row[$column['Field']] = ''; + $special_chars = ''; + $data = $current_row[$column['Field']]; + } elseif ($column['True_Type'] == 'bit') { + $special_chars = PMA_Util::printableBitValue( + $current_row[$column['Field']], $extracted_columnspec['spec_in_brackets'] + ); + } elseif ((substr($column['True_Type'], 0, 9) == 'timestamp' + || $column['True_Type'] == 'datetime' + || $column['True_Type'] == 'time') + && (strpos ($current_row[$column['Field']],"." ) === TRUE) + ) { + $current_row[$column['Field']] = PMA_Util::addMicroseconds( + $current_row[$column['Field']] + ); + $special_chars = htmlspecialchars($current_row[$column['Field']]); + } elseif (in_array($column['True_Type'], $gis_data_types)) { + // Convert gis data to Well Know Text format + $current_row[$column['Field']] = PMA_Util::asWKT( + $current_row[$column['Field']], true + ); + $special_chars = htmlspecialchars($current_row[$column['Field']]); + } else { + // special binary "characters" + if ($column['is_binary'] + || ($column['is_blob'] && ! $GLOBALS['cfg']['ProtectBinary']) + ) { + if ($_SESSION['tmpval']['display_binary_as_hex'] + && $GLOBALS['cfg']['ShowFunctionFields'] + ) { + $current_row[$column['Field']] = bin2hex( + $current_row[$column['Field']] + ); + $column['display_binary_as_hex'] = true; + } else { + $current_row[$column['Field']] + = PMA_Util::replaceBinaryContents( + $current_row[$column['Field']] + ); + } + } // end if + $special_chars = htmlspecialchars($current_row[$column['Field']]); + + //We need to duplicate the first \n or otherwise we will lose + //the first newline entered in a VARCHAR or TEXT column + $special_chars_encoded + = PMA_Util::duplicateFirstNewline($special_chars); + + $data = $current_row[$column['Field']]; + } // end if... else... + + //when copying row, it is useful to empty auto-increment column + // to prevent duplicate key error + if (isset($_REQUEST['default_action']) + && $_REQUEST['default_action'] === 'insert' + ) { + if ($column['Key'] === 'PRI' + && strpos($column['Extra'], 'auto_increment') !== false + ) { + $data = $special_chars_encoded = $special_chars = null; + } + } + // If a timestamp field value is not included in an update + // statement MySQL auto-update it to the current timestamp; + // however, things have changed since MySQL 4.1, so + // it's better to set a fields_prev in this situation + $backup_field = ''; + + return array( + $real_null_value, + $special_chars_encoded, + $special_chars, + $data, + $backup_field + ); +} + +/** + * display default values + * + * @param type $column description of column in given table + * @param boolean $real_null_value whether column value null or not null + * + * @return array $real_null_value, $data, $special_chars, + * $backup_field, $special_chars_encoded + */ +function PMA_getSpecialCharsAndBackupFieldForInsertingMode( + $column, $real_null_value +) { + if (! isset($column['Default'])) { + $column['Default'] = ''; + $real_null_value = true; + $data = ''; + } else { + $data = $column['Default']; + } + + if ($column['True_Type'] == 'bit') { + $special_chars = PMA_Util::convertBitDefaultValue($column['Default']); + } elseif ((substr($column['True_Type'], 0, 9) == 'timestamp' + || $column['True_Type'] == 'datetime' + || $column['True_Type'] == 'time') + && strpos($column['Default'], '.') === true + ) { + $special_chars = PMA_Util::addMicroseconds($column['Default']); + } else { + $special_chars = htmlspecialchars($column['Default']); + } + $backup_field = ''; + $special_chars_encoded = PMA_Util::duplicateFirstNewline($special_chars); + // this will select the UNHEX function while inserting + if (($column['is_binary'] + || ($column['is_blob'] && ! $GLOBALS['cfg']['ProtectBinary'])) + && (isset($_SESSION['tmpval']['display_binary_as_hex']) + && $_SESSION['tmpval']['display_binary_as_hex']) + && $GLOBALS['cfg']['ShowFunctionFields'] + ) { + $column['display_binary_as_hex'] = true; + } + return array( + $real_null_value, $data, $special_chars, + $backup_field, $special_chars_encoded + ); +} + +/** + * Prepares the update/insert of a row + * + * @return array $loop_array, $using_key, $is_insert, $is_insertignore + */ +function PMA_getParamsForUpdateOrInsert() +{ + if (isset($_REQUEST['where_clause'])) { + // we were editing something => use the WHERE clause + $loop_array = is_array($_REQUEST['where_clause']) + ? $_REQUEST['where_clause'] + : array($_REQUEST['where_clause']); + $using_key = true; + $is_insert = $_REQUEST['submit_type'] == 'insert' + || $_REQUEST['submit_type'] == 'showinsert' + || $_REQUEST['submit_type'] == 'insertignore'; + } else { + // new row => use indexes + $loop_array = array(); + foreach ($_REQUEST['fields']['multi_edit'] as $key => $dummy) { + $loop_array[] = $key; + } + $using_key = false; + $is_insert = true; + } + $is_insertignore = $_REQUEST['submit_type'] == 'insertignore'; + return array($loop_array, $using_key, $is_insert, $is_insertignore); +} + +/** + * Check wether insert row mode and if so include tbl_changen script and set + * global variables. + * + * @return void + */ +function PMA_isInsertRow() +{ + if (isset($_REQUEST['insert_rows']) + && is_numeric($_REQUEST['insert_rows']) + && $_REQUEST['insert_rows'] != $GLOBALS['cfg']['InsertRows'] + ) { + $GLOBALS['cfg']['InsertRows'] = $_REQUEST['insert_rows']; + $response = PMA_Response::getInstance(); + $header = $response->getHeader(); + $scripts = $header->getScripts(); + $scripts->addFile('tbl_change.js'); + if (!defined('TESTSUITE')) { + include 'tbl_change.php'; + exit; + } + } +} + +/** + * set $_SESSION for edit_next + * + * @param string $one_where_clause one where clause from where clauses array + * + * @return void + */ +function PMA_setSessionForEditNext($one_where_clause) +{ + $local_query = 'SELECT * FROM ' . PMA_Util::backquote($GLOBALS['db']) + . '.' . PMA_Util::backquote($GLOBALS['table']) . ' WHERE ' + . str_replace('` =', '` >', $one_where_clause) . ' LIMIT 1;'; + + $res = $GLOBALS['dbi']->query($local_query); + $row = $GLOBALS['dbi']->fetchRow($res); + $meta = $GLOBALS['dbi']->getFieldsMeta($res); + // must find a unique condition based on unique key, + // not a combination of all fields + list($unique_condition, $clause_is_unique) + = PMA_Util::getUniqueCondition( + $res, count($meta), $meta, $row, true + ); + if (! empty($unique_condition)) { + $_SESSION['edit_next'] = $unique_condition; + } + unset($unique_condition, $clause_is_unique); +} + +/** + * set $goto_include variable for different cases and retrieve like, + * if $GLOBALS['goto'] empty, if $goto_include previously not defined + * and new_insert, same_insert, edit_next + * + * @param string $goto_include store some script for include, otherwise it is + * boolean false + * + * @return string $goto_include + */ +function PMA_getGotoInclude($goto_include) +{ + $valid_options = array('new_insert', 'same_insert', 'edit_next'); + if (isset($_REQUEST['after_insert']) + && in_array($_REQUEST['after_insert'], $valid_options) + ) { + $goto_include = 'tbl_change.php'; + } elseif (! empty($GLOBALS['goto'])) { + if (! preg_match('@^[a-z_]+\.php$@', $GLOBALS['goto'])) { + // this should NOT happen + //$GLOBALS['goto'] = false; + $goto_include = false; + } else { + $goto_include = $GLOBALS['goto']; + } + if ($GLOBALS['goto'] == 'db_sql.php' && strlen($GLOBALS['table'])) { + $GLOBALS['table'] = ''; + } + } + if (! $goto_include) { + if (! strlen($GLOBALS['table'])) { + $goto_include = 'db_sql.php'; + } else { + $goto_include = 'tbl_sql.php'; + } + } + return $goto_include; +} + +/** + * Defines the url to return in case of failure of the query + * + * @param array $url_params url parameters + * + * @return string error url for query failure + */ +function PMA_getErrorUrl($url_params) +{ + if (isset($_REQUEST['err_url'])) { + return $_REQUEST['err_url']; + } else { + return 'tbl_change.php' . PMA_URL_getCommon($url_params); + } +} + +/** + * Builds the sql query + * + * @param boolean $is_insertignore $_REQUEST['submit_type'] == 'insertignore' + * @param array $query_fields column names array + * @param array $value_sets array of query values + * + * @return string a query + */ +function PMA_buildSqlQuery($is_insertignore, $query_fields, $value_sets) +{ + if ($is_insertignore) { + $insert_command = 'INSERT IGNORE '; + } else { + $insert_command = 'INSERT '; + } + $query[] = $insert_command . 'INTO ' + . PMA_Util::backquote($GLOBALS['db']) . '.' + . PMA_Util::backquote($GLOBALS['table']) + . ' (' . implode(', ', $query_fields) . ') VALUES (' + . implode('), (', $value_sets) . ')'; + unset($insert_command, $query_fields); + return $query; +} + +/** + * Executes the sql query and get the result, then move back to the calling page + * + * @param array $url_params url parameters array + * @param array $query built query from PMA_buildSqlQuery() + * + * @return array $url_params, $total_affected_rows, $last_messages + * $warning_messages, $error_messages, $return_to_sql_query + */ +function PMA_executeSqlQuery($url_params, $query) +{ + $return_to_sql_query = ''; + if (! empty($GLOBALS['sql_query'])) { + $url_params['sql_query'] = $GLOBALS['sql_query']; + $return_to_sql_query = $GLOBALS['sql_query']; + } + $GLOBALS['sql_query'] = implode('; ', $query) . ';'; + // to ensure that the query is displayed in case of + // "insert as new row" and then "insert another new row" + $GLOBALS['display_query'] = $GLOBALS['sql_query']; + + $total_affected_rows = 0; + $last_messages = array(); + $warning_messages = array(); + $error_messages = array(); + + foreach ($query as $single_query) { + if ($_REQUEST['submit_type'] == 'showinsert') { + $last_messages[] = PMA_Message::notice(__('Showing SQL query')); + continue; + } + if ($GLOBALS['cfg']['IgnoreMultiSubmitErrors']) { + $result = $GLOBALS['dbi']->tryQuery($single_query); + } else { + $result = $GLOBALS['dbi']->query($single_query); + } + if (! $result) { + $error_messages[] = PMA_Message::sanitize($GLOBALS['dbi']->getError()); + } else { + // The next line contains a real assignment, it's not a typo + if ($tmp = @$GLOBALS['dbi']->affectedRows()) { + $total_affected_rows += $tmp; + } + unset($tmp); + + $insert_id = $GLOBALS['dbi']->insertId(); + if ($insert_id != 0) { + // insert_id is id of FIRST record inserted in one insert, so if we + // inserted multiple rows, we had to increment this + + if ($total_affected_rows > 0) { + $insert_id = $insert_id + $total_affected_rows - 1; + } + $last_message = PMA_Message::notice(__('Inserted row id: %1$d')); + $last_message->addParam($insert_id); + $last_messages[] = $last_message; + } + $GLOBALS['dbi']->freeResult($result); + } + $warning_messages = PMA_getWarningMessages(); + } + return array( + $url_params, + $total_affected_rows, + $last_messages, + $warning_messages, + $error_messages, + $return_to_sql_query + ); +} + +/** + * get the warning messages array + * + * @return array $warning_essages + */ +function PMA_getWarningMessages() +{ + $warning_essages = array(); + foreach ($GLOBALS['dbi']->getWarnings() as $warning) { + $warning_essages[] = PMA_Message::sanitize( + $warning['Level'] . ': #' . $warning['Code'] . ' ' . $warning['Message'] + ); + } + return $warning_essages; +} + +/** + * Column to display from the foreign table? + * + * @param string $where_comparison string that contain relation field value + * @param string $relation_field_value relation field value + * @param array $map all Relations to foreign tables for a given + * table or optionally a given column in a table + * @param string $relation_field relation field + * + * @return string $dispval display value from the foreign table + */ +function PMA_getDisplayValueForForeignTableColumn($where_comparison, + $relation_field_value, $map, $relation_field +) { + $display_field = PMA_getDisplayField( + $map[$relation_field]['foreign_db'], + $map[$relation_field]['foreign_table'] + ); + // Field to display from the foreign table? + if (isset($display_field) && strlen($display_field)) { + $dispsql = 'SELECT ' . PMA_Util::backquote($display_field) + . ' FROM ' . PMA_Util::backquote($map[$relation_field]['foreign_db']) + . '.' . PMA_Util::backquote($map[$relation_field]['foreign_table']) + . ' WHERE ' . PMA_Util::backquote($map[$relation_field]['foreign_field']) + . $where_comparison; + $dispresult = $GLOBALS['dbi']->tryQuery( + $dispsql, null, PMA_DatabaseInterface::QUERY_STORE + ); + if ($dispresult && $GLOBALS['dbi']->numRows($dispresult) > 0) { + list($dispval) = $GLOBALS['dbi']->fetchRow($dispresult, 0); + } + @$GLOBALS['dbi']->freeResult($dispresult); + return $dispval; + } + return ''; +} + +/** + * Display option in the cell according to user choises + * + * @param array $map all Relations to foreign tables for a given + * table or optionally a given column in a table + * @param string $relation_field relation field + * @param string $where_comparison string that contain relation field value + * @param string $dispval display value from the foreign table + * @param string $relation_field_value relation field value + * + * @return string $output HTML tag + */ +function PMA_getLinkForRelationalDisplayField($map, $relation_field, + $where_comparison, $dispval, $relation_field_value +) { + if ('K' == $_SESSION['tmpval']['relational_display']) { + // user chose "relational key" in the display options, so + // the title contains the display field + $title = (! empty($dispval)) + ? ' title="' . htmlspecialchars($dispval) . '"' + : ''; + } else { + $title = ' title="' . htmlspecialchars($relation_field_value) . '"'; + } + $_url_params = array( + 'db' => $map[$relation_field]['foreign_db'], + 'table' => $map[$relation_field]['foreign_table'], + 'pos' => '0', + 'sql_query' => 'SELECT * FROM ' + . PMA_Util::backquote($map[$relation_field]['foreign_db']) + . '.' . PMA_Util::backquote($map[$relation_field]['foreign_table']) + . ' WHERE ' . PMA_Util::backquote($map[$relation_field]['foreign_field']) + . $where_comparison + ); + $output = ''; + + if ('D' == $_SESSION['tmpval']['relational_display']) { + // user chose "relational display field" in the + // display options, so show display field in the cell + $output .= (!empty($dispval)) ? htmlspecialchars($dispval) : ''; + } else { + // otherwise display data in the cell + $output .= htmlspecialchars($relation_field_value); + } + $output .= ''; + return $output; +} + +/** + * Transform edited values + * + * @param string $db db name + * @param string $table table name + * @param array $transformation mimetypes for all columns of a table + * [field_name][field_key] + * @param array $edited_values transform columns list and new values + * @param string $file file containing the transformation plugin + * @param string $column_name column name + * @param array $extra_data extra data array + * + * @return array $extra_data + */ +function PMA_transformEditedValues($db, $table, + $transformation, $edited_values, $file, $column_name, $extra_data +) { + foreach ($edited_values as $cell_index => $curr_cell_edited_values) { + if (isset($curr_cell_edited_values[$column_name])) { + $column_data = $curr_cell_edited_values[$column_name]; + + $_url_params = array( + 'db' => $db, + 'table' => $table, + 'where_clause' => $_REQUEST['where_clause'], + 'transform_key' => $column_name + ); + + $include_file = 'libraries/plugins/transformations/' . $file; + if (file_exists($include_file)) { + include_once $include_file; + + $transform_options = PMA_Transformation_getOptions( + isset($transformation['transformation_options']) + ? $transformation['transformation_options'] + : '' + ); + $transform_options['wrapper_link'] + = PMA_URL_getCommon($_url_params); + $class_name = str_replace('.class.php', '', $file); + $plugin_manager = null; + $transformation_plugin = new $class_name( + $plugin_manager + ); + } + + $extra_data['transformations'][$cell_index] + = $transformation_plugin->applyTransformation( + $column_data, + $transform_options, + '' + ); + } + } // end of loop for each transformation cell + return $extra_data; +} + +/** + * Get current value in multi edit mode + * + * @param array $multi_edit_colummns multiple edit column array + * @param array $multi_edit_columns_name multiple edit columns name array + * @param array $multi_edit_funcs multiple edit functions array + * @param array $multi_edit_salt multiple edit array with encryption salt + * @param array $gis_from_text_functions array that contains gis from text functions + * @param string $current_value current value in the column + * @param array $gis_from_wkb_functions initialy $val is $multi_edit_colummns[$key] + * @param array $func_optional_param array('RAND','UNIX_TIMESTAMP') + * @param array $func_no_param array of set of string + * @param string $key an md5 of the column name + * + * @return array $cur_value + */ +function PMA_getCurrentValueAsAnArrayForMultipleEdit($multi_edit_colummns, + $multi_edit_columns_name, $multi_edit_funcs, $multi_edit_salt, + $gis_from_text_functions, $current_value, $gis_from_wkb_functions, + $func_optional_param, $func_no_param, $key +) { + if (empty($multi_edit_funcs[$key])) { + return $current_value; + } elseif ('UUID' === $multi_edit_funcs[$key]) { + /* This way user will know what UUID new row has */ + $uuid = $GLOBALS['dbi']->fetchValue('SELECT UUID()'); + return "'" . $uuid . "'"; + } elseif ((in_array($multi_edit_funcs[$key], $gis_from_text_functions) + && substr($current_value, 0, 3) == "'''") + || in_array($multi_edit_funcs[$key], $gis_from_wkb_functions) + ) { + // Remove enclosing apostrophes + $current_value = substr($current_value, 1, strlen($current_value) - 2); + // Remove escaping apostrophes + $current_value = str_replace("''", "'", $current_value); + return $multi_edit_funcs[$key] . '(' . $current_value . ')'; + } elseif (! in_array($multi_edit_funcs[$key], $func_no_param) + || ($current_value != "''" + && in_array($multi_edit_funcs[$key], $func_optional_param)) + ) { + if (isset($multi_edit_salt[$key]) + && ($multi_edit_funcs[$key] == "AES_ENCRYPT") + ) { + return $multi_edit_funcs[$key] . '(' . $current_value . ",'" + . PMA_Util::sqlAddSlashes($multi_edit_salt[$key]) . "')"; + } else { + return $multi_edit_funcs[$key] . '(' . $current_value . ')'; + } + } else { + return $multi_edit_funcs[$key] . '()'; + } +} + +/** + * Get query values array and query fields array for insert and update in multi edit + * + * @param array $multi_edit_columns_name multiple edit columns name array + * @param array $multi_edit_columns_null multiple edit columns null array + * @param string $current_value current value in the column in loop + * @param array $multi_edit_columns_prev multiple edit previous columns array + * @param array $multi_edit_funcs multiple edit functions array + * @param boolean $is_insert boolean value whether insert or not + * @param array $query_values SET part of the sql query + * @param array $query_fields array of query fields + * @param string $current_value_as_an_array current value in the column + * as an array + * @param array $value_sets array of valu sets + * @param string $key an md5 of the column name + * @param array $multi_edit_columns_null_prev array of multiple edit columns + * null previous + * + * @return array ($query_values, $query_fields) + */ +function PMA_getQueryValuesForInsertAndUpdateInMultipleEdit($multi_edit_columns_name, + $multi_edit_columns_null, $current_value, $multi_edit_columns_prev, + $multi_edit_funcs,$is_insert, $query_values, $query_fields, + $current_value_as_an_array, $value_sets, $key, $multi_edit_columns_null_prev +) { + // i n s e r t + if ($is_insert) { + // no need to add column into the valuelist + if (strlen($current_value_as_an_array)) { + $query_values[] = $current_value_as_an_array; + // first inserted row so prepare the list of fields + if (empty($value_sets)) { + $query_fields[] = PMA_Util::backquote( + $multi_edit_columns_name[$key] + ); + } + } + + } elseif (! empty($multi_edit_columns_null_prev[$key]) + && ! isset($multi_edit_columns_null[$key]) + ) { + // u p d a t e + + // field had the null checkbox before the update + // field no longer has the null checkbox + $query_values[] + = PMA_Util::backquote($multi_edit_columns_name[$key]) + . ' = ' . $current_value_as_an_array; + } elseif (empty($multi_edit_funcs[$key]) + && isset($multi_edit_columns_prev[$key]) + && ("'" . PMA_Util::sqlAddSlashes($multi_edit_columns_prev[$key]) . "'" + == $current_value) + ) { + // No change for this column and no MySQL function is used -> next column + } elseif (! empty($current_value)) { + // avoid setting a field to NULL when it's already NULL + // (field had the null checkbox before the update + // field still has the null checkbox) + if (empty($multi_edit_columns_null_prev[$key]) + || empty($multi_edit_columns_null[$key]) + ) { + $query_values[] + = PMA_Util::backquote($multi_edit_columns_name[$key]) + . ' = ' . $current_value_as_an_array; + } + } + return array($query_values, $query_fields); +} + +/** + * Get the current column value in the form for different data types + * + * @param string $possibly_uploaded_val uploaded file content + * @param string $key an md5 of the column name + * @param array $multi_edit_columns_type array of multi edit column types + * @param string $current_value current column value in the form + * @param array $multi_edit_auto_increment multi edit auto increment + * @param string $rownumber index of where clause array + * @param array $multi_edit_columns_name multi edit column names array + * @param array $multi_edit_columns_null multi edit columns null array + * @param array $multi_edit_columns_null_prev multi edit columns previous null + * @param boolean $is_insert whether insert or not + * @param boolean $using_key whether editing or new row + * @param array $where_clause where clauses + * @param string $table table name + * + * @return string $current_value current column value in the form + */ +function PMA_getCurrentValueForDifferentTypes($possibly_uploaded_val, $key, + $multi_edit_columns_type, $current_value, $multi_edit_auto_increment, + $rownumber, $multi_edit_columns_name, $multi_edit_columns_null, + $multi_edit_columns_null_prev, $is_insert, $using_key, $where_clause, $table +) { + // Fetch the current values of a row to use in case we have a protected field + if ($is_insert + && $using_key && isset($multi_edit_columns_type) + && is_array($multi_edit_columns_type) && isset($where_clause) + ) { + $protected_row = $GLOBALS['dbi']->fetchSingleRow( + 'SELECT * FROM ' . PMA_Util::backquote($table) + . ' WHERE ' . $where_clause . ';' + ); + } + + if (false !== $possibly_uploaded_val) { + $current_value = $possibly_uploaded_val; + } else { + // c o l u m n v a l u e i n t h e f o r m + if (isset($multi_edit_columns_type[$key])) { + $type = $multi_edit_columns_type[$key]; + } else { + $type = ''; + } + + if ($type != 'protected' && $type != 'set' && 0 === strlen($current_value)) { + // best way to avoid problems in strict mode + // (works also in non-strict mode) + if (isset($multi_edit_auto_increment) + && isset($multi_edit_auto_increment[$key]) + ) { + $current_value = 'NULL'; + } else { + $current_value = "''"; + } + } elseif ($type == 'set') { + if (! empty($_REQUEST['fields']['multi_edit'][$rownumber][$key])) { + $current_value = implode( + ',', $_REQUEST['fields']['multi_edit'][$rownumber][$key] + ); + $current_value = "'" . PMA_Util::sqlAddSlashes($current_value) . "'"; + } else { + $current_value = "''"; + } + } elseif ($type == 'protected') { + // here we are in protected mode (asked in the config) + // so tbl_change has put this special value in the + // coulmns array, so we do not change the column value + // but we can still handle column upload + + // when in UPDATE mode, do not alter field's contents. When in INSERT + // mode, insert empty field because no values were submitted. + // If protected blobs where set, insert original fields content. + if (! empty($protected_row[$multi_edit_columns_name[$key]])) { + $current_value = '0x' + . bin2hex($protected_row[$multi_edit_columns_name[$key]]); + } else { + $current_value = ''; + } + } elseif ($type == 'bit') { + $current_value = preg_replace('/[^01]/', '0', $current_value); + $current_value = "b'" . PMA_Util::sqlAddSlashes($current_value) . "'"; + } elseif (! ($type == 'datetime' || $type == 'timestamp') + || $current_value != 'CURRENT_TIMESTAMP' + ) { + $current_value = "'" . PMA_Util::sqlAddSlashes($current_value) . "'"; + } + + // Was the Null checkbox checked for this field? + // (if there is a value, we ignore the Null checkbox: this could + // be possible if Javascript is disabled in the browser) + if (! empty($multi_edit_columns_null[$key]) + && ($current_value == "''" || $current_value == '') + ) { + $current_value = 'NULL'; + } + + // The Null checkbox was unchecked for this field + if (empty($current_value) + && ! empty($multi_edit_columns_null_prev[$key]) + && ! isset($multi_edit_columns_null[$key]) + ) { + $current_value = "''"; + } + } // end else (column value in the form) + return $current_value; +} + + +/** + * Check whether inline edited value can be truncated or not, + * and add additional parameters for extra_data array if needed + * + * @param string $db Database name + * @param string $table Table name + * @param string $column_name Column name + * @param array &$extra_data Extra data for ajax response + * + * @return void + */ +function PMA_verifyWhetherValueCanBeTruncatedAndAppendExtraData( + $db, $table, $column_name, &$extra_data +) { + + $extra_data['isNeedToRecheck'] = true; + + $sql_for_real_value = 'SELECT '. PMA_Util::backquote($table) . '.' + . PMA_Util::backquote($column_name) + . ' FROM ' . PMA_Util::backquote($db) . '.' + . PMA_Util::backquote($table) + . ' WHERE ' . $_REQUEST['where_clause'][0]; + + $result = $GLOBALS['dbi']->tryQuery($sql_for_real_value); + $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result); + $meta = $fields_meta[0]; + $new_value = $GLOBALS['dbi']->fetchValue($result); + if ($new_value !== false) { + if ((substr($meta->type, 0, 9) == 'timestamp') + || ($meta->type == 'datetime') + || ($meta->type == 'time') + ) { + $new_value = PMA_Util::addMicroseconds($new_value); + } + $extra_data['truncatableFieldValue'] = $new_value; + } else { + $extra_data['isNeedToRecheck'] = false; + } + +} + +/** + * Function to get the columns of a table + * + * @param string $db current db + * @param string $table current table + * + * @return array + */ +function PMA_getTableColumns($db, $table) +{ + $GLOBALS['dbi']->selectDb($db); + return array_values($GLOBALS['dbi']->getColumns($db, $table)); + +} + +/** + * Function to determine Insert/Edit rows + * + * @param string $where_clause where clause + * @param string $db current database + * @param string $table current table + * + * @return mixed + */ +function PMA_determineInsertOrEdit($where_clause, $db, $table) +{ + if (isset($_REQUEST['where_clause'])) { + $where_clause = $_REQUEST['where_clause']; + } + if (isset($_SESSION['edit_next'])) { + $where_clause = $_SESSION['edit_next']; + unset($_SESSION['edit_next']); + $after_insert = 'edit_next'; + } + if (isset($_REQUEST['ShowFunctionFields'])) { + $GLOBALS['cfg']['ShowFunctionFields'] = $_REQUEST['ShowFunctionFields']; + } + if (isset($_REQUEST['ShowFieldTypesInDataEditView'])) { + $GLOBALS['cfg']['ShowFieldTypesInDataEditView'] + = $_REQUEST['ShowFieldTypesInDataEditView']; + } + if (isset($_REQUEST['after_insert'])) { + $after_insert = $_REQUEST['after_insert']; + } + + if (isset($where_clause)) { + // we are editing + $insert_mode = false; + $where_clause_array = PMA_getWhereClauseArray($where_clause); + list($where_clauses, $result, $rows, $found_unique_key) + = PMA_analyzeWhereClauses( + $where_clause_array, $table, $db + ); + } else { + // we are inserting + $insert_mode = true; + $where_clause = null; + list($result, $rows) = PMA_loadFirstRow($table, $db); + $where_clauses = null; + $where_clause_array = null; + $found_unique_key = false; + } + + // Copying a row - fetched data will be inserted as a new row, + // therefore the where clause is needless. + if (isset($_REQUEST['default_action']) + && $_REQUEST['default_action'] === 'insert' + ) { + $where_clause = $where_clauses = null; + } + + return array( + $insert_mode, $where_clause, $where_clause_array, $where_clauses, + $result, $rows, $found_unique_key, + isset($after_insert) ? $after_insert : null + ); +} + +/** + * Function to get comments for the table columns + * + * @param string $db current database + * @param string $table current table + * + * @return array $comments_map comments for columns + */ +function PMA_getCommentsMap($db, $table) +{ + /** + * get table information + * @todo should be done by a Table object + */ + include 'libraries/tbl_info.inc.php'; + + /** + * Get comments for table fields/columns + */ + $comments_map = array(); + + if ($GLOBALS['cfg']['ShowPropertyComments']) { + $comments_map = PMA_getComments($db, $table); + } + + return $comments_map; +} + +/** + * Function to get URL parameters + * + * @param string $db current database + * @param string $table current table + * + * @return array $url_params url parameters + */ +function PMA_getUrlParameters($db, $table) +{ + /** + * @todo check if we could replace by "db_|tbl_" - please clarify!? + */ + $url_params = array( + 'db' => $db, + 'sql_query' => $_REQUEST['sql_query'] + ); + + if (preg_match('@^tbl_@', $GLOBALS['goto'])) { + $url_params['table'] = $table; + } + + return $url_params; +} + +/** + * Function to get html for the gis editor div + * + * @return string + */ +function PMA_getHtmlForGisEditor() +{ + return '
    ' + . '' + . '
    '; +} + +/** + * Function to get html for the ignore option in insert mode + * + * @param int $row_id row id + * + * @return string + */ +function PMA_getHtmlForIgnoreOption($row_id) +{ + return '' + .'
    ' . "\n"; +} + +/** + * Function to get html for the function option + * + * @param bool $odd_row whether odd row or not + * @param array $column column + * @param string $column_name_appendix column name appendix + * + * @return String + */ +function PMA_getHtmlForFunctionOption($odd_row, $column, $column_name_appendix) +{ + $longDoubleTextArea = $GLOBALS['cfg']['LongtextDoubleTextarea']; + return '' + . ''; + +} + +/** + * Function to get html for the column type + * + * @param array $column column + * + * @return string + */ +function PMA_getHtmlForInsertEditColumnType($column) +{ + return ''; + +} + +/** + * Function to get html for the insert edit form header + * + * @param bool $has_blob_field whether has blob field + * @param bool $is_upload whether is upload + * + * @return string + */ +function PMA_getHtmlForInsertEditFormHeader($has_blob_field, $is_upload) +{ + $html_output ='fieldLen($current_result, $i); + // length is unknown for geometry fields, + // make enough space to edit very simple WKTs + if (-1 === $column['len']) { + $column['len'] = 30; + } + } + //Call validation when the form submitted... + $unnullify_trigger = $chg_evt_handler + . "=\"return verificationsAfterFieldChange('" + . PMA_escapeJsString($column['Field_md5']) . "', '" + . PMA_escapeJsString($jsvkey) . "','".$column['pma_type'] . "')\""; + + // Use an MD5 as an array index to avoid having special characters + // in the name atttibute (see bug #1746964 ) + $column_name_appendix = $vkey . '[' . $column['Field_md5'] . ']'; + + if ($column['Type'] == 'datetime' + && ! isset($column['Default']) + && ! is_null($column['Default']) + && ($insert_mode || ! isset($current_row[$column['Field']])) + ) { + // INSERT case or + // UPDATE case with an NULL value + $current_row[$column['Field']] = date('Y-m-d H:i:s', time()); + } + + $html_output = PMA_getHtmlForFunctionOption( + $odd_row, $column, $column_name_appendix + ); + + if ($GLOBALS['cfg']['ShowFieldTypesInDataEditView']) { + $html_output .= PMA_getHtmlForInsertEditColumnType($column); + } //End if + + // Get a list of GIS data types. + $gis_data_types = PMA_Util::getGISDatatypes(); + + // Prepares the field value + $real_null_value = false; + $special_chars_encoded = ''; + if (isset($current_row)) { + // (we are editing) + list( + $real_null_value, $special_chars_encoded, $special_chars, + $data, $backup_field + ) + = PMA_getSpecialCharsAndBackupFieldForExistingRow( + $current_row, $column, $extracted_columnspec, + $real_null_value, $gis_data_types, $column_name_appendix + ); + } else { + // (we are inserting) + // display default values + list($real_null_value, $data, $special_chars, $backup_field, + $special_chars_encoded + ) + = PMA_getSpecialCharsAndBackupFieldForInsertingMode( + $column, $real_null_value + ); + } + + $idindex = ($o_rows * $columns_cnt) + $i + 1; + $tabindex = $idindex; + + // Get a list of data types that are not yet supported. + $no_support_types = PMA_Util::unsupportedDatatypes(); + + // The function column + // ------------------- + if ($GLOBALS['cfg']['ShowFunctionFields']) { + $html_output .= PMA_getFunctionColumn( + $column, $is_upload, $column_name_appendix, + $unnullify_trigger, $no_support_types, $tabindex_for_function, + $tabindex, $idindex, $insert_mode + ); + } + + // The null column + // --------------- + $foreignData = PMA_getForeignData( + $foreigners, $column['Field'], false, '', '' + ); + $html_output .= PMA_getNullColumn( + $column, $column_name_appendix, $real_null_value, + $tabindex, $tabindex_for_null, $idindex, $vkey, $foreigners, + $foreignData + ); + + // The value column (depends on type) + // ---------------- + // See bug #1667887 for the reason why we don't use the maxlength + // HTML attribute + + //add data attributes "no of decimals" and "data type" + $no_decimals=0; + $type = current(explode("(", $column['pma_type'])); + if(preg_match('/\(([^()]+)\)/', $column['pma_type'], $match)){ + $match[0] = trim($match[0], '()'); + $no_decimals=$match[0]; + } + $html_output .= '' . "\n"; + // Will be used by js/tbl_change.js to set the default value + // for the "Continue insertion" feature + $html_output .= '' + . $special_chars . ''; + + $html_output .= PMA_getValueColumn( + $column, $backup_field, $column_name_appendix, $unnullify_trigger, + $tabindex, $tabindex_for_value, $idindex, $data, $special_chars, + $foreignData, $odd_row, array($table, $db), $row_id, $titles, + $text_dir, $special_chars_encoded, $vkey, $is_upload, + $biggest_max_file_size, $default_char_editing, + $no_support_types, $gis_data_types, $extracted_columnspec + ); + + $html_output .= '' + . ''; + + return $html_output; +} + +/** + * Function to get html for each insert/edit row + * + * @param array $url_params url parameters + * @param array $table_columns table columns + * @param array $column column + * @param array $comments_map comments map + * @param bool $timestamp_seen whether timestamp seen + * @param array $current_result current result + * @param string $chg_evt_handler javascript change event handler + * @param string $jsvkey javascript validation key + * @param string $vkey validation key + * @param bool $insert_mode whether insert mode + * @param array $current_row current row + * @param int &$o_rows row offset + * @param int &$tabindex tab index + * @param int $columns_cnt columns count + * @param bool $is_upload whether upload + * @param int $tabindex_for_function tab index offset for function + * @param array $foreigners foreigners + * @param int $tabindex_for_null tab index offset for null + * @param int $tabindex_for_value tab index offset for value + * @param string $table table + * @param string $db database + * @param int $row_id row id + * @param array $titles titles + * @param int $biggest_max_file_size biggest max file size + * @param string $text_dir text direction + * + * @return string + */ +function PMA_getHtmlForInsertEditRow($url_params, $table_columns, + $column, $comments_map, $timestamp_seen, $current_result, $chg_evt_handler, + $jsvkey, $vkey, $insert_mode, $current_row, &$o_rows, &$tabindex, $columns_cnt, + $is_upload, $tabindex_for_function, $foreigners, $tabindex_for_null, + $tabindex_for_value, $table, $db, $row_id, $titles, + $biggest_max_file_size, $text_dir +) { + $html_output = PMA_getHeadAndFootOfInsertRowTable($url_params) + . ''; + + //store the default value for CharEditing + $default_char_editing = $GLOBALS['cfg']['CharEditing']; + + $odd_row = true; + for ($i = 0; $i < $columns_cnt; $i++) { + $html_output .= PMA_getHtmlForInsertEditFormColumn( + $table_columns, $i, $column, $comments_map, $timestamp_seen, + $current_result, $chg_evt_handler, $jsvkey, $vkey, $insert_mode, + $current_row, $odd_row, $o_rows, $tabindex, $columns_cnt, $is_upload, + $tabindex_for_function, $foreigners, $tabindex_for_null, + $tabindex_for_value, $table, $db, $row_id, $titles, + $biggest_max_file_size, $default_char_editing, $text_dir + ); + $odd_row = !$odd_row; + } // end for + $o_rows++; + $html_output .= ' ' + . '
    ' . __('Column') . ''. __('Null') . '' . __('Value') . '
    ' + . '' + . '
    ' + . $column['Field_title'] + . '' + . '' + . '' . $column['pma_type'] . '' + . '

    '; + + return $html_output; +} +?> diff --git a/phpMyAdmin/libraries/ip_allow_deny.lib.php b/phpMyAdmin/libraries/ip_allow_deny.lib.php index fd0bc02..86a88ed 100644 --- a/phpMyAdmin/libraries/ip_allow_deny.lib.php +++ b/phpMyAdmin/libraries/ip_allow_deny.lib.php @@ -4,16 +4,16 @@ * This library is used with the server IP allow/deny host authentication * feature * - * @todo Broken for IPv6 - * * @package PhpMyAdmin */ - +if (! defined('PHPMYADMIN')) { + exit; +} /** * Gets the "true" IP address of the current user * - * @return string the ip of the user + * @return string the ip of the user * * @access private */ @@ -29,10 +29,15 @@ function PMA_getIp() /* Do we trust this IP as a proxy? If yes we will use it's header. */ if (isset($GLOBALS['cfg']['TrustedProxies'][$direct_ip])) { - $trusted_header_value = PMA_getenv($GLOBALS['cfg']['TrustedProxies'][$direct_ip]); + $trusted_header_value + = PMA_getenv($GLOBALS['cfg']['TrustedProxies'][$direct_ip]); $matches = array(); - // the $ checks that the header contains only one IP address, ?: makes sure the () don't capture - $is_ip = preg_match('|^(?:[0-9]{1,3}\.){3,3}[0-9]{1,3}$|', $trusted_header_value, $matches); + // the $ checks that the header contains only one IP address, + // ?: makes sure the () don't capture + $is_ip = preg_match( + '|^(?:[0-9]{1,3}\.){3,3}[0-9]{1,3}$|', + $trusted_header_value, $matches + ); if ($is_ip && (count($matches) == 1)) { // True IP behind a proxy return $matches[0]; @@ -44,6 +49,31 @@ function PMA_getIp() } // end of the 'PMA_getIp()' function +/** + * Matches for IPv4 or IPv6 addresses + * + * @param string $testRange string of IP range to match + * @param string $ipToTest string of IP to test against range + * + * @return boolean whether the IP mask matches + * + * @access public + */ +function PMA_ipMaskTest($testRange, $ipToTest) +{ + $result = true; + + if (strpos($testRange, ':') > -1 || strpos($ipToTest, ':') > -1) { + // assume IPv6 + $result = PMA_ipv6MaskTest($testRange, $ipToTest); + } else { + $result = PMA_ipv4MaskTest($testRange, $ipToTest); + } + + return $result; +} // end of the "PMA_ipMaskTest()" function + + /** * Based on IP Pattern Matcher * Originally by J.Adams @@ -58,45 +88,50 @@ function PMA_getIp() * Does not match: * xxx.xxx.xxx.xx[yyy-zzz] (range, partial octets not supported) * - * @param string string of IP range to match - * @param string string of IP to test against range + * @param string $testRange string of IP range to match + * @param string $ipToTest string of IP to test against range * - * @return boolean always true + * @return boolean whether the IP mask matches * * @access public */ -function PMA_ipMaskTest($testRange, $ipToTest) +function PMA_ipv4MaskTest($testRange, $ipToTest) { - $result = true; - - if (preg_match('|([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/([0-9]+)|', $testRange, $regs)) { - // performs a mask match - $ipl = ip2long($ipToTest); - $rangel = ip2long($regs[1] . '.' . $regs[2] . '.' . $regs[3] . '.' . $regs[4]); - - $maskl = 0; - - for ($i = 0; $i < 31; $i++) { - if ($i < $regs[5] - 1) { - $maskl = $maskl + PMA_pow(2, (30 - $i)); - } // end if - } // end for - - if (($maskl & $rangel) == ($maskl & $ipl)) { - return true; - } else { - return false; - } - } else { - // range based - $maskocts = explode('.', $testRange); - $ipocts = explode('.', $ipToTest); - - // perform a range match - for ($i = 0; $i < 4; $i++) { + $result = true; + $match = preg_match( + '|([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/([0-9]+)|', + $testRange, + $regs + ); + if ($match) { + // performs a mask match + $ipl = ip2long($ipToTest); + $rangel = ip2long( + $regs[1] . '.' . $regs[2] . '.' . $regs[3] . '.' . $regs[4] + ); + + $maskl = 0; + + for ($i = 0; $i < 31; $i++) { + if ($i < $regs[5] - 1) { + $maskl = $maskl + PMA_Util::pow(2, (30 - $i)); + } // end if + } // end for + + if (($maskl & $rangel) == ($maskl & $ipl)) { + return true; + } else { + return false; + } + } else { + // range based + $maskocts = explode('.', $testRange); + $ipocts = explode('.', $ipToTest); + + // perform a range match + for ($i = 0; $i < 4; $i++) { if (preg_match('|\[([0-9]+)\-([0-9]+)\]|', $maskocts[$i], $regs)) { - if (($ipocts[$i] > $regs[2]) - || ($ipocts[$i] < $regs[1])) { + if (($ipocts[$i] > $regs[2]) || ($ipocts[$i] < $regs[1])) { $result = false; } // end if } else { @@ -104,19 +139,125 @@ function PMA_ipMaskTest($testRange, $ipToTest) $result = false; } // end if } // end if/else - } //end for - } //end if/else + } //end for + } //end if/else + + return $result; +} // end of the "PMA_ipv4MaskTest()" function + + +/** + * IPv6 matcher + * CIDR section taken from http://stackoverflow.com/a/10086404 + * Modified for phpMyAdmin + * + * Matches: + * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx + * (exact) + * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:[yyyy-zzzz] + * (range, only at end of IP - no subnets) + * xxxx:xxxx:xxxx:xxxx/nn + * (CIDR) + * + * Does not match: + * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xx[yyy-zzz] + * (range, partial octets not supported) + * + * @param string $test_range string of IP range to match + * @param string $ip_to_test string of IP to test against range + * + * @return boolean whether the IP mask matches + * + * @access public + */ +function PMA_ipv6MaskTest($test_range, $ip_to_test) +{ + $result = true; + + // convert to lowercase for easier comparison + $test_range = strtolower($test_range); + $ip_to_test = strtolower($ip_to_test); + + $is_cidr = strpos($test_range, '/') > -1; + $is_range = strpos($test_range, '[') > -1; + $is_single = ! $is_cidr && ! $is_range; + + $ip_hex = bin2hex(inet_pton($ip_to_test)); + + if ($is_single) { + $range_hex = bin2hex(inet_pton($test_range)); + $result = $ip_hex === $range_hex; + } elseif ($is_range) { + // what range do we operate on? + $range_match = array(); + $match = preg_match( + '/\[([0-9a-f]+)\-([0-9a-f]+)\]/', $test_range, $range_match + ); + if ($match) { + $range_start = $range_match[1]; + $range_end = $range_match[2]; + + // get the first and last allowed IPs + $first_ip = str_replace($range_match[0], $range_start, $test_range); + $first_hex = bin2hex(inet_pton($first_ip)); + $last_ip = str_replace($range_match[0], $range_end, $test_range); + $last_hex = bin2hex(inet_pton($last_ip)); + + // check if the IP to test is within the range + $result = ($ip_hex >= $first_hex && $ip_hex <= $last_hex); + } + } elseif ($is_cidr) { + // Split in address and prefix length + list($first_ip, $subnet) = explode('/', $test_range); + + // Parse the address into a binary string + $first_bin = inet_pton($first_ip); + $first_hex = bin2hex($first_bin); + + // Overwriting first address string to make sure notation is optimal + $first_ip = inet_ntop($first_bin); + + $flexbits = 128 - $subnet; + + // Build the hexadecimal string of the last address + $last_hex = $first_hex; + + $pos = 31; + while ($flexbits > 0) { + // Get the character at this position + $orig = substr($last_hex, $pos, 1); + + // Convert it to an integer + $origval = hexdec($orig); + + // OR it with (2^flexbits)-1, with flexbits limited to 4 at a time + $newval = $origval | (pow(2, min(4, $flexbits)) - 1); + + // Convert it back to a hexadecimal character + $new = dechex($newval); + + // And put that character back in the string + $last_hex = substr_replace($last_hex, $new, $pos, 1); + + // We processed one nibble, move to previous position + $flexbits -= 4; + $pos -= 1; + } + + // check if the IP to test is within the range + $result = ($ip_hex >= $first_hex && $ip_hex <= $last_hex); + } - return $result; -} // end of the "PMA_IPMaskTest()" function + return $result; +} // end of the "PMA_ipv6MaskTest()" function /** * Runs through IP Allow/Deny rules the use of it below for more information * - * @param string 'allow' | 'deny' type of rule to match + * @param string $type 'allow' | 'deny' type of rule to match * - * @return bool Matched a rule ? + * @return bool Matched a rule ? * * @access public * @@ -162,7 +303,8 @@ function PMA_allowDeny($type) // check for username if (($rule_data[1] != '%') //wildcarded first - && ($rule_data[1] != $username)) { + && ($rule_data[1] != $username) + ) { continue; } diff --git a/phpMyAdmin/libraries/js_escape.lib.php b/phpMyAdmin/libraries/js_escape.lib.php index c410eb9..42d7fed 100644 --- a/phpMyAdmin/libraries/js_escape.lib.php +++ b/phpMyAdmin/libraries/js_escape.lib.php @@ -6,6 +6,9 @@ * @package PhpMyAdmin * */ +if (! defined('PHPMYADMIN')) { + exit; +} /** * Format a string so it can be a string inside JavaScript code inside an @@ -13,10 +16,10 @@ * This function is used to displays a javascript confirmation box for * "DROP/DELETE/ALTER" queries. * - * @param string $a_string the string to format - * @param boolean $add_backquotes whether to add backquotes to the string or not + * @param string $a_string the string to format + * @param boolean $add_backquotes whether to add backquotes to the string or not * - * @return string the formatted string + * @return string the formatted string * * @access public */ @@ -30,7 +33,7 @@ function PMA_jsFormat($a_string = '', $add_backquotes = true) $a_string = str_replace('#', '\\#', $a_string); } - return (($add_backquotes) ? PMA_backquote($a_string) : $a_string); + return (($add_backquotes) ? PMA_Util::backquote($a_string) : $a_string); } // end of the 'PMA_jsFormat()' function /** @@ -41,19 +44,26 @@ function PMA_jsFormat($a_string = '', $add_backquotes = true) * We also remove NUL byte as some browsers (namely MSIE) ignore it and * inserting it anywhere inside '', - '\\' => '\\\\', - '\'' => '\\\'', - '"' => '\"', - "\n" => '\n', - "\r" => '\r'))); + return preg_replace( + '@ '', + '\\' => '\\\\', + '\'' => '\\\'', + '"' => '\"', + "\n" => '\n', + "\r" => '\r' + ) + ) + ); } /** @@ -61,7 +71,7 @@ function PMA_escapeJsString($string) * * @param string $value String to be formatted. * - * @retrun string formatted value. + * @return string formatted value. */ function PMA_formatJsVal($value) { @@ -84,7 +94,8 @@ function PMA_formatJsVal($value) * * @param string $key Name of value to set * @param mixed $value Value to set, can be either string or array of strings - * @param bool $escape Whether to escape value or keep it as it is (for inclusion of js code) + * @param bool $escape Whether to escape value or keep it as it is + * (for inclusion of js code) * * @return string Javascript code. */ @@ -95,7 +106,7 @@ function PMA_getJsValue($key, $value, $escape = true) $result .= $value; } elseif (is_array($value)) { $result .= '['; - foreach ($value as $id => $val) { + foreach ($value as $val) { $result .= PMA_formatJsVal($val) . ","; } $result .= "];\n"; @@ -109,10 +120,10 @@ function PMA_getJsValue($key, $value, $escape = true) * Prints an javascript assignment with proper escaping of a value * and support for assigning array of strings. * - * @param string $key Name of value to set - * @param mixed $value Value to set, can be either string or array of strings + * @param string $key Name of value to set + * @param mixed $value Value to set, can be either string or array of strings * - * @return nothing + * @return void */ function PMA_printJsValue($key, $value) { diff --git a/phpMyAdmin/libraries/kanji-encoding.lib.php b/phpMyAdmin/libraries/kanji-encoding.lib.php index 86c4f09..0495112 100644 --- a/phpMyAdmin/libraries/kanji-encoding.lib.php +++ b/phpMyAdmin/libraries/kanji-encoding.lib.php @@ -20,94 +20,93 @@ * codes list * 2002/1/4 by Y.Kawada * - * @global string the current encoding code - * @global string the available encoding codes list + * @global string $kanji_encoding_list the available encoding codes list * - * @return boolean always true + * @return boolean always true */ -function PMA_internal_enc_check() +function PMA_Kanji_checkEncoding() { - global $internal_enc, $enc_list; + global $kanji_encoding_list; $internal_enc = mb_internal_encoding(); if ($internal_enc == 'EUC-JP') { - $enc_list = 'ASCII,EUC-JP,SJIS,JIS'; + $kanji_encoding_list = 'ASCII,EUC-JP,SJIS,JIS'; } else { - $enc_list = 'ASCII,SJIS,EUC-JP,JIS'; + $kanji_encoding_list = 'ASCII,SJIS,EUC-JP,JIS'; } return true; -} // end of the 'PMA_internal_enc_check' function +} // end of the 'PMA_Kanji_checkEncoding' function /** * Reverses SJIS & EUC-JP position in the encoding codes list * 2002/1/4 by Y.Kawada * - * @global string the available encoding codes list + * @global string $kanji_encoding_list the available encoding codes list * - * @return boolean always true + * @return boolean always true */ -function PMA_change_enc_order() +function PMA_Kanji_changeOrder() { - global $enc_list; + global $kanji_encoding_list; - $p = explode(',', $enc_list); - if ($p[1] == 'EUC-JP') { - $enc_list = 'ASCII,SJIS,EUC-JP,JIS'; + $parts = explode(',', $kanji_encoding_list); + if ($parts[1] == 'EUC-JP') { + $kanji_encoding_list = 'ASCII,SJIS,EUC-JP,JIS'; } else { - $enc_list = 'ASCII,EUC-JP,SJIS,JIS'; + $kanji_encoding_list = 'ASCII,EUC-JP,SJIS,JIS'; } return true; -} // end of the 'PMA_change_enc_order' function +} // end of the 'PMA_Kanji_changeOrder' function /** * Kanji string encoding convert * 2002/1/4 by Y.Kawada * - * @param string the string to convert - * @param string the destination encoding code - * @param string set 'kana' convert to JIS-X208-kana + * @param string $str the string to convert + * @param string $enc the destination encoding code + * @param string $kana set 'kana' convert to JIS-X208-kana * - * @global string the available encoding codes list + * @global string $kanji_encoding_list the available encoding codes list * - * @return string the converted string + * @return string the converted string */ -function PMA_kanji_str_conv($str, $enc, $kana) +function PMA_Kanji_strConv($str, $enc, $kana) { - global $enc_list; + global $kanji_encoding_list; if ($enc == '' && $kana == '') { return $str; } - $nw = mb_detect_encoding($str, $enc_list); + $string_encoding = mb_detect_encoding($str, $kanji_encoding_list); if ($kana == 'kana') { - $dist = mb_convert_kana($str, 'KV', $nw); + $dist = mb_convert_kana($str, 'KV', $string_encoding); $str = $dist; } - if ($nw != $enc && $enc != '') { - $dist = mb_convert_encoding($str, $enc, $nw); + if ($string_encoding != $enc && $enc != '') { + $dist = mb_convert_encoding($str, $enc, $string_encoding); } else { $dist = $str; } return $dist; -} // end of the 'PMA_kanji_str_conv' function +} // end of the 'PMA_Kanji_strConv' function /** * Kanji file encoding convert * 2002/1/4 by Y.Kawada * - * @param string the name of the file to convert - * @param string the destination encoding code - * @param string set 'kana' convert to JIS-X208-kana + * @param string $file the name of the file to convert + * @param string $enc the destination encoding code + * @param string $kana set 'kana' convert to JIS-X208-kana * - * @return string the name of the converted file + * @return string the name of the converted file */ -function PMA_kanji_file_conv($file, $enc, $kana) +function PMA_Kanji_fileConv($file, $enc, $kana) { if ($enc == '' && $kana == '') { return $file; @@ -116,46 +115,54 @@ function PMA_kanji_file_conv($file, $enc, $kana) $tmpfname = tempnam('', $enc); $fpd = fopen($tmpfname, 'wb'); $fps = fopen($file, 'r'); - PMA_change_enc_order(); + PMA_Kanji_changeOrder(); while (!feof($fps)) { $line = fgets($fps, 4096); - $dist = PMA_kanji_str_conv($line, $enc, $kana); + $dist = PMA_Kanji_strConv($line, $enc, $kana); fputs($fpd, $dist); } // end while - PMA_change_enc_order(); + PMA_Kanji_changeOrder(); fclose($fps); fclose($fpd); unlink($file); return $tmpfname; -} // end of the 'PMA_kanji_file_conv' function +} // end of the 'PMA_Kanji_fileConv' function /** * Defines radio form fields to switch between encoding modes * 2002/1/4 by Y.Kawada * - * @param string spaces character to prepend the output with - * - * @return string xhtml code for the radio controls + * @return string xhtml code for the radio controls */ -function PMA_set_enc_form($spaces) +function PMA_Kanji_encodingForm() { return "\n" - /* l10n: This is currently used only in Japanese locales */ - . $spaces . '
      ' . "\n" . '
    • ' - . $spaces . '\n" - . $spaces . '' . "\n" - . $spaces . '' . "\n" - . $spaces . '
    • ' . "\n" . '
    • ' - . $spaces . '' . "\n" - /* l10n: This is currently used only in Japanese locales */ - . $spaces . '
      ' . "\n" - . $spaces . '
    • ' . "\n" . '
    ' - ; -} // end of the 'PMA_set_enc_form' function - - -PMA_internal_enc_check(); + . '
      ' . "\n" . '
    • ' + . '' + . '\n" + . '' + . '' . "\n" + . '' + . '' . "\n" + . '
    • ' . "\n" . '
    • ' + . '' + . "\n" + . '
      ' + . "\n" + . '
    • ' . "\n" . '
    ' + ; +} // end of the 'PMA_Kanji_encodingForm' function + + +PMA_Kanji_checkEncoding(); ?> diff --git a/phpMyAdmin/libraries/language_stats.inc.php b/phpMyAdmin/libraries/language_stats.inc.php index 528394b..94855ec 100644 --- a/phpMyAdmin/libraries/language_stats.inc.php +++ b/phpMyAdmin/libraries/language_stats.inc.php @@ -3,70 +3,78 @@ /* Generated by scripts/remove-incomplete-mo */ $GLOBALS["language_stats"] = array ( - 'af' => 11, - 'ar' => 51, - 'az' => 17, - 'be@latin' => 35, - 'be' => 35, - 'bg' => 79, - 'bn' => 21, - 'br' => 28, - 'bs' => 19, - 'ca' => 99, + 'af' => 12, + 'ar' => 45, + 'az' => 15, + 'be' => 31, + 'be@latin' => 31, + 'bg' => 71, + 'bn' => 90, + 'br' => 24, + 'bs' => 16, + 'ca' => 91, + 'ckb' => 19, 'cs' => 100, - 'cy' => 27, - 'da' => 100, + 'cy' => 23, + 'da' => 99, 'de' => 100, 'el' => 100, - 'en_GB' => 100, + 'en_GB' => 99, 'es' => 100, - 'et' => 99, - 'eu' => 24, - 'fa' => 38, - 'fi' => 74, + 'et' => 100, + 'eu' => 20, + 'fa' => 34, + 'fi' => 70, 'fr' => 100, - 'gl' => 100, - 'he' => 23, - 'hi' => 61, - 'hr' => 42, - 'hu' => 83, - 'id' => 81, - 'it' => 99, - 'ja' => 99, - 'ka' => 22, - 'ko' => 42, - 'lt' => 73, + 'gl' => 96, + 'he' => 22, + 'hi' => 52, + 'hr' => 38, + 'hu' => 98, + 'hy' => 3, + 'ia' => 40, + 'id' => 80, + 'it' => 89, + 'ja' => 88, + 'ka' => 19, + 'kk' => 12, + 'kn' => 0, + 'ko' => 74, + 'ky' => 2, + 'lt' => 61, 'lv' => 25, - 'mk' => 24, - 'ml' => 2, - 'mn' => 29, + 'mk' => 21, + 'ml' => 1, + 'mn' => 26, 'ms' => 13, - 'nb' => 77, + 'nb' => 65, 'nl' => 100, - 'pl' => 99, - 'pt_BR' => 98, - 'pt' => 50, - 'ro' => 62, - 'ru' => 100, - 'si' => 81, + 'pa' => 0, + 'pl' => 92, + 'pt' => 61, + 'pt_BR' => 100, + 'ro' => 59, + 'ru' => 95, + 'si' => 78, 'sk' => 80, 'sl' => 100, - 'sq' => 30, - 'sr@latin' => 73, - 'sr' => 33, - 'sv' => 100, - 'ta' => 16, - 'te' => 13, - 'th' => 37, + 'sq' => 28, + 'sr' => 29, + 'sr@latin' => 62, + 'sv' => 98, + 'ta' => 15, + 'te' => 12, + 'th' => 41, 'tk' => 0, 'tr' => 100, - 'tt' => 24, - 'ug' => 16, - 'uk' => 97, - 'ur' => 28, - 'uz@latin' => 53, - 'uz' => 54, - 'zh_CN' => 99, - 'zh_TW' => 85, + 'tt' => 21, + 'ug' => 13, + 'uk' => 94, + 'ur' => 27, + 'uz' => 45, + 'uz@latin' => 44, + 'vls' => 0, + 'zh_CN' => 93, + 'zh_TW' => 99, ); ?> diff --git a/phpMyAdmin/libraries/logging.lib.php b/phpMyAdmin/libraries/logging.lib.php index b2688fe..975fc5a 100644 --- a/phpMyAdmin/libraries/logging.lib.php +++ b/phpMyAdmin/libraries/logging.lib.php @@ -7,11 +7,19 @@ * * @package PhpMyAdmin */ +if (! defined('PHPMYADMIN')) { + exit; +} /** * Logs user information to webserver logs. + * + * @param string $user user name + * @param string $status status message + * + * @return void */ -function PMA_log_user($user, $status = 'ok') +function PMA_logUser($user, $status = 'ok') { if (function_exists('apache_note')) { apache_note('userID', $user); diff --git a/phpMyAdmin/libraries/mime.lib.php b/phpMyAdmin/libraries/mime.lib.php index 71b3f94..399b36d 100644 --- a/phpMyAdmin/libraries/mime.lib.php +++ b/phpMyAdmin/libraries/mime.lib.php @@ -6,11 +6,15 @@ * @package PhpMyAdmin * @todo Maybe we could try to use fileinfo module if loaded */ +if (! defined('PHPMYADMIN')) { + exit; +} /** * Tries to detect MIME type of content. * - * @param string &$test + * @param string &$test First few bytes of content to use for detection + * * @return string */ function PMA_detectMIME(&$test) diff --git a/phpMyAdmin/libraries/mult_submits.inc.php b/phpMyAdmin/libraries/mult_submits.inc.php index 3065492..b52087f 100644 --- a/phpMyAdmin/libraries/mult_submits.inc.php +++ b/phpMyAdmin/libraries/mult_submits.inc.php @@ -1,6 +1,7 @@ getVirtualTables($db); /** * Displays the confirmation form if required @@ -121,357 +123,124 @@ if (!empty($submit_mult) && !empty($what)) { unset($message); - include_once './libraries/header.inc.php'; if (strlen($table)) { - include './libraries/tbl_common.php'; + include './libraries/tbl_common.inc.php'; $url_query .= '&goto=tbl_sql.php&back=tbl_sql.php'; include './libraries/tbl_info.inc.php'; - include_once './libraries/tbl_links.inc.php'; } elseif (strlen($db)) { include './libraries/db_common.inc.php'; include './libraries/db_info.inc.php'; } else { include_once './libraries/server_common.inc.php'; - include_once './libraries/server_links.inc.php'; } // Builds the query - $full_query = ''; - if ($what == 'drop_tbl') { - $full_query_views = ''; - } - $selected_cnt = count($selected); - $i = 0; - foreach ($selected AS $idx => $sval) { - switch ($what) { - case 'row_delete': - $full_query .= htmlspecialchars($sval) - . ';
    '; - break; - case 'drop_db': - $full_query .= 'DROP DATABASE ' - . PMA_backquote(htmlspecialchars($sval)) - . ';
    '; - $reload = 1; - break; - - case 'drop_tbl': - $current = $sval; - if (!empty($views) && in_array($current, $views)) { - $full_query_views .= (empty($full_query_views) ? 'DROP VIEW ' : ', ') - . PMA_backquote(htmlspecialchars($current)); - } else { - $full_query .= (empty($full_query) ? 'DROP TABLE ' : ', ') - . PMA_backquote(htmlspecialchars($current)); - } - break; - - case 'empty_tbl': - $full_query .= 'TRUNCATE '; - $full_query .= PMA_backquote(htmlspecialchars($sval)) - . ';
    '; - break; - - case 'primary_fld': - if ($full_query == '') { - $full_query .= 'ALTER TABLE ' - . PMA_backquote(htmlspecialchars($table)) - . '
      DROP PRIMARY KEY,' - . '
       ADD PRIMARY KEY(' - . '
         ' - . PMA_backquote(htmlspecialchars($sval)) - . ','; - } else { - $full_query .= '
         ' - . PMA_backquote(htmlspecialchars($sval)) - . ','; - } - if ($i == $selected_cnt-1) { - $full_query = preg_replace('@,$@', ');
    ', $full_query); - } - break; - - case 'drop_fld': - if ($full_query == '') { - $full_query .= 'ALTER TABLE ' - . PMA_backquote(htmlspecialchars($table)); - } - $full_query .= '
      DROP ' - . PMA_backquote(htmlspecialchars($sval)) - . ','; - if ($i == $selected_cnt - 1) { - $full_query = preg_replace('@,$@', ';
    ', $full_query); - } - break; - } // end switch - $i++; - } - if ($what == 'drop_tbl') { - if (!empty($full_query)) { - $full_query .= ';
    ' . "\n"; - } - if (!empty($full_query_views)) { - $full_query .= $full_query_views . ';
    ' . "\n"; - } - unset($full_query_views); - } + list($full_query, $reload, $full_query_views) + = PMA_getQueryFromSelected( + $what, $db, $table, $selected, $action, $views + ); // Displays the confirmation form - $_url_params = array( - 'query_type' => $what, - 'reload' => (! empty($reload) ? 1 : 0), + $_url_params = PMA_getUrlParams( + $what, $reload, $action, $db, $table, $selected, $views, + isset($original_sql_query)? $original_sql_query : null, + isset($original_url_query)? $original_url_query : null ); - if (strpos(' ' . $action, 'db_') == 1) { - $_url_params['db']= $db; - } elseif (strpos(' ' . $action, 'tbl_') == 1 || $what == 'row_delete') { - $_url_params['db']= $db; - $_url_params['table']= $table; - } - foreach ($selected as $idx => $sval) { - $_url_params['selected'][] = $sval; - } - if ($what == 'drop_tbl' && !empty($views)) { - foreach ($views as $current) { - $_url_params['views'][] = $current; - } - } - if ($what == 'row_delete') { - $_url_params['original_sql_query'] = $original_sql_query; - if (! empty($original_url_query)) { - $_url_params['original_url_query'] = $original_url_query; - } - } - ?> - - - -
    - : - - - - - -
    -
    -
    -
    -
    - -
    - -
    - : - - - -
    -
    -
    -
    - -
    - -
    - : - -
    -
    - - -
    - '; - include './libraries/footer.inc.php'; -} elseif ($mult_btn == __('Yes')) { -/** - * Executes the query - dropping rows, columns/fields, tables or dbs - */ - if ($query_type == 'drop_db' || $query_type == 'drop_tbl' || $query_type == 'drop_fld') { - include_once './libraries/relation_cleanup.lib.php'; + if ($what == 'replace_prefix_tbl' || $what == 'copy_tbl_change_prefix') { + echo PMA_getHtmlForReplacePrefixTable($what, $action, $_url_params); + } elseif ($what == 'add_prefix_tbl') { + echo PMA_getHtmlForAddPrefixTable($action, $_url_params); + } else { + echo PMA_getHtmlForOtherActions($what, $action, $_url_params, $full_query); } + exit; - $sql_query = ''; - if ($query_type == 'drop_tbl') { - $sql_query_views = ''; +} elseif (! empty($mult_btn) && $mult_btn == __('Yes')) { + /** + * Executes the query - dropping rows, columns/fields, tables or dbs + */ + if ($query_type == 'drop_db' + || $query_type == 'drop_tbl' + || $query_type == 'drop_fld' + ) { + include_once './libraries/relation_cleanup.lib.php'; } - $selected_cnt = count($selected); - $run_parts = false; // whether to run query after each pass - $use_sql = false; // whether to include sql.php at the end (to display results) if ($query_type == 'primary_fld') { // Gets table primary key - PMA_DBI_select_db($db); - $result = PMA_DBI_query('SHOW KEYS FROM ' . PMA_backquote($table) . ';'); - $primary = ''; - while ($row = PMA_DBI_fetch_assoc($result)) { + $GLOBALS['dbi']->selectDb($db); + $result = $GLOBALS['dbi']->query( + 'SHOW KEYS FROM ' . PMA_Util::backquote($table) . ';' + ); + $primary = ''; + while ($row = $GLOBALS['dbi']->fetchAssoc($result)) { // Backups the list of primary keys if ($row['Key_name'] == 'PRIMARY') { $primary .= $row['Column_name'] . ', '; } } // end while - PMA_DBI_free_result($result); + $GLOBALS['dbi']->freeResult($result); } - $rebuild_database_list = false; - - for ($i = 0; $i < $selected_cnt; $i++) { - switch ($query_type) { - case 'row_delete': - $a_query = $selected[$i]; - $run_parts = true; - break; - - case 'drop_db': - PMA_relationsCleanupDatabase($selected[$i]); - $a_query = 'DROP DATABASE ' - . PMA_backquote($selected[$i]); - $reload = 1; - $run_parts = true; - $rebuild_database_list = true; - break; - - case 'drop_tbl': - PMA_relationsCleanupTable($db, $selected[$i]); - $current = $selected[$i]; - if (!empty($views) && in_array($current, $views)) { - $sql_query_views .= (empty($sql_query_views) ? 'DROP VIEW ' : ', ') - . PMA_backquote($current); - } else { - $sql_query .= (empty($sql_query) ? 'DROP TABLE ' : ', ') - . PMA_backquote($current); - } - $reload = 1; - break; - - case 'check_tbl': - $sql_query .= (empty($sql_query) ? 'CHECK TABLE ' : ', ') - . PMA_backquote($selected[$i]); - $use_sql = true; - break; - - case 'optimize_tbl': - $sql_query .= (empty($sql_query) ? 'OPTIMIZE TABLE ' : ', ') - . PMA_backquote($selected[$i]); - $use_sql = true; - break; - - case 'analyze_tbl': - $sql_query .= (empty($sql_query) ? 'ANALYZE TABLE ' : ', ') - . PMA_backquote($selected[$i]); - $use_sql = true; - break; - - case 'repair_tbl': - $sql_query .= (empty($sql_query) ? 'REPAIR TABLE ' : ', ') - . PMA_backquote($selected[$i]); - $use_sql = true; - break; - - case 'empty_tbl': - $a_query = 'TRUNCATE '; - $a_query .= PMA_backquote($selected[$i]); - $run_parts = true; - break; - - case 'drop_fld': - PMA_relationsCleanupColumn($db, $table, $selected[$i]); - $sql_query .= (empty($sql_query) ? 'ALTER TABLE ' . PMA_backquote($table) : ',') - . ' DROP ' . PMA_backquote($selected[$i]) - . (($i == $selected_cnt-1) ? ';' : ''); - break; - - case 'primary_fld': - $sql_query .= (empty($sql_query) ? 'ALTER TABLE ' . PMA_backquote($table) . (empty($primary) ? '' : ' DROP PRIMARY KEY,') . ' ADD PRIMARY KEY( ' : ', ') - . PMA_backquote($selected[$i]) - . (($i == $selected_cnt-1) ? ');' : ''); - break; - - case 'index_fld': - $sql_query .= (empty($sql_query) ? 'ALTER TABLE ' . PMA_backquote($table) . ' ADD INDEX( ' : ', ') - . PMA_backquote($selected[$i]) - . (($i == $selected_cnt-1) ? ');' : ''); - break; - - case 'unique_fld': - $sql_query .= (empty($sql_query) ? 'ALTER TABLE ' . PMA_backquote($table) . ' ADD UNIQUE( ' : ', ') - . PMA_backquote($selected[$i]) - . (($i == $selected_cnt-1) ? ');' : ''); - break; - - case 'spatial_fld': - $sql_query .= (empty($sql_query) ? 'ALTER TABLE ' . PMA_backquote($table) . ' ADD SPATIAL( ' : ', ') - . PMA_backquote($selected[$i]) - . (($i == $selected_cnt-1) ? ');' : ''); - break; - - case 'fulltext_fld': - $sql_query .= (empty($sql_query) ? 'ALTER TABLE ' . PMA_backquote($table) . ' ADD FULLTEXT( ' : ', ') - . PMA_backquote($selected[$i]) - . (($i == $selected_cnt-1) ? ');' : ''); - break; - - case 'add_prefix_tbl': - $newtablename = $add_prefix . $selected[$i]; - $a_query = 'ALTER TABLE ' . PMA_backquote($selected[$i]) . ' RENAME ' . PMA_backquote($newtablename) ; // ADD PREFIX TO TABLE NAME - $run_parts = true; - break; - - case 'replace_prefix_tbl': - $current = $selected[$i]; - $newtablename = preg_replace("/^" . $from_prefix . "/", $to_prefix, $current); - $a_query = 'ALTER TABLE ' . PMA_backquote($selected[$i]) . ' RENAME ' . PMA_backquote($newtablename) ; // CHANGE PREFIX PATTERN - $run_parts = true; - break; - - case 'copy_tbl_change_prefix': - $current = $selected[$i]; - $newtablename = preg_replace("/^" . $from_prefix . "/", $to_prefix, $current); - $a_query = 'CREATE TABLE ' . PMA_backquote($newtablename) . ' SELECT * FROM ' . PMA_backquote($selected[$i]) ; // COPY TABLE AND CHANGE PREFIX PATTERN - $run_parts = true; - break; - - } // end switch - - // All "DROP TABLE", "DROP FIELD", "OPTIMIZE TABLE" and "REPAIR TABLE" - // statements will be run at once below - if ($run_parts) { - $sql_query .= $a_query . ';' . "\n"; - if ($query_type != 'drop_db') { - PMA_DBI_select_db($db); - } - $result = PMA_DBI_query($a_query); - } // end if - } // end for + list( + $result, $rebuild_database_list, $reload_ret, + $run_parts, $use_sql, $sql_query, $sql_query_views + ) = PMA_getQueryStrFromSelected( + $query_type, $selected, $db, $table, $views, + isset($primary) ? $primary : null, + isset($from_prefix) ? $from_prefix : null, + isset($to_prefix) ? $to_prefix : null + ); + //update the existed variable + if (isset($reload_ret)) { + $reload = $reload_ret; + } if ($query_type == 'drop_tbl') { + $default_fk_check_value = $GLOBALS['dbi']->fetchValue( + 'SHOW VARIABLES LIKE \'foreign_key_checks\';', 0, 1 + ) == 'ON'; if (!empty($sql_query)) { - $sql_query .= ';'; - } elseif (!empty($sql_query_views)) { - $sql_query = $sql_query_views . ';'; + $sql_query .= ';'; + } elseif (!empty($sql_query_views)) { + $sql_query = $sql_query_views . ';'; unset($sql_query_views); } } if ($use_sql) { - include './sql.php'; + /** + * Parse and analyze the query + */ + include_once 'libraries/parse_analyze.inc.php'; + + PMA_executeQueryAndSendQueryResponse( + $analyzed_sql_results, false, $db, $table, null, null, null, + false, null, null, null, null, $goto, $pmaThemeImage, null, null, + $query_type, $sql_query, $selected, null + ); } elseif (!$run_parts) { - PMA_DBI_select_db($db); - $result = PMA_DBI_try_query($sql_query); + $GLOBALS['dbi']->selectDb($db); + // for disabling foreign key checks while dropping tables + if (! isset($_REQUEST['fk_check']) && $query_type == 'drop_tbl') { + $GLOBALS['dbi']->query('SET FOREIGN_KEY_CHECKS = 0;'); + } + $result = $GLOBALS['dbi']->tryQuery($sql_query); + if (! isset($_REQUEST['fk_check']) + && $query_type == 'drop_tbl' + && $default_fk_check_value + ) { + $GLOBALS['dbi']->query('SET FOREIGN_KEY_CHECKS = 1;'); + } if ($result && !empty($sql_query_views)) { $sql_query .= ' ' . $sql_query_views . ';'; - $result = PMA_DBI_try_query($sql_query_views); + $result = $GLOBALS['dbi']->tryQuery($sql_query_views); unset($sql_query_views); } if (! $result) { - $message = PMA_Message::error(PMA_DBI_getError()); + $message = PMA_Message::error($GLOBALS['dbi']->getError()); } } if ($rebuild_database_list) { diff --git a/phpMyAdmin/libraries/mult_submits.lib.php b/phpMyAdmin/libraries/mult_submits.lib.php new file mode 100644 index 0000000..1247513 --- /dev/null +++ b/phpMyAdmin/libraries/mult_submits.lib.php @@ -0,0 +1,627 @@ + $what, + 'reload' => (! empty($reload) ? 1 : 0), + ); + if (strpos(' ' . $action, 'db_') == 1) { + $_url_params['db']= $db; + } elseif (strpos(' ' . $action, 'tbl_') == 1 || $what == 'row_delete') { + $_url_params['db']= $db; + $_url_params['table']= $table; + } + foreach ($selected as $idx => $sval) { + if ($what == 'row_delete') { + $_url_params['selected'][] = 'DELETE FROM ' + . PMA_Util::backquote($db) . '.' . PMA_Util::backquote($table) + . ' WHERE ' . urldecode($sval) . ' LIMIT 1;'; + } else { + $_url_params['selected'][] = $sval; + } + } + if ($what == 'drop_tbl' && !empty($views)) { + foreach ($views as $current) { + $_url_params['views'][] = $current; + } + } + if ($what == 'row_delete') { + $_url_params['original_sql_query'] = $original_sql_query; + if (! empty($original_url_query)) { + $_url_params['original_url_query'] = $original_url_query; + } + } + + return $_url_params; +} + +/** + * Gets query results from + * + * @param string $query_type query type + * @param array $selected selected tables + * @param string $db db name + * @param string $table table name + * @param string $views table views + * @param string $primary table primary + * @param string $from_prefix from prefix original + * @param string $to_prefix to prefix original + * + * @return array + */ +function PMA_getQueryStrFromSelected( + $query_type, $selected, $db, $table, $views, $primary, + $from_prefix, $to_prefix +) { + $rebuild_database_list = false; + $reload = null; + $a_query = null; + $sql_query = ''; + $sql_query_views = null; + // whether to run query after each pass + $run_parts = false; + // whether to execute the query at the end (to display results) + $use_sql = false; + $result = null; + + if ($query_type == 'drop_tbl') { + $sql_query_views = ''; + } + + $selected_cnt = count($selected); + $deletes = false; + + for ($i = 0; $i < $selected_cnt; $i++) { + switch ($query_type) { + case 'row_delete': + $deletes = true; + $a_query = $selected[$i]; + $run_parts = true; + break; + + case 'drop_db': + PMA_relationsCleanupDatabase($selected[$i]); + $a_query = 'DROP DATABASE ' + . PMA_Util::backquote($selected[$i]); + $reload = 1; + $run_parts = true; + $rebuild_database_list = true; + break; + + case 'drop_tbl': + PMA_relationsCleanupTable($db, $selected[$i]); + $current = $selected[$i]; + if (!empty($views) && in_array($current, $views)) { + $sql_query_views .= (empty($sql_query_views) ? 'DROP VIEW ' : ', ') + . PMA_Util::backquote($current); + } else { + $sql_query .= (empty($sql_query) ? 'DROP TABLE ' : ', ') + . PMA_Util::backquote($current); + } + $reload = 1; + break; + + case 'check_tbl': + $sql_query .= (empty($sql_query) ? 'CHECK TABLE ' : ', ') + . PMA_Util::backquote($selected[$i]); + $use_sql = true; + break; + + case 'optimize_tbl': + $sql_query .= (empty($sql_query) ? 'OPTIMIZE TABLE ' : ', ') + . PMA_Util::backquote($selected[$i]); + $use_sql = true; + break; + + case 'analyze_tbl': + $sql_query .= (empty($sql_query) ? 'ANALYZE TABLE ' : ', ') + . PMA_Util::backquote($selected[$i]); + $use_sql = true; + break; + + case 'repair_tbl': + $sql_query .= (empty($sql_query) ? 'REPAIR TABLE ' : ', ') + . PMA_Util::backquote($selected[$i]); + $use_sql = true; + break; + + case 'empty_tbl': + $deletes = true; + $a_query = 'TRUNCATE '; + $a_query .= PMA_Util::backquote($selected[$i]); + $run_parts = true; + break; + + case 'drop_fld': + PMA_relationsCleanupColumn($db, $table, $selected[$i]); + $sql_query .= (empty($sql_query) + ? 'ALTER TABLE ' . PMA_Util::backquote($table) + : ',') + . ' DROP ' . PMA_Util::backquote($selected[$i]) + . (($i == $selected_cnt-1) ? ';' : ''); + break; + + case 'primary_fld': + $sql_query .= (empty($sql_query) + ? 'ALTER TABLE ' . PMA_Util::backquote($table) . (empty($primary) + ? '' + : ' DROP PRIMARY KEY,') . ' ADD PRIMARY KEY( ' + : ', ') + . PMA_Util::backquote($selected[$i]) + . (($i == $selected_cnt-1) ? ');' : ''); + break; + + case 'index_fld': + $sql_query .= (empty($sql_query) + ? 'ALTER TABLE ' . PMA_Util::backquote($table) . ' ADD INDEX( ' + : ', ') + . PMA_Util::backquote($selected[$i]) + . (($i == $selected_cnt-1) ? ');' : ''); + break; + + case 'unique_fld': + $sql_query .= (empty($sql_query) + ? 'ALTER TABLE ' . PMA_Util::backquote($table) . ' ADD UNIQUE( ' + : ', ') + . PMA_Util::backquote($selected[$i]) + . (($i == $selected_cnt-1) ? ');' : ''); + break; + + case 'spatial_fld': + $sql_query .= (empty($sql_query) + ? 'ALTER TABLE ' . PMA_Util::backquote($table) . ' ADD SPATIAL( ' + : ', ') + . PMA_Util::backquote($selected[$i]) + . (($i == $selected_cnt-1) ? ');' : ''); + break; + + case 'fulltext_fld': + $sql_query .= (empty($sql_query) + ? 'ALTER TABLE ' . PMA_Util::backquote($table) . ' ADD FULLTEXT( ' + : ', ') + . PMA_Util::backquote($selected[$i]) + . (($i == $selected_cnt-1) ? ');' : ''); + break; + + case 'add_prefix_tbl': + $newtablename = $_POST['add_prefix'] . $selected[$i]; + // ADD PREFIX TO TABLE NAME + $a_query = 'ALTER TABLE ' + . PMA_Util::backquote($selected[$i]) + . ' RENAME ' + . PMA_Util::backquote($newtablename); + $run_parts = true; + break; + + case 'replace_prefix_tbl': + $current = $selected[$i]; + if (substr($current, 0, strlen($from_prefix)) == $from_prefix) { + $newtablename = $to_prefix . substr($current, strlen($from_prefix)); + } else { + $newtablename = $current; + } + // CHANGE PREFIX PATTERN + $a_query = 'ALTER TABLE ' + . PMA_Util::backquote($selected[$i]) + . ' RENAME ' + . PMA_Util::backquote($newtablename); + $run_parts = true; + break; + + case 'copy_tbl_change_prefix': + $current = $selected[$i]; + if (substr($current, 0, strlen($from_prefix)) == $from_prefix) { + $newtablename = $to_prefix . substr($current, strlen($from_prefix)); + } else { + $newtablename = $current; + } + $newtablename = $to_prefix . substr($current, strlen($from_prefix)); + // COPY TABLE AND CHANGE PREFIX PATTERN + $a_query = 'CREATE TABLE ' + . PMA_Util::backquote($newtablename) + . ' SELECT * FROM ' + . PMA_Util::backquote($selected[$i]); + $run_parts = true; + break; + + } // end switch + + // All "DROP TABLE", "DROP FIELD", "OPTIMIZE TABLE" and "REPAIR TABLE" + // statements will be run at once below + if ($run_parts) { + $sql_query .= $a_query . ';' . "\n"; + if ($query_type != 'drop_db') { + $GLOBALS['dbi']->selectDb($db); + } + $result = $GLOBALS['dbi']->query($a_query); + + if ($query_type == 'drop_db') { + PMA_clearTransformations($selected[$i]); + } elseif ($query_type == 'drop_tbl') { + PMA_clearTransformations($db, $selected[$i]); + } else if ($query_type == 'drop_fld') { + PMA_clearTransformations($db, $table, $selected[$i]); + } + } // end if + } // end for + + if ($deletes) { + $_REQUEST['pos'] = PMA_calculatePosForLastPage($db, $table, $_REQUEST['pos']); + } + + return array( + $result, $rebuild_database_list, $reload, + $run_parts, $use_sql, $sql_query, $sql_query_views + ); +} + +/** + * Gets table primary key + * + * @param string $db name of db + * @param string $table name of table + * + * @return string + */ +function PMA_getKeyForTablePrimary($db, $table) +{ + $GLOBALS['dbi']->selectDb($db); + $result = $GLOBALS['dbi']->query( + 'SHOW KEYS FROM ' . PMA_Util::backquote($table) . ';' + ); + $primary = ''; + while ($row = $GLOBALS['dbi']->fetchAssoc($result)) { + // Backups the list of primary keys + if ($row['Key_name'] == 'PRIMARY') { + $primary .= $row['Column_name'] . ', '; + } + } // end while + $GLOBALS['dbi']->freeResult($result); + + return $primary; +} + +/** + * Gets HTML for replace_prefix_tbl or copy_tbl_change_prefix + * + * @param string $what mult_submit type + * @param string $action action type + * @param array $_url_params URL params + * + * @return string + */ +function PMA_getHtmlForReplacePrefixTable($what, $action, $_url_params) +{ + $html = ''; + $html .= PMA_URL_getHiddenInputs($_url_params); + $html .= '
    '; + $html .= ''; + if ($what == 'replace_prefix_tbl') { + $html .= __('Replace table prefix:'); + } else { + $html .= __('Copy table with prefix:'); + } + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= '
    ' . __('From') . ''; + $html .= ''; + $html .= '
    ' . __('To') . ''; + $html .= ''; + $html .= '
    '; + $html .= '
    '; + $html .= '
    '; + $html .= ''; + $html .= ''; + $html .= '
    '; + $html .= ''; + + return $html; +} + +/** + * Gets HTML for add_prefix_tbl + * + * @param string $action action type + * @param array $_url_params URL params + * + * @return string + */ +function PMA_getHtmlForAddPrefixTable($action, $_url_params) +{ + $html = '
    '; + $html .= PMA_URL_getHiddenInputs($_url_params); + $html .= '
    '; + $html .= '' . __('Add table prefix:') . ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= '
    ' . __('Add prefix') . ''; + $html .= ''; + $html .= '
    '; + $html .= '
    '; + $html .= '
    '; + $html .= ''; + $html .= ''; + $html .= '
    '; + $html .= '
    '; + + return $html; +} + +/** + * Gets HTML for other mult_submits actions + * + * @param string $what mult_submit type + * @param string $action action type + * @param array $_url_params URL params + * @param array $full_query full sql query string + * + * @return string + */ +function PMA_getHtmlForOtherActions($what, $action, $_url_params, $full_query) +{ + $html = '
    '; + $html .= ''; + if ($what == 'drop_db') { + $html .= __('You are about to DESTROY a complete database!') . ' '; + } + $html .= __('Do you really want to execute the following query?'); + $html .= ''; + $html .= '' . $full_query . ''; + $html .= '
    '; + $html .= '
    '; + $html .= '
    '; + $html .= PMA_URL_getHiddenInputs($_url_params); + // Display option to disable foreign key checks while dropping tables + if ($what == 'drop_tbl') { + $html .= '
    '; + $html .= ''; + $html .= __('Foreign key check:'); + $html .= ''; + $html .= ''; + $html .= 'fetchValue( + 'SHOW VARIABLES LIKE \'foreign_key_checks\';', 0, 1 + ) == 'ON'; + if ($default_fk_check_value) { + $html .= ' checked="checked"'; + } + $html .= '/>'; + $html .= ''; + $html .= ($default_fk_check_value) ? __('(Enabled)') : __('(Disabled)'); + $html .= ''; + $html .= '
    '; + } + $html .= ''; + $html .= ''; + $html .= '
    '; + + $html .= '
    '; + $html .= PMA_URL_getHiddenInputs($_url_params); + $html .= ''; + $html .= ''; + $html .= '
    '; + $html .= '
    '; + + return $html; +} + +/** + * Get List of information for Submit Mult + * + * @param string $submit_mult mult_submit type + * @param string $db dtabase name + * @param array $table table name + * @param array $selected the selected columns + * @param array $action action type + * + * @return array() + */ +function PMA_getDataForSubmitMult($submit_mult, $db, $table, $selected, $action) +{ + $what = null; + $query_type = null; + $is_unset_submit_mult = false; + $mult_btn = null; + + switch ($submit_mult) { + case 'drop': + $what = 'drop_fld'; + break; + case 'primary': + // Gets table primary key + $primary = PMA_getKeyForTablePrimary($db, $table); + if (empty($primary)) { + // no primary key, so we can safely create new + $is_unset_submit_mult = true; + $query_type = 'primary_fld'; + $mult_btn = __('Yes'); + } else { + // primary key exists, so lets as user + $what = 'primary_fld'; + } + break; + case 'index': + $is_unset_submit_mult = true; + $query_type = 'index_fld'; + $mult_btn = __('Yes'); + break; + case 'unique': + $is_unset_submit_mult = true; + $query_type = 'unique_fld'; + $mult_btn = __('Yes'); + break; + case 'spatial': + $is_unset_submit_mult = true; + $query_type = 'spatial_fld'; + $mult_btn = __('Yes'); + break; + case 'ftext': + $is_unset_submit_mult = true; + $query_type = 'fulltext_fld'; + $mult_btn = __('Yes'); + break; + case 'change': + PMA_displayHtmlForColumnChange($db, $table, $selected, $action); + // execution stops here but PMA_Response correctly finishes + // the rendering + exit; + case 'browse': + // this should already be handled by tbl_structure.php + } + + return array($what, $query_type, $is_unset_submit_mult, $mult_btn); +} + +/** + * Get query string from Selected + * + * @param string $what mult_submit type + * @param string $db dtabase name + * @param array $table table name + * @param array $selected the selected columns + * @param array $action action type + * @param array $views table views + * + * @return array() + */ +function PMA_getQueryFromSelected($what, $db, $table, $selected, $action, $views) +{ + $reload = null; + $full_query_views = null; + $full_query = ''; + + if ($what == 'drop_tbl') { + $full_query_views = ''; + } + + $selected_cnt = count($selected); + $i = 0; + foreach ($selected as $idx => $sval) { + switch ($what) { + case 'row_delete': + $full_query .= 'DELETE FROM ' . PMA_Util::backquote($db) + . '.' . PMA_Util::backquote($table) + // Do not append a "LIMIT 1" clause here + // (it's not binlog friendly). + // We don't need the clause because the calling panel permits + // this feature only when there is a unique index. + . ' WHERE ' . urldecode($sval) + . ';
    '; + break; + case 'drop_db': + $full_query .= 'DROP DATABASE ' + . PMA_Util::backquote(htmlspecialchars($sval)) + . ';
    '; + $reload = 1; + break; + + case 'drop_tbl': + $current = $sval; + if (!empty($views) && in_array($current, $views)) { + $full_query_views .= (empty($full_query_views) ? 'DROP VIEW ' : ', ') + . PMA_Util::backquote(htmlspecialchars($current)); + } else { + $full_query .= (empty($full_query) ? 'DROP TABLE ' : ', ') + . PMA_Util::backquote(htmlspecialchars($current)); + } + break; + + case 'empty_tbl': + $full_query .= 'TRUNCATE '; + $full_query .= PMA_Util::backquote(htmlspecialchars($sval)) + . ';
    '; + break; + + case 'primary_fld': + if ($full_query == '') { + $full_query .= 'ALTER TABLE ' + . PMA_Util::backquote(htmlspecialchars($table)) + . '
      DROP PRIMARY KEY,' + . '
       ADD PRIMARY KEY(' + . '
         ' + . PMA_Util::backquote(htmlspecialchars($sval)) + . ','; + } else { + $full_query .= '
         ' + . PMA_Util::backquote(htmlspecialchars($sval)) + . ','; + } + if ($i == $selected_cnt-1) { + $full_query = preg_replace('@,$@', ');
    ', $full_query); + } + break; + + case 'drop_fld': + if ($full_query == '') { + $full_query .= 'ALTER TABLE ' + . PMA_Util::backquote(htmlspecialchars($table)); + } + $full_query .= '
      DROP ' + . PMA_Util::backquote(htmlspecialchars($sval)) + . ','; + if ($i == $selected_cnt - 1) { + $full_query = preg_replace('@,$@', ';
    ', $full_query); + } + break; + } // end switch + $i++; + } + + if ($what == 'drop_tbl') { + if (!empty($full_query)) { + $full_query .= ';
    ' . "\n"; + } + if (!empty($full_query_views)) { + $full_query .= $full_query_views . ';
    ' . "\n"; + } + unset($full_query_views); + } + + $full_query_views = isset($full_query_views)? $full_query_views : null; + + return array($full_query, $reload, $full_query_views); +} + +?> diff --git a/phpMyAdmin/libraries/mysql_charsets.inc.php b/phpMyAdmin/libraries/mysql_charsets.inc.php new file mode 100644 index 0000000..ea3aa29 --- /dev/null +++ b/phpMyAdmin/libraries/mysql_charsets.inc.php @@ -0,0 +1,143 @@ +query($sql); + + $mysql_charsets = array(); + while ($row = $GLOBALS['dbi']->fetchAssoc($res)) { + $mysql_charsets[] = $row['CHARACTER_SET_NAME']; + // never used + //$mysql_charsets_maxlen[$row['Charset']] = $row['Maxlen']; + $mysql_charsets_descriptions[$row['CHARACTER_SET_NAME']] + = $row['DESCRIPTION']; + } + $GLOBALS['dbi']->freeResult($res); + + sort($mysql_charsets, SORT_STRING); + + $mysql_collations = array_flip($mysql_charsets); + $mysql_default_collations = $mysql_collations_flat + = $mysql_charsets_available = $mysql_collations_available = array(); + + $sql = PMA_DRIZZLE + ? 'SELECT * FROM data_dictionary.COLLATIONS' + : 'SELECT * FROM information_schema.COLLATIONS'; + $res = $GLOBALS['dbi']->query($sql); + while ($row = $GLOBALS['dbi']->fetchAssoc($res)) { + if (! is_array($mysql_collations[$row['CHARACTER_SET_NAME']])) { + $mysql_collations[$row['CHARACTER_SET_NAME']] + = array($row['COLLATION_NAME']); + } else { + $mysql_collations[$row['CHARACTER_SET_NAME']][] = $row['COLLATION_NAME']; + } + $mysql_collations_flat[] = $row['COLLATION_NAME']; + if ($row['IS_DEFAULT'] == 'Yes' || $row['IS_DEFAULT'] == '1') { + $mysql_default_collations[$row['CHARACTER_SET_NAME']] + = $row['COLLATION_NAME']; + } + //$mysql_collations_available[$row['Collation']] + // = ! isset($row['Compiled']) || $row['Compiled'] == 'Yes'; + $mysql_collations_available[$row['COLLATION_NAME']] = true; + $mysql_charsets_available[$row['CHARACTER_SET_NAME']] + = !empty($mysql_charsets_available[$row['CHARACTER_SET_NAME']]) + || !empty($mysql_collations_available[$row['COLLATION_NAME']]); + } + $GLOBALS['dbi']->freeResult($res); + unset($res, $row); + + if (PMA_DRIZZLE + && isset($mysql_collations['utf8_general_ci']) + && isset($mysql_collations['utf8']) + ) { + $mysql_collations['utf8'] = $mysql_collations['utf8_general_ci']; + $mysql_default_collations['utf8'] + = $mysql_default_collations['utf8_general_ci']; + $mysql_charsets_available['utf8'] + = $mysql_charsets_available['utf8_general_ci']; + unset( + $mysql_collations['utf8_general_ci'], + $mysql_default_collations['utf8_general_ci'], + $mysql_charsets_available['utf8_general_ci'] + ); + } + + sort($mysql_collations_flat, SORT_STRING); + foreach ($mysql_collations as $key => $value) { + sort($mysql_collations[$key], SORT_STRING); + reset($mysql_collations[$key]); + } + unset($key, $value); + + PMA_Util::cacheSet( + 'mysql_charsets', $GLOBALS['mysql_charsets'], true + ); + PMA_Util::cacheSet( + 'mysql_charsets_descriptions', $GLOBALS['mysql_charsets_descriptions'], true + ); + PMA_Util::cacheSet( + 'mysql_charsets_available', $GLOBALS['mysql_charsets_available'], true + ); + PMA_Util::cacheSet( + 'mysql_collations', $GLOBALS['mysql_collations'], true + ); + PMA_Util::cacheSet( + 'mysql_default_collations', $GLOBALS['mysql_default_collations'], true + ); + PMA_Util::cacheSet( + 'mysql_collations_flat', $GLOBALS['mysql_collations_flat'], true + ); + PMA_Util::cacheSet( + 'mysql_collations_available', $GLOBALS['mysql_collations_available'], true + ); +} else { + $GLOBALS['mysql_charsets'] = PMA_Util::cacheGet( + 'mysql_charsets', true + ); + $GLOBALS['mysql_charsets_descriptions'] = PMA_Util::cacheGet( + 'mysql_charsets_descriptions', true + ); + $GLOBALS['mysql_charsets_available'] = PMA_Util::cacheGet( + 'mysql_charsets_available', true + ); + $GLOBALS['mysql_collations'] = PMA_Util::cacheGet( + 'mysql_collations', true + ); + $GLOBALS['mysql_default_collations'] = PMA_Util::cacheGet( + 'mysql_default_collations', true + ); + $GLOBALS['mysql_collations_flat'] = PMA_Util::cacheGet( + 'mysql_collations_flat', true + ); + $GLOBALS['mysql_collations_available'] = PMA_Util::cacheGet( + 'mysql_collations_available', true + ); +} + +define('PMA_CSDROPDOWN_COLLATION', 0); +define('PMA_CSDROPDOWN_CHARSET', 1); + +/** + * shared functions for mysql charsets + */ +require_once './libraries/mysql_charsets.lib.php'; + +?> diff --git a/phpMyAdmin/libraries/mysql_charsets.lib.php b/phpMyAdmin/libraries/mysql_charsets.lib.php index 5af1bf7..3a88ec0 100644 --- a/phpMyAdmin/libraries/mysql_charsets.lib.php +++ b/phpMyAdmin/libraries/mysql_charsets.lib.php @@ -1,6 +1,7 @@ $value) { - sort($mysql_collations[$key], SORT_STRING); - reset($mysql_collations[$key]); - } - unset($key, $value); - - PMA_cacheSet('mysql_charsets', $GLOBALS['mysql_charsets'], true); - PMA_cacheSet('mysql_charsets_descriptions', $GLOBALS['mysql_charsets_descriptions'], true); - PMA_cacheSet('mysql_charsets_available', $GLOBALS['mysql_charsets_available'], true); - PMA_cacheSet('mysql_collations', $GLOBALS['mysql_collations'], true); - PMA_cacheSet('mysql_default_collations', $GLOBALS['mysql_default_collations'], true); - PMA_cacheSet('mysql_collations_flat', $GLOBALS['mysql_collations_flat'], true); - PMA_cacheSet('mysql_collations_available', $GLOBALS['mysql_collations_available'], true); -} else { - $GLOBALS['mysql_charsets'] = PMA_cacheGet('mysql_charsets', true); - $GLOBALS['mysql_charsets_descriptions'] = PMA_cacheGet('mysql_charsets_descriptions', true); - $GLOBALS['mysql_charsets_available'] = PMA_cacheGet('mysql_charsets_available', true); - $GLOBALS['mysql_collations'] = PMA_cacheGet('mysql_collations', true); - $GLOBALS['mysql_default_collations'] = PMA_cacheGet('mysql_default_collations', true); - $GLOBALS['mysql_collations_flat'] = PMA_cacheGet('mysql_collations_flat', true); - $GLOBALS['mysql_collations_available'] = PMA_cacheGet('mysql_collations_available', true); -} - -define('PMA_CSDROPDOWN_COLLATION', 0); -define('PMA_CSDROPDOWN_CHARSET', 1); - function PMA_generateCharsetDropdownBox($type = PMA_CSDROPDOWN_COLLATION, $name = null, $id = null, $default = null, $label = true, $indent = 0, - $submitOnChange = false, $displayUnavailable = false) -{ + $submitOnChange = false, $displayUnavailable = false +) { global $mysql_charsets, $mysql_charsets_descriptions, $mysql_charsets_available, $mysql_collations, $mysql_collations_available; @@ -104,7 +24,7 @@ function PMA_generateCharsetDropdownBox($type = PMA_CSDROPDOWN_COLLATION, } } - $return_str = ' 9 + ) { + $placeholder_key = 'placeholder'; + } + $retval .= " $placeholder_key='" + . __('Filter databases by name or regex'); + $retval .= "' />"; + $retval .= 'X'; + $retval .= ""; + $retval .= ""; + $retval .= ""; + } else if (($node->type == Node::CONTAINER + && ( $node->real_name == 'tables' + || $node->real_name == 'views' + || $node->real_name == 'functions' + || $node->real_name == 'procedures' + || $node->real_name == 'events')) + && method_exists($node->realParent(), 'getPresence') + && $node->realParent()->getPresence($node->real_name) >= $filter_min + ) { + $paths = $node->getPaths(); + $url_params = array( + 'pos' => $this->_pos, + 'aPath' => $paths['aPath'], + 'vPath' => $paths['vPath'], + 'pos2_name' => $node->real_name, + 'pos2_value' => 0 + ); + $retval .= "
  • "; + $retval .= "
    "; + $retval .= PMA_getHiddenFields($url_params); + $retval .= " 9 + ) { + $placeholder_key = 'placeholder'; + } + $retval .= " $placeholder_key='" + . __('Filter by name or regex') . "' />"; + $retval .= "X"; + $retval .= "
    "; + $retval .= "
  • "; + } + return $retval; + } + + /** + * Generates the HTML code for displaying the list pagination + * + * @param Node $node The node for whose children the page + * selector will be created + * + * @return string + */ + private function _getPageSelector($node) + { + $retval = ''; + if ($node === $this->_tree) { + $retval .= PMA_Util::getListNavigator( + $this->_tree->getPresence('databases', $this->_searchClause), + $this->_pos, + array('server' => $GLOBALS['server']), + 'navigation.php', + 'frame_navigation', + $GLOBALS['cfg']['MaxNavigationItems'], + 'pos', + array('dbselector') + ); + } else if ($node->type == Node::CONTAINER && ! $node->is_group) { + $paths = $node->getPaths(); + + $level = isset($paths['aPath_clean'][4]) ? 3 : 2; + $_url_params = array( + 'aPath' => $paths['aPath'], + 'vPath' => $paths['vPath'], + 'pos' => $this->_pos, + 'server' => $GLOBALS['server'], + 'pos2_name' => $paths['aPath_clean'][2] + ); + if ($level == 3) { + $pos = $node->pos3; + $_url_params['pos2_value'] = $node->pos2; + $_url_params['pos3_name'] = $paths['aPath_clean'][4]; + } else { + $pos = $node->pos2; + } + $num = $node->realParent()->getPresence( + $node->real_name, + $this->_searchClause2 + ); + $retval .= PMA_Util::getListNavigator( + $num, + $pos, + $_url_params, + 'navigation.php', + 'frame_navigation', + $GLOBALS['cfg']['MaxNavigationItems'], + 'pos' . $level . '_value' + ); + } + return $retval; + } + + /** + * Called by usort() for sorting the nodes in a container + * + * @param Node $a The first element used in the comparison + * @param Node $b The second element used in the comparison + * + * @return int See strnatcmp() and strcmp() + */ + static public function sortNode($a, $b) + { + if ($a->isNew) { + return -1; + } else if ($b->isNew) { + return 1; + } + if ($GLOBALS['cfg']['NaturalOrder']) { + return strnatcasecmp($a->name, $b->name); + } else { + return strcasecmp($a->name, $b->name); + } + } +} +?> diff --git a/phpMyAdmin/libraries/navigation/NodeFactory.class.php b/phpMyAdmin/libraries/navigation/NodeFactory.class.php new file mode 100644 index 0000000..f561fb8 --- /dev/null +++ b/phpMyAdmin/libraries/navigation/NodeFactory.class.php @@ -0,0 +1,97 @@ + diff --git a/phpMyAdmin/libraries/navigation/Nodes/Node.class.php b/phpMyAdmin/libraries/navigation/Nodes/Node.class.php new file mode 100644 index 0000000..583f28b --- /dev/null +++ b/phpMyAdmin/libraries/navigation/Nodes/Node.class.php @@ -0,0 +1,441 @@ +name = $name; + $this->real_name = $name; + } + if ($type === Node::CONTAINER) { + $this->type = Node::CONTAINER; + } + $this->is_group = (bool)$is_group; + } + + /** + * Adds a child node to this node + * + * @param Node $child A child node + * + * @return void + */ + public function addChild($child) + { + $this->children[] = $child; + $child->parent = $this; + } + + /** + * Returns a child node given it's name + * + * @param string $name The name of requested child + * @param bool $real_name Whether to use the "real_name" + * instead of "name" in comparisons + * + * @return false|Node The requested child node or false, + * if the requested node cannot be found + */ + public function getChild($name, $real_name = false) + { + if ($real_name) { + foreach ($this->children as $child) { + if ($child->real_name == $name) { + return $child; + } + } + } else { + foreach ($this->children as $child) { + if ($child->name == $name) { + return $child; + } + } + } + return false; + } + + /** + * Removes a child node from this node + * + * @param string $name The name of child to be removed + * + * @return void + */ + public function removeChild($name) + { + foreach ($this->children as $key => $child) { + if ($child->name == $name) { + unset($this->children[$key]); + break; + } + } + } + + /** + * Retreives the parents for a node + * + * @param bool $self Whether to include the Node itself in the results + * @param bool $containers Whether to include nodes of type CONTAINER + * @param bool $groups Whether to include nodes which have $group == true + * + * @return array An array of parent Nodes + */ + public function parents($self = false, $containers = false, $groups = false) + { + $parents = array(); + if ($self + && ($this->type != Node::CONTAINER || $containers) + && ($this->is_group != true || $groups) + ) { + $parents[] = $this; + $self = false; + } + $parent = $this->parent; + while (isset($parent)) { + if ( ($parent->type != Node::CONTAINER || $containers) + && ($parent->is_group != true || $groups) + ) { + $parents[] = $parent; + } + $parent = $parent->parent; + } + return $parents; + } + + /** + * Returns the actual parent of a node. If used twice on an index or columns + * node, it will return the table and database nodes. The names of the returned + * nodes can be used in SQL queries, etc... + * + * @return Node + */ + public function realParent() + { + $retval = $this->parents(); + if (count($retval) > 0) { + return $retval[0]; + } else { + return false; + } + } + + /** + * This function checks if the node has children nodes associated with it + * + * @param bool $count_empty_containers Whether to count empty child + * containers as valid children + * + * @return bool Whether the node has child nodes + */ + public function hasChildren($count_empty_containers = true) + { + $retval = false; + if ($count_empty_containers) { + if (count($this->children)) { + $retval = true; + } + } else { + foreach ($this->children as $child) { + if ($child->type == Node::OBJECT || $child->hasChildren(false)) { + $retval = true; + break; + } + } + } + return $retval; + } + + /** + * Returns true the node has some siblings (other nodes on the same tree level, + * in the same branch), false otherwise. The only exception is for nodes on + * the third level of the tree (columns and indexes), for which the function + * always returns true. This is because we want to render the containers + * for these nodes + * + * @return bool + */ + public function hasSiblings() + { + $retval = false; + $paths = $this->getPaths(); + if (count($paths['aPath_clean']) > 3) { + $retval = true; + } else { + foreach ($this->parent->children as $child) { + if ($child !== $this + && ($child->type == Node::OBJECT || $child->hasChildren(false)) + ) { + $retval = true; + break; + } + } + } + return $retval; + } + + /** + * Returns the number of child nodes that a node has associated with it + * + * @return int The number of children nodes + */ + public function numChildren() + { + $retval = 0; + foreach ($this->children as $child) { + if ($child->type == Node::OBJECT) { + $retval++; + } else { + $retval += $child->numChildren(); + } + } + return $retval; + } + + /** + * Returns the actual path and the virtual paths for a node + * both as clean arrays and base64 encoded strings + * + * @return array + */ + public function getPaths() + { + $aPath = array(); + $aPath_clean = array(); + foreach ($this->parents(true, true, false) as $parent) { + $aPath[] = base64_encode($parent->real_name); + $aPath_clean[] = $parent->real_name; + } + $aPath = implode('.', array_reverse($aPath)); + $aPath_clean = array_reverse($aPath_clean); + + $vPath = array(); + $vPath_clean = array(); + foreach ($this->parents(true, true, true) as $parent) { + $vPath[] = base64_encode($parent->name); + $vPath_clean[] = $parent->name; + } + $vPath = implode('.', array_reverse($vPath)); + $vPath_clean = array_reverse($vPath_clean); + + return array( + 'aPath' => $aPath, + 'aPath_clean' => $aPath_clean, + 'vPath' => $vPath, + 'vPath_clean' => $vPath_clean + ); + } + + /** + * Returns the names of children of type $type present inside this container + * This method is overridden by the Node_Database and Node_Table classes + * + * @param string $type The type of item we are looking for + * ('tables', 'views', etc) + * @param int $pos The offset of the list within the results + * @param string $searchClause A string used to filter the results of the query + * + * @return array + */ + public function getData($type, $pos, $searchClause = '') + { + $query = "SELECT `SCHEMA_NAME` "; + $query .= "FROM `INFORMATION_SCHEMA`.`SCHEMATA` "; + $query .= $this->_getWhereClause($searchClause); + $query .= "ORDER BY `SCHEMA_NAME` ASC "; + $query .= "LIMIT $pos, {$GLOBALS['cfg']['MaxNavigationItems']}"; + return $GLOBALS['dbi']->fetchResult($query); + + } + + /** + * Returns the number of children of type $type present inside this container + * This method is overridden by the Node_Database and Node_Table classes + * + * @param string $type The type of item we are looking for + * ('tables', 'views', etc) + * @param string $searchClause A string used to filter the results of the query + * + * @return int + */ + public function getPresence($type = '', $searchClause = '') + { + $query = "SELECT COUNT(*) "; + $query .= "FROM `INFORMATION_SCHEMA`.`SCHEMATA` "; + $query .= $this->_getWhereClause($searchClause); + $retval = (int)$GLOBALS['dbi']->fetchValue($query); + return $retval; + } + + /** + * Returns the WHERE clause depending on the $searchClause parameter + * and the hide_db directive + * + * @param string $searchClause A string used to filter the results of the query + * + * @return string + */ + private function _getWhereClause($searchClause = '') + { + $whereClause = "WHERE TRUE "; + if (! empty($searchClause)) { + $whereClause .= "AND `SCHEMA_NAME` LIKE '%"; + $whereClause .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $whereClause .= "%' "; + } + + if (! empty($GLOBALS['cfg']['Server']['hide_db'])) { + $whereClause .= "AND `SCHEMA_NAME` NOT REGEXP '" + . $GLOBALS['cfg']['Server']['hide_db'] . "' "; + } + + if (! empty($GLOBALS['cfg']['Server']['only_db'])) { + if (is_string($GLOBALS['cfg']['Server']['only_db'])) { + $GLOBALS['cfg']['Server']['only_db'] = array( + $GLOBALS['cfg']['Server']['only_db'] + ); + } + $whereClause .= "AND ("; + $subClauses = array(); + foreach ($GLOBALS['cfg']['Server']['only_db'] as $each_only_db) { + $subClauses[] = " `SCHEMA_NAME` LIKE '" + . $each_only_db . "' "; + } + $whereClause .= implode("OR", $subClauses) . ")"; + } + return $whereClause; + } + + /** + * Returns HTML for control buttons displayed infront of a node + * + * @return String HTML for control buttons + */ + public function getHtmlForControlButtons() + { + return ''; + } +} +?> diff --git a/phpMyAdmin/libraries/navigation/Nodes/Node_Column.class.php b/phpMyAdmin/libraries/navigation/Nodes/Node_Column.class.php new file mode 100644 index 0000000..2458aee --- /dev/null +++ b/phpMyAdmin/libraries/navigation/Nodes/Node_Column.class.php @@ -0,0 +1,46 @@ +icon = PMA_Util::getImage('pause.png', __('Column')); + $this->links = array( + 'text' => 'tbl_structure.php?server=' . $GLOBALS['server'] + . '&db=%3$s&table=%2$s&field=%1$s' + . '&change_column=1' + . '&token=' . $GLOBALS['token'], + 'icon' => 'tbl_structure.php?server=' . $GLOBALS['server'] + . '&db=%3$s&table=%2$s&field=%1$s' + . '&change_column=1' + . '&token=' . $GLOBALS['token'] + ); + } +} + +?> diff --git a/phpMyAdmin/libraries/navigation/Nodes/Node_Column_Container.class.php b/phpMyAdmin/libraries/navigation/Nodes/Node_Column_Container.class.php new file mode 100644 index 0000000..3bb1462 --- /dev/null +++ b/phpMyAdmin/libraries/navigation/Nodes/Node_Column_Container.class.php @@ -0,0 +1,57 @@ +icon = PMA_Util::getImage('pause.png', __('Columns')); + $this->links = array( + 'text' => 'tbl_structure.php?server=' . $GLOBALS['server'] + . '&db=%2$s&table=%1$s' + . '&token=' . $GLOBALS['token'], + 'icon' => 'tbl_structure.php?server=' . $GLOBALS['server'] + . '&db=%2$s&table=%1$s' + . '&token=' . $GLOBALS['token'], + ); + $this->real_name = 'columns'; + + $new_label = _pgettext('Create new column', 'New'); + $new = PMA_NodeFactory::getInstance('Node', $new_label); + $new->isNew = true; + $new->icon = PMA_Util::getImage('b_column_add.png', $new_label); + $new->links = array( + 'text' => 'tbl_addfield.php?server=' . $GLOBALS['server'] + . '&db=%3$s&table=%2$s' + . '&field_where=last&after_field=' + . '&token=' . $GLOBALS['token'], + 'icon' => 'tbl_addfield.php?server=' . $GLOBALS['server'] + . '&db=%3$s&table=%2$s' + . '&field_where=last&after_field=' + . '&token=' . $GLOBALS['token'], + ); + $new->classes = 'new_column italics'; + $this->addChild($new); + } +} + +?> diff --git a/phpMyAdmin/libraries/navigation/Nodes/Node_Database.class.php b/phpMyAdmin/libraries/navigation/Nodes/Node_Database.class.php new file mode 100644 index 0000000..7a445ab --- /dev/null +++ b/phpMyAdmin/libraries/navigation/Nodes/Node_Database.class.php @@ -0,0 +1,327 @@ +icon = PMA_Util::getImage( + 's_db.png', + __('Database operations') + ); + $this->links = array( + 'text' => $GLOBALS['cfg']['DefaultTabDatabase'] + . '?server=' . $GLOBALS['server'] + . '&db=%1$s&token=' . $GLOBALS['token'], + 'icon' => 'db_operations.php?server=' . $GLOBALS['server'] + . '&db=%1$s&token=' . $GLOBALS['token'] + ); + $this->classes = 'database'; + } + + /** + * Returns the number of children of type $type present inside this container + * This method is overridden by the Node_Database and Node_Table classes + * + * @param string $type The type of item we are looking for + * ('tables', 'views', etc) + * @param string $searchClause A string used to filter the results of the query + * + * @return int + */ + public function getPresence($type = '', $searchClause = '') + { + $retval = 0; + $db = $this->real_name; + switch ($type) { + case 'tables': + $db = PMA_Util::sqlAddSlashes($db); + $query = "SELECT COUNT(*) "; + $query .= "FROM `INFORMATION_SCHEMA`.`TABLES` "; + $query .= "WHERE `TABLE_SCHEMA`='$db' "; + if (PMA_DRIZZLE) { + $query .= "AND `TABLE_TYPE`='BASE' "; + } else { + $query .= "AND `TABLE_TYPE`='BASE TABLE' "; + } + if (! empty($searchClause)) { + $query .= "AND `TABLE_NAME` LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $retval = (int)$GLOBALS['dbi']->fetchValue($query); + break; + case 'views': + $db = PMA_Util::sqlAddSlashes($db); + $query = "SELECT COUNT(*) "; + $query .= "FROM `INFORMATION_SCHEMA`.`TABLES` "; + $query .= "WHERE `TABLE_SCHEMA`='$db' "; + if (PMA_DRIZZLE) { + $query .= "AND `TABLE_TYPE`!='BASE' "; + } else { + $query .= "AND `TABLE_TYPE`!='BASE TABLE' "; + } + if (! empty($searchClause)) { + $query .= "AND `TABLE_NAME` LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $retval = (int)$GLOBALS['dbi']->fetchValue($query); + break; + case 'procedures': + $db = PMA_Util::sqlAddSlashes($db); + $query = "SELECT COUNT(*) "; + $query .= "FROM `INFORMATION_SCHEMA`.`ROUTINES` "; + $query .= "WHERE `ROUTINE_SCHEMA`='$db'"; + $query .= "AND `ROUTINE_TYPE`='PROCEDURE' "; + if (! empty($searchClause)) { + $query .= "AND `ROUTINE_NAME` LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $retval = (int)$GLOBALS['dbi']->fetchValue($query); + break; + case 'functions': + $db = PMA_Util::sqlAddSlashes($db); + $query = "SELECT COUNT(*) "; + $query .= "FROM `INFORMATION_SCHEMA`.`ROUTINES` "; + $query .= "WHERE `ROUTINE_SCHEMA`='$db' "; + $query .= "AND `ROUTINE_TYPE`='FUNCTION' "; + if (! empty($searchClause)) { + $query .= "AND `ROUTINE_NAME` LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $retval = (int)$GLOBALS['dbi']->fetchValue($query); + break; + case 'events': + $db = PMA_Util::sqlAddSlashes($db); + $query = "SELECT COUNT(*) "; + $query .= "FROM `INFORMATION_SCHEMA`.`EVENTS` "; + $query .= "WHERE `EVENT_SCHEMA`='$db' "; + if (! empty($searchClause)) { + $query .= "AND `EVENT_NAME` LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $retval = (int)$GLOBALS['dbi']->fetchValue($query); + break; + default: + break; + } + return $retval; + } + + /** + * Returns the names of children of type $type present inside this container + * This method is overridden by the Node_Database and Node_Table classes + * + * @param string $type The type of item we are looking for + * ('tables', 'views', etc) + * @param int $pos The offset of the list within the results + * @param string $searchClause A string used to filter the results of the query + * + * @return array + */ + public function getData($type, $pos, $searchClause = '') + { + $maxItems = $GLOBALS['cfg']['MaxNavigationItems']; + $retval = array(); + $db = $this->real_name; + switch ($type) { + case 'tables': + $escdDb = PMA_Util::sqlAddSlashes($db); + $query = "SELECT `TABLE_NAME` AS `name` "; + $query .= "FROM `INFORMATION_SCHEMA`.`TABLES` "; + $query .= "WHERE `TABLE_SCHEMA`='$escdDb' "; + if (PMA_DRIZZLE) { + $query .= "AND `TABLE_TYPE`='BASE' "; + } else { + $query .= "AND `TABLE_TYPE`='BASE TABLE' "; + } + if (! empty($searchClause)) { + $query .= "AND `TABLE_NAME` LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $query .= "ORDER BY `TABLE_NAME` ASC "; + $query .= "LIMIT " . intval($pos) . ", $maxItems"; + $retval = $GLOBALS['dbi']->fetchResult($query); + break; + case 'views': + $escdDb = PMA_Util::sqlAddSlashes($db); + $query = "SELECT `TABLE_NAME` AS `name` "; + $query .= "FROM `INFORMATION_SCHEMA`.`TABLES` "; + $query .= "WHERE `TABLE_SCHEMA`='$escdDb' "; + if (PMA_DRIZZLE) { + $query .= "AND `TABLE_TYPE`!='BASE' "; + } else { + $query .= "AND `TABLE_TYPE`!='BASE TABLE' "; + } + if (! empty($searchClause)) { + $query .= "AND `TABLE_NAME` LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $query .= "ORDER BY `TABLE_NAME` ASC "; + $query .= "LIMIT " . intval($pos) . ", $maxItems"; + $retval = $GLOBALS['dbi']->fetchResult($query); + break; + case 'procedures': + $escdDb = PMA_Util::sqlAddSlashes($db); + $query = "SELECT `ROUTINE_NAME` AS `name` "; + $query .= "FROM `INFORMATION_SCHEMA`.`ROUTINES` "; + $query .= "WHERE `ROUTINE_SCHEMA`='$escdDb'"; + $query .= "AND `ROUTINE_TYPE`='PROCEDURE' "; + if (! empty($searchClause)) { + $query .= "AND `ROUTINE_NAME` LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $query .= "ORDER BY `ROUTINE_NAME` ASC "; + $query .= "LIMIT " . intval($pos) . ", $maxItems"; + $retval = $GLOBALS['dbi']->fetchResult($query); + break; + case 'functions': + $escdDb = PMA_Util::sqlAddSlashes($db); + $query = "SELECT `ROUTINE_NAME` AS `name` "; + $query .= "FROM `INFORMATION_SCHEMA`.`ROUTINES` "; + $query .= "WHERE `ROUTINE_SCHEMA`='$escdDb' "; + $query .= "AND `ROUTINE_TYPE`='FUNCTION' "; + if (! empty($searchClause)) { + $query .= "AND `ROUTINE_NAME` LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $query .= "ORDER BY `ROUTINE_NAME` ASC "; + $query .= "LIMIT " . intval($pos) . ", $maxItems"; + $retval = $GLOBALS['dbi']->fetchResult($query); + break; + case 'events': + $escdDb = PMA_Util::sqlAddSlashes($db); + $query = "SELECT `EVENT_NAME` AS `name` "; + $query .= "FROM `INFORMATION_SCHEMA`.`EVENTS` "; + $query .= "WHERE `EVENT_SCHEMA`='$escdDb' "; + if (! empty($searchClause)) { + $query .= "AND `EVENT_NAME` LIKE '%"; + $query .= PMA_Util::sqlAddSlashes( + $searchClause, true + ); + $query .= "%'"; + } + $query .= "ORDER BY `EVENT_NAME` ASC "; + $query .= "LIMIT " . intval($pos) . ", $maxItems"; + $retval = $GLOBALS['dbi']->fetchResult($query); + break; + default: + break; + } + + // Remove hidden items so that they are not displayed in navigation tree + $cfgRelation = PMA_getRelationsParam(); + if ($cfgRelation['navwork']) { + $navTable = PMA_Util::backquote($cfgRelation['db']) + . "." . PMA_Util::backquote($cfgRelation['navigationhiding']); + $sqlQuery = "SELECT `item_name` FROM " . $navTable + . " WHERE `username`='" . $cfgRelation['user'] . "'" + . " AND `item_type`='" . substr($type, 0, -1) . "'" + . " AND `db_name`='" . PMA_Util::sqlAddSlashes($db) . "'"; + $result = PMA_queryAsControlUser($sqlQuery, false); + if ($result) { + $hiddenItems = array(); + while ($row = $GLOBALS['dbi']->fetchArray($result)) { + $hiddenItems[] = $row[0]; + } + foreach ($retval as $key => $item) { + if (in_array($item, $hiddenItems)) { + unset($retval[$key]); + } + } + } + $GLOBALS['dbi']->freeResult($result); + } + + return $retval; + } + + /** + * Returns HTML for show hidden button displayed infront of database node + * + * @return String HTML for show hidden button + */ + public function getHtmlForControlButtons() + { + $ret = ''; + $db = $this->real_name; + + $cfgRelation = PMA_getRelationsParam(); + if ($cfgRelation['navwork']) { + $navTable = PMA_Util::backquote($cfgRelation['db']) + . "." . PMA_Util::backquote($cfgRelation['navigationhiding']); + $sqlQuery = "SELECT COUNT(*) FROM " . $navTable + . " WHERE `username`='" + . PMA_Util::sqlAddSlashes($GLOBALS['cfg']['Server']['user']) ."'" + . " AND `db_name`='" . PMA_Util::sqlAddSlashes($db) . "'"; + $count = $GLOBALS['dbi']->fetchValue( + $sqlQuery, 0, 0, $GLOBALS['controllink'] + ); + if ($count > 0) { + $ret = '' + . '' + . PMA_Util::getImage( + 'lightbulb.png', __('Show hidden items') + ) + . ''; + } + } + return $ret; + } +} + +?> diff --git a/phpMyAdmin/libraries/navigation/Nodes/Node_DatabaseChild.class.php b/phpMyAdmin/libraries/navigation/Nodes/Node_DatabaseChild.class.php new file mode 100644 index 0000000..36e8a37 --- /dev/null +++ b/phpMyAdmin/libraries/navigation/Nodes/Node_DatabaseChild.class.php @@ -0,0 +1,52 @@ +realParent()->real_name; + $item = $this->real_name; + $ret = '' + . '' + . PMA_Util::getImage('lightbulb_off', __('Hide')) + . ''; + } + return $ret; + } + + /** + * Returns the type of the item reprsented by the node. + * + * @return string type of the item + */ + protected abstract function getItemType(); +} +?> diff --git a/phpMyAdmin/libraries/navigation/Nodes/Node_Database_Container.class.php b/phpMyAdmin/libraries/navigation/Nodes/Node_Database_Container.class.php new file mode 100644 index 0000000..6396b03 --- /dev/null +++ b/phpMyAdmin/libraries/navigation/Nodes/Node_Database_Container.class.php @@ -0,0 +1,47 @@ +isNew = $GLOBALS['is_create_db_priv']; + $new->icon = PMA_Util::getImage('b_newdb.png', ''); + $new->links = array( + 'text' => 'server_databases.php?server=' . $GLOBALS['server'] + . '&token=' . $GLOBALS['token'], + 'icon' => 'server_databases.php?server=' . $GLOBALS['server'] + . '&token=' . $GLOBALS['token'], + ); + $new->classes = 'new_database italics'; + $this->addChild($new); + } +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/navigation/Nodes/Node_Event.class.php b/phpMyAdmin/libraries/navigation/Nodes/Node_Event.class.php new file mode 100644 index 0000000..7df1f88 --- /dev/null +++ b/phpMyAdmin/libraries/navigation/Nodes/Node_Event.class.php @@ -0,0 +1,57 @@ +icon = PMA_Util::getImage('b_events.png'); + $this->links = array( + 'text' => 'db_events.php?server=' . $GLOBALS['server'] + . '&db=%2$s&item_name=%1$s&edit_item=1' + . '&token=' . $GLOBALS['token'], + 'icon' => 'db_events.php?server=' . $GLOBALS['server'] + . '&db=%2$s&item_name=%1$s&export_item=1' + . '&token=' . $GLOBALS['token'] + ); + $this->classes = 'event'; + } + + /** + * Returns the type of the item represented by the node. + * + * @return string type of the item + */ + protected function getItemType() + { + return 'event'; + } +} + +?> diff --git a/phpMyAdmin/libraries/navigation/Nodes/Node_Event_Container.class.php b/phpMyAdmin/libraries/navigation/Nodes/Node_Event_Container.class.php new file mode 100644 index 0000000..cc66db8 --- /dev/null +++ b/phpMyAdmin/libraries/navigation/Nodes/Node_Event_Container.class.php @@ -0,0 +1,54 @@ +icon = PMA_Util::getImage('b_events.png', ''); + $this->links = array( + 'text' => 'db_events.php?server=' . $GLOBALS['server'] + . '&db=%1$s&token=' . $GLOBALS['token'], + 'icon' => 'db_events.php?server=' . $GLOBALS['server'] + . '&db=%1$s&token=' . $GLOBALS['token'], + ); + $this->real_name = 'events'; + + $new = PMA_NodeFactory::getInstance( + 'Node', _pgettext('Create new event', 'New') + ); + $new->isNew = true; + $new->icon = PMA_Util::getImage('b_event_add.png', ''); + $new->links = array( + 'text' => 'db_events.php?server=' . $GLOBALS['server'] + . '&db=%2$s&token=' . $GLOBALS['token'] + . '&add_item=1', + 'icon' => 'db_events.php?server=' . $GLOBALS['server'] + . '&db=%2$s&token=' . $GLOBALS['token'] + . '&add_item=1', + ); + $new->classes = 'new_event italics'; + $this->addChild($new); + } +} + +?> diff --git a/phpMyAdmin/libraries/navigation/Nodes/Node_Function.class.php b/phpMyAdmin/libraries/navigation/Nodes/Node_Function.class.php new file mode 100644 index 0000000..c068e49 --- /dev/null +++ b/phpMyAdmin/libraries/navigation/Nodes/Node_Function.class.php @@ -0,0 +1,57 @@ +icon = PMA_Util::getImage('b_routines.png', __('Function')); + $this->links = array( + 'text' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%2$s&item_name=%1$s&item_type=FUNCTION' + . '&edit_item=1&token=' . $GLOBALS['token'], + 'icon' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%2$s&item_name=%1$s&item_type=FUNCTION' + . '&export_item=1&token=' . $GLOBALS['token'] + ); + $this->classes = 'function'; + } + + /** + * Returns the type of the item represented by the node. + * + * @return string type of the item + */ + protected function getItemType() + { + return 'function'; + } +} + +?> diff --git a/phpMyAdmin/libraries/navigation/Nodes/Node_Function_Container.class.php b/phpMyAdmin/libraries/navigation/Nodes/Node_Function_Container.class.php new file mode 100644 index 0000000..6a571ff --- /dev/null +++ b/phpMyAdmin/libraries/navigation/Nodes/Node_Function_Container.class.php @@ -0,0 +1,53 @@ +icon = PMA_Util::getImage('b_routines.png', __('Functions')); + $this->links = array( + 'text' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%1$s&token=' . $GLOBALS['token'] + . '&type=FUNCTION', + 'icon' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%1$s&token=' . $GLOBALS['token'] + . '&type=FUNCTION', + ); + $this->real_name = 'functions'; + + $new_label = _pgettext('Create new function', 'New'); + $new = PMA_NodeFactory::getInstance('Node', $new_label); + $new->isNew = true; + $new->icon = PMA_Util::getImage('b_routine_add.png', $new_label); + $new->links = array( + 'text' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%2$s&token=' . $GLOBALS['token'] + . '&add_item=1&item_type=FUNCTION', + 'icon' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%2$s&token=' . $GLOBALS['token'] + . '&add_item=1&item_type=FUNCTION', + ); + $new->classes = 'new_function italics'; + $this->addChild($new); + } +} + +?> diff --git a/phpMyAdmin/libraries/navigation/Nodes/Node_Index.class.php b/phpMyAdmin/libraries/navigation/Nodes/Node_Index.class.php new file mode 100644 index 0000000..15ddcb4 --- /dev/null +++ b/phpMyAdmin/libraries/navigation/Nodes/Node_Index.class.php @@ -0,0 +1,45 @@ +icon = PMA_Util::getImage('b_index.png', __('Index')); + $this->links = array( + 'text' => 'tbl_indexes.php?server=' . $GLOBALS['server'] + . '&db=%3$s&table=%2$s&index=%1$s' + . '&token=' . $GLOBALS['token'], + 'icon' => 'tbl_indexes.php?server=' . $GLOBALS['server'] + . '&db=%3$s&table=%2$s&index=%1$s' + . '&token=' . $GLOBALS['token'] + ); + $this->classes = 'index'; + } +} + +?> diff --git a/phpMyAdmin/libraries/navigation/Nodes/Node_Index_Container.class.php b/phpMyAdmin/libraries/navigation/Nodes/Node_Index_Container.class.php new file mode 100644 index 0000000..8903515 --- /dev/null +++ b/phpMyAdmin/libraries/navigation/Nodes/Node_Index_Container.class.php @@ -0,0 +1,55 @@ +icon = PMA_Util::getImage('b_index.png', __('Indexes')); + $this->links = array( + 'text' => 'tbl_structure.php?server=' . $GLOBALS['server'] + . '&db=%2$s&table=%1$s' + . '&token=' . $GLOBALS['token'], + 'icon' => 'tbl_structure.php?server=' . $GLOBALS['server'] + . '&db=%2$s&table=%1$s' + . '&token=' . $GLOBALS['token'], + ); + $this->real_name = 'indexes'; + + $new_label = _pgettext('Create new index', 'New'); + $new = PMA_NodeFactory::getInstance('Node', $new_label); + $new->isNew = true; + $new->icon = PMA_Util::getImage('b_index_add.png', $new_label); + $new->links = array( + 'text' => 'tbl_indexes.php?server=' . $GLOBALS['server'] + . '&create_index=1&added_fields=2' + . '&db=%3$s&table=%2$s&token=' . $GLOBALS['token'], + 'icon' => 'tbl_indexes.php?server=' . $GLOBALS['server'] + . '&create_index=1&added_fields=2' + . '&db=%3$s&table=%2$s&token=' . $GLOBALS['token'], + ); + $new->classes = 'new_index italics'; + $this->addChild($new); + } +} + +?> diff --git a/phpMyAdmin/libraries/navigation/Nodes/Node_Procedure.class.php b/phpMyAdmin/libraries/navigation/Nodes/Node_Procedure.class.php new file mode 100644 index 0000000..686e2d7 --- /dev/null +++ b/phpMyAdmin/libraries/navigation/Nodes/Node_Procedure.class.php @@ -0,0 +1,57 @@ +icon = PMA_Util::getImage('b_routines.png', __('Procedure')); + $this->links = array( + 'text' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%2$s&item_name=%1$s&item_type=PROCEDURE' + . '&edit_item=1&token=' . $GLOBALS['token'], + 'icon' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%2$s&item_name=%1$s&item_type=PROCEDURE' + . '&export_item=1&token=' . $GLOBALS['token'] + ); + $this->classes = 'procedure'; + } + + /** + * Returns the type of the item represented by the node. + * + * @return string type of the item + */ + protected function getItemType() + { + return 'procedure'; + } +} + +?> diff --git a/phpMyAdmin/libraries/navigation/Nodes/Node_Procedure_Container.class.php b/phpMyAdmin/libraries/navigation/Nodes/Node_Procedure_Container.class.php new file mode 100644 index 0000000..0e4fe08 --- /dev/null +++ b/phpMyAdmin/libraries/navigation/Nodes/Node_Procedure_Container.class.php @@ -0,0 +1,55 @@ +icon = PMA_Util::getImage('b_routines.png', __('Procedures')); + $this->links = array( + 'text' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%1$s&token=' . $GLOBALS['token'] + . '&type=PROCEDURE', + 'icon' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%1$s&token=' . $GLOBALS['token'] + . '&type=PROCEDURE', + ); + $this->real_name = 'procedures'; + + $new_label = _pgettext('Create new procedure', 'New'); + $new = PMA_NodeFactory::getInstance('Node', $new_label); + $new->isNew = true; + $new->icon = PMA_Util::getImage('b_routine_add.png', $new_label); + $new->links = array( + 'text' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%2$s&token=' . $GLOBALS['token'] + . '&add_item=1', + 'icon' => 'db_routines.php?server=' . $GLOBALS['server'] + . '&db=%2$s&token=' . $GLOBALS['token'] + . '&add_item=1', + ); + $new->classes = 'new_procedure italics'; + $this->addChild($new); + } +} + +?> diff --git a/phpMyAdmin/libraries/navigation/Nodes/Node_Table.class.php b/phpMyAdmin/libraries/navigation/Nodes/Node_Table.class.php new file mode 100644 index 0000000..8a398a5 --- /dev/null +++ b/phpMyAdmin/libraries/navigation/Nodes/Node_Table.class.php @@ -0,0 +1,186 @@ +icon = PMA_Util::getImage('b_props.png', __('Structure')); + break; + case 'tbl_select.php': + $this->icon = PMA_Util::getImage('b_search.png', __('Search')); + break; + case 'tbl_change.php': + $this->icon = PMA_Util::getImage('b_insrow.png', __('Insert')); + break; + case 'tbl_sql.php': + $this->icon = PMA_Util::getImage('b_sql.png', __('SQL')); + break; + case 'sql.php': + $this->icon = PMA_Util::getImage('b_browse.png', __('Browse')); + break; + } + $this->links = array( + 'text' => $GLOBALS['cfg']['DefaultTabTable'] + . '?server=' . $GLOBALS['server'] + . '&db=%2$s&table=%1$s' + . '&pos=0&token=' . $GLOBALS['token'], + 'icon' => $GLOBALS['cfg']['NavigationTreeDefaultTabTable'] + . '?server=' . $GLOBALS['server'] + . '&db=%2$s&table=%1$s&token=' . $GLOBALS['token'] + ); + $this->classes = 'table'; + } + + /** + * Returns the number of children of type $type present inside this container + * This method is overridden by the Node_Database and Node_Table classes + * + * @param string $type The type of item we are looking for + * ('columns' or 'indexes') + * @param string $searchClause A string used to filter the results of the query + * + * @return int + */ + public function getPresence($type = '', $searchClause = '') + { + $retval = 0; + $db = $this->realParent()->real_name; + $table = $this->real_name; + switch ($type) { + case 'columns': + $db = PMA_Util::sqlAddSlashes($db); + $table = PMA_Util::sqlAddSlashes($table); + $query = "SELECT COUNT(*) "; + $query .= "FROM `INFORMATION_SCHEMA`.`COLUMNS` "; + $query .= "WHERE `TABLE_NAME`='$table' "; + $query .= "AND `TABLE_SCHEMA`='$db'"; + $retval = (int)$GLOBALS['dbi']->fetchValue($query); + break; + case 'indexes': + $db = PMA_Util::backquote($db); + $table = PMA_Util::backquote($table); + $query = "SHOW INDEXES FROM $table FROM $db"; + $retval = (int)$GLOBALS['dbi']->numRows( + $GLOBALS['dbi']->tryQuery($query) + ); + break; + case 'triggers': + $db = PMA_Util::sqlAddSlashes($db); + $table = PMA_Util::sqlAddSlashes($table); + $query = "SELECT COUNT(*) "; + $query .= "FROM `INFORMATION_SCHEMA`.`TRIGGERS` "; + $query .= "WHERE `EVENT_OBJECT_SCHEMA`='$db' "; + $query .= "AND `EVENT_OBJECT_TABLE`='$table'"; + $retval = (int)$GLOBALS['dbi']->fetchValue($query); + break; + default: + break; + } + return $retval; + } + + /** + * Returns the names of children of type $type present inside this container + * This method is overridden by the Node_Database and Node_Table classes + * + * @param string $type The type of item we are looking for + * ('tables', 'views', etc) + * @param int $pos The offset of the list within the results + * @param string $searchClause A string used to filter the results of the query + * + * @return array + */ + public function getData($type, $pos, $searchClause = '') + { + $maxItems = $GLOBALS['cfg']['MaxNavigationItems']; + $retval = array(); + $db = $this->realParent()->real_name; + $table = $this->real_name; + switch ($type) { + case 'columns': + $db = PMA_Util::sqlAddSlashes($db); + $table = PMA_Util::sqlAddSlashes($table); + $query = "SELECT `COLUMN_NAME` AS `name` "; + $query .= "FROM `INFORMATION_SCHEMA`.`COLUMNS` "; + $query .= "WHERE `TABLE_NAME`='$table' "; + $query .= "AND `TABLE_SCHEMA`='$db' "; + $query .= "ORDER BY `COLUMN_NAME` ASC "; + $query .= "LIMIT " . intval($pos) . ", $maxItems"; + $retval = $GLOBALS['dbi']->fetchResult($query); + break; + case 'indexes': + $db = PMA_Util::backquote($db); + $table = PMA_Util::backquote($table); + $query = "SHOW INDEXES FROM $table FROM $db"; + $handle = $GLOBALS['dbi']->tryQuery($query); + if ($handle !== false) { + $count = 0; + while ($arr = $GLOBALS['dbi']->fetchArray($handle)) { + if (! in_array($arr['Key_name'], $retval)) { + if ($pos <= 0 && $count < $maxItems) { + $retval[] = $arr['Key_name']; + $count++; + } + $pos--; + } + } + } + break; + case 'triggers': + $db = PMA_Util::sqlAddSlashes($db); + $table = PMA_Util::sqlAddSlashes($table); + $query = "SELECT `TRIGGER_NAME` AS `name` "; + $query .= "FROM `INFORMATION_SCHEMA`.`TRIGGERS` "; + $query .= "WHERE `EVENT_OBJECT_SCHEMA`='$db' "; + $query .= "AND `EVENT_OBJECT_TABLE`='$table' "; + $query .= "ORDER BY `TRIGGER_NAME` ASC "; + $query .= "LIMIT " . intval($pos) . ", $maxItems"; + $retval = $GLOBALS['dbi']->fetchResult($query); + break; + default: + break; + } + return $retval; + } + + /** + * Returns the type of the item represented by the node. + * + * @return string type of the item + */ + protected function getItemType() + { + return 'table'; + } +} + +?> diff --git a/phpMyAdmin/libraries/navigation/Nodes/Node_Table_Container.class.php b/phpMyAdmin/libraries/navigation/Nodes/Node_Table_Container.class.php new file mode 100644 index 0000000..4c4ef20 --- /dev/null +++ b/phpMyAdmin/libraries/navigation/Nodes/Node_Table_Container.class.php @@ -0,0 +1,60 @@ +icon = PMA_Util::getImage('b_browse.png', __('Tables')); + $this->links = array( + 'text' => 'db_structure.php?server=' . $GLOBALS['server'] + . '&db=%1$s&tbl_type=table' + . '&token=' . $GLOBALS['token'], + 'icon' => 'db_structure.php?server=' . $GLOBALS['server'] + . '&db=%1$s&tbl_type=table' + . '&token=' . $GLOBALS['token'], + ); + if ($GLOBALS['cfg']['NavigationTreeEnableGrouping']) { + $this->separator = $GLOBALS['cfg']['NavigationTreeTableSeparator']; + $this->separator_depth = (int)( + $GLOBALS['cfg']['NavigationTreeTableLevel'] + ); + } + $this->real_name = 'tables'; + $this->classes = 'tableContainer subContainer'; + + $new_label = _pgettext('Create new table', 'New'); + $new = PMA_NodeFactory::getInstance('Node', $new_label); + $new->isNew = true; + $new->icon = PMA_Util::getImage('b_table_add.png', $new_label); + $new->links = array( + 'text' => 'tbl_create.php?server=' . $GLOBALS['server'] + . '&db=%2$s&token=' . $GLOBALS['token'], + 'icon' => 'tbl_create.php?server=' . $GLOBALS['server'] + . '&db=%2$s&token=' . $GLOBALS['token'], + ); + $new->classes = 'new_table italics'; + $this->addChild($new); + } +} + +?> diff --git a/phpMyAdmin/libraries/navigation/Nodes/Node_Trigger.class.php b/phpMyAdmin/libraries/navigation/Nodes/Node_Trigger.class.php new file mode 100644 index 0000000..bc51106 --- /dev/null +++ b/phpMyAdmin/libraries/navigation/Nodes/Node_Trigger.class.php @@ -0,0 +1,45 @@ +icon = PMA_Util::getImage('b_triggers.png'); + $this->links = array( + 'text' => 'db_triggers.php?server=' . $GLOBALS['server'] + . '&db=%3$s&item_name=%1$s&edit_item=1' + . '&token=' . $GLOBALS['token'], + 'icon' => 'db_triggers.php?server=' . $GLOBALS['server'] + . '&db=%3$s&item_name=%1$s&export_item=1' + . '&token=' . $GLOBALS['token'] + ); + $this->classes = 'trigger'; + } +} + +?> diff --git a/phpMyAdmin/libraries/navigation/Nodes/Node_Trigger_Container.class.php b/phpMyAdmin/libraries/navigation/Nodes/Node_Trigger_Container.class.php new file mode 100644 index 0000000..1d47d31 --- /dev/null +++ b/phpMyAdmin/libraries/navigation/Nodes/Node_Trigger_Container.class.php @@ -0,0 +1,55 @@ +icon = PMA_Util::getImage('b_triggers.png'); + $this->links = array( + 'text' => 'db_triggers.php?server=' . $GLOBALS['server'] + . '&db=%2$s&table=%1$s&token=' . $GLOBALS['token'], + 'icon' => 'db_triggers.php?server=' . $GLOBALS['server'] + . '&db=%2$s&table=%1$s&token=' . $GLOBALS['token'] + ); + $this->real_name = 'triggers'; + + $new = PMA_NodeFactory::getInstance( + 'Node', _pgettext('Create new trigger', 'New') + ); + $new->isNew = true; + $new->icon = PMA_Util::getImage('b_trigger_add.png', ''); + $new->links = array( + 'text' => 'db_triggers.php?server=' . $GLOBALS['server'] + . '&db=%3$s&token=' . $GLOBALS['token'] + . '&add_item=1', + 'icon' => 'db_triggers.php?server=' . $GLOBALS['server'] + . '&db=%3$s&token=' . $GLOBALS['token'] + . '&add_item=1', + ); + $new->classes = 'new_trigger italics'; + $this->addChild($new); + } + +} + +?> diff --git a/phpMyAdmin/libraries/navigation/Nodes/Node_View.class.php b/phpMyAdmin/libraries/navigation/Nodes/Node_View.class.php new file mode 100644 index 0000000..cdb4f33 --- /dev/null +++ b/phpMyAdmin/libraries/navigation/Nodes/Node_View.class.php @@ -0,0 +1,57 @@ +icon = PMA_Util::getImage('b_props.png', __('View')); + $this->links = array( + 'text' => 'sql.php?server=' . $GLOBALS['server'] + . '&db=%2$s&table=%1$s&pos=0' + . '&token=' . $GLOBALS['token'], + 'icon' => 'tbl_structure.php?server=' . $GLOBALS['server'] + . '&db=%2$s&table=%1$s' + . '&token=' . $GLOBALS['token'] + ); + $this->classes = 'view'; + } + + /** + * Returns the type of the item represented by the node. + * + * @return string type of the item + */ + protected function getItemType() + { + return 'view'; + } +} + +?> diff --git a/phpMyAdmin/libraries/navigation/Nodes/Node_View_Container.class.php b/phpMyAdmin/libraries/navigation/Nodes/Node_View_Container.class.php new file mode 100644 index 0000000..775c550 --- /dev/null +++ b/phpMyAdmin/libraries/navigation/Nodes/Node_View_Container.class.php @@ -0,0 +1,60 @@ +icon = PMA_Util::getImage('b_views.png', __('Views')); + $this->links = array( + 'text' => 'db_structure.php?server=' . $GLOBALS['server'] + . '&db=%1$s&tbl_type=view' + . '&token=' . $GLOBALS['token'], + 'icon' => 'db_structure.php?server=' . $GLOBALS['server'] + . '&db=%1$s&tbl_type=view' + . '&token=' . $GLOBALS['token'], + ); + if ($GLOBALS['cfg']['NavigationTreeEnableGrouping']) { + $this->separator = $GLOBALS['cfg']['NavigationTreeTableSeparator']; + $this->separator_depth = (int)( + $GLOBALS['cfg']['NavigationTreeTableLevel'] + ); + } + $this->classes = 'viewContainer subContainer'; + $this->real_name = 'views'; + + $new_label = _pgettext('Create new view', 'New'); + $new = PMA_NodeFactory::getInstance('Node', $new_label); + $new->isNew = true; + $new->icon = PMA_Util::getImage('b_view_add.png', $new_label); + $new->links = array( + 'text' => 'view_create.php?server=' . $GLOBALS['server'] + . '&db=%2$s&token=' . $GLOBALS['token'], + 'icon' => 'view_create.php?server=' . $GLOBALS['server'] + . '&db=%2$s&token=' . $GLOBALS['token'], + ); + $new->classes = 'new_view italics'; + $this->addChild($new); + } +} + +?> diff --git a/phpMyAdmin/libraries/navigation_header.inc.php b/phpMyAdmin/libraries/navigation_header.inc.php deleted file mode 100644 index 8646659..0000000 --- a/phpMyAdmin/libraries/navigation_header.inc.php +++ /dev/null @@ -1,134 +0,0 @@ -'; - } elseif (@file_exists($GLOBALS['pmaThemeImage'] . 'pma_logo2.png')) { - $logo = ''; - } - - echo '' . "\n"; -} // end of display logo -?> -' . "\n"; - -/** - * Displays the MySQL servers choice form - */ -if ($GLOBALS['cfg']['LeftDisplayServers'] && (count($GLOBALS['cfg']['Servers']) > 1 || $server == 0 && count($GLOBALS['cfg']['Servers']) == 1)) { - echo '
    '; - include './libraries/select_server.lib.php'; - PMA_select_server(true, true); - echo '

    '; -} // end if LeftDisplayServers -?> diff --git a/phpMyAdmin/libraries/ob.lib.php b/phpMyAdmin/libraries/ob.lib.php deleted file mode 100644 index be7e463..0000000 --- a/phpMyAdmin/libraries/ob.lib.php +++ /dev/null @@ -1,96 +0,0 @@ - - * http://www.jeremybrand.com/Jeremy/Brand/Jeremy_Brand.html - * - * Check for all the needed functions for output buffering - * Make some wrappers for the top and bottoms of our files. - * - * @package PhpMyAdmin - */ - -/** - * This function be used eventually to support more modes. It is needed - * because both header and footer functions must know what each other is - * doing. - * - * @staticvar integer remember last calculated value - * @return integer the output buffer mode - */ -function PMA_outBufferModeGet() -{ - static $mode = null; - - if (null !== $mode) { - return $mode; - } - - $mode = 0; - - if ($GLOBALS['cfg']['OBGzip'] && function_exists('ob_start')) { - if (ini_get('output_handler') == 'ob_gzhandler') { - // If a user sets the output_handler in php.ini to ob_gzhandler, then - // any right frame file in phpMyAdmin will not be handled properly by - // the browser. My fix was to check the ini file within the - // PMA_outBufferModeGet() function. - $mode = 0; - } elseif (function_exists('ob_get_level') && ob_get_level() > 0) { - // If output buffering is enabled in php.ini it's not possible to - // add the ob_gzhandler without a warning message from php 4.3.0. - // Being better safe than sorry, check for any existing output handler - // instead of just checking the 'output_buffering' setting. - $mode = 0; - } else { - $mode = 1; - } - } - - // Zero (0) is no mode or in other words output buffering is OFF. - // Follow 2^0, 2^1, 2^2, 2^3 type values for the modes. - // Usefull if we ever decide to combine modes. Then a bitmask field of - // the sum of all modes will be the natural choice. - - return $mode; -} // end of the 'PMA_outBufferModeGet()' function - - -/** - * This function will need to run at the top of all pages if output - * output buffering is turned on. It also needs to be passed $mode from - * the PMA_outBufferModeGet() function or it will be useless. - * - */ -function PMA_outBufferPre() -{ - if ($mode = PMA_outBufferModeGet()) { - ob_start('ob_gzhandler'); - } - - header('X-ob_mode: ' . $mode); - - register_shutdown_function('PMA_outBufferPost'); -} // end of the 'PMA_outBufferPre()' function - - -/** - * This function will need to run at the bottom of all pages if output - * buffering is turned on. It also needs to be passed $mode from the - * PMA_outBufferModeGet() function or it will be useless. - * - */ -function PMA_outBufferPost() -{ - if (ob_get_status() && PMA_outBufferModeGet()) { - ob_flush(); - } - /** - * previously we had here an "else flush()" but some PHP versions - * (at least PHP 5.2.11) have a bug (49816) that produces garbled - * data - */ -} // end of the 'PMA_outBufferPost()' function - -?> diff --git a/phpMyAdmin/libraries/opendocument.lib.php b/phpMyAdmin/libraries/opendocument.lib.php index c1d698e..08ff2b1 100644 --- a/phpMyAdmin/libraries/opendocument.lib.php +++ b/phpMyAdmin/libraries/opendocument.lib.php @@ -14,91 +14,158 @@ */ require_once './libraries/zip.lib.php'; -$GLOBALS['OpenDocumentNS'] = 'xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" ' - . 'xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" ' - . 'xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" ' - . 'xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" ' - . 'xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" '; +$GLOBALS['OpenDocumentNS'] + = 'xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" ' + . 'xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" ' + . 'xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" ' + . 'xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" ' + . 'xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" ' + . 'xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" '; /** * Minimalistic creator of OASIS OpenDocument * - * @param string desired MIME type - * @param string document content + * @param string $mime desired MIME type + * @param string $data document content * - * @return string OASIS OpenDocument data + * @return string OASIS OpenDocument data * * @access public */ function PMA_createOpenDocument($mime, $data) { - $zipfile = new zipfile(); + $zipfile = new ZipFile(); $zipfile -> addFile($mime, 'mimetype'); $zipfile -> addFile($data, 'content.xml'); - $zipfile -> addFile('' + $zipfile -> addFile( + '' . '' - . '' - . 'phpMyAdmin ' . PMA_VERSION . '' - . 'phpMyAdmin ' . PMA_VERSION . '' - . '' . strftime('%Y-%m-%dT%H:%M:%S') . '' - . '' + . 'xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" ' + . 'xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" ' + . 'office:version="1.0">' + . '' + . 'phpMyAdmin ' . PMA_VERSION . '' + . 'phpMyAdmin ' . PMA_VERSION + . '' + . '' . strftime('%Y-%m-%dT%H:%M:%S') + . '' + . '' . '', - 'meta.xml'); - $zipfile -> addFile('' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' - . '' + 'meta.xml' + ); + $zipfile -> addFile( + '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . '' . '', - 'styles.xml'); - $zipfile -> addFile('' - . '' - . '' - . '' - . '' - . '' + 'styles.xml' + ); + $zipfile -> addFile( + '' + . '' + . '' + . '' + . '' + . '' . '', - 'META-INF/manifest.xml'); + 'META-INF/manifest.xml' + ); return $zipfile -> file(); } ?> diff --git a/phpMyAdmin/libraries/operations.lib.php b/phpMyAdmin/libraries/operations.lib.php new file mode 100644 index 0000000..a47ae51 --- /dev/null +++ b/phpMyAdmin/libraries/operations.lib.php @@ -0,0 +1,1619 @@ +' + . '
    ' + . PMA_URL_getHiddenInputs($db) + . '
    ' + . ''; + if (PMA_Util::showIcons('ActionLinksMode')) { + $html_output .= ''; + } + $html_output .= __('Database comment: '); + $html_output .= ''; + $html_output .= '' + . '
    '; + $html_output .= '
    ' + . '' + . '
    ' + . '
    ' + . '
    '; + + return $html_output; +} + +/** + * Get HTML output for rename database + * + * @param string $db database name + * + * @return string $html_output + */ +function PMA_getHtmlForRenameDatabase($db) +{ + $html_output = '
    ' + . '
    '; + if (isset($_REQUEST['db_collation'])) { + $html_output .= '' . "\n"; + } + $html_output .= '' + . '' + . PMA_URL_getHiddenInputs($db) + . '
    ' + . ''; + + if (PMA_Util::showIcons('ActionLinksMode')) { + $html_output .= PMA_Util::getImage('b_edit.png'); + } + $html_output .= __('Rename database to:') + . ''; + + $html_output .= '' + . '
    ' + . '
    ' + . '' + . '
    ' + . '
    ' + . '
    '; + + return $html_output; +} + +/** + * Get HTML for database drop link + * + * @param string $db database name + * + * @return string $html_output + */ +function PMA_getHtmlForDropDatabaseLink($db) +{ + $this_sql_query = 'DROP DATABASE ' . PMA_Util::backquote($db); + $this_url_params = array( + 'sql_query' => $this_sql_query, + 'back' => 'db_operations.php', + 'goto' => 'index.php', + 'reload' => '1', + 'purge' => '1', + 'message_to_show' => sprintf( + __('Database %s has been dropped.'), + htmlspecialchars(PMA_Util::backquote($db)) + ), + 'db' => null, + ); + + $html_output = '
    ' + . '
    '; + $html_output .= ''; + if (PMA_Util::showIcons('ActionLinksMode')) { + $html_output .= PMA_Util::getImage('b_deltbl.png'); + } + $html_output .= __('Remove database') + . ''; + $html_output .= '
      '; + $html_output .= PMA_getDeleteDataOrTablelink( + $this_url_params, + 'DROP_DATABASE', + __('Drop the database (DROP)'), + 'drop_db_anchor' + ); + $html_output .= '
    ' + . '
    '; + + return $html_output; +} + +/** + * Get HTML snippet for copy database + * + * @param string $db database name + * + * @return string $html_output + */ +function PMA_getHtmlForCopyDatabase($db) +{ + $drop_clause = 'DROP TABLE / DROP VIEW'; + $choices = array( + 'structure' => __('Structure only'), + 'data' => __('Structure and data'), + 'dataonly' => __('Data only') + ); + + if (isset($_COOKIE) + && isset($_COOKIE['pma_switch_to_new']) + && $_COOKIE['pma_switch_to_new'] == 'true' + ) { + $pma_switch_to_new = 'true'; + } + + $html_output = '
    '; + $html_output .= '
    '; + + if (isset($_REQUEST['db_collation'])) { + $html_output .= '' . "\n"; + } + $html_output .= '' . "\n" + . PMA_URL_getHiddenInputs($db); + $html_output .= '
    ' + . ''; + + if (PMA_Util::showIcons('ActionLinksMode')) { + $html_output .= PMA_Util::getImage('b_edit.png'); + } + $html_output .= __('Copy database to:') + . '' + . '
    ' + . PMA_Util::getRadioFields( + 'what', $choices, 'data', true + ); + $html_output .= ''; + $html_output .= '
    '; + $html_output .= ''; + $html_output .= '
    '; + $html_output .= ''; + $html_output .= '
    '; + $html_output .= ''; + $html_output .= '
    '; + $html_output .= ''; + $html_output .= '' + . '
    '; + $html_output .= '
    ' + . '' + . '
    ' + . '
    ' + . '
    '; + + return $html_output; +} + +/** + * Get HTML snippet for change database charset + * + * @param string $db database name + * @param string $table tabel name + * + * @return string $html_output + */ +function PMA_getHtmlForChangeDatabaseCharset($db, $table) +{ + $html_output = '
    ' + . '
    '; + if (PMA_Util::showIcons('ActionLinksMode')) { + $html_output .= PMA_Util::getImage('s_asci.png'); + } + $html_output .= '' . "\n" + . '' . "\n" + . PMA_generateCharsetDropdownBox( + PMA_CSDROPDOWN_COLLATION, + 'db_collation', + 'select_db_collation', + isset($_REQUEST['db_collation']) ? $_REQUEST['db_collation'] : '', + false, + 3 + ) + . '' + . '
    ' + . '' . "\n" + . '
    ' . "\n" + . '
    ' . "\n"; + + return $html_output; +} + +/** + * Get HTML snippet for export relational schema view + * + * @param string $url_query Query string for link + * + * @return string $html_output + */ +function PMA_getHtmlForExportRelationalSchemaView($url_query) +{ + $html_output = ''; + + return $html_output; +} + +/** + * Run the Procedure definitions and function definitions + * + * to avoid selecting alternatively the current and new db + * we would need to modify the CREATE definitions to qualify + * the db name + * + * @param string $db database name + * + * @return void + */ +function PMA_runProcedureAndFunctionDefinitions($db) +{ + $procedure_names = $GLOBALS['dbi']->getProceduresOrFunctions($db, 'PROCEDURE'); + if ($procedure_names) { + foreach ($procedure_names as $procedure_name) { + $GLOBALS['dbi']->selectDb($db); + $tmp_query = $GLOBALS['dbi']->getDefinition( + $db, 'PROCEDURE', $procedure_name + ); + // collect for later display + $GLOBALS['sql_query'] .= "\n" . $tmp_query; + $GLOBALS['dbi']->selectDb($_REQUEST['newname']); + $GLOBALS['dbi']->query($tmp_query); + } + } + + $function_names = $GLOBALS['dbi']->getProceduresOrFunctions($db, 'FUNCTION'); + if ($function_names) { + foreach ($function_names as $function_name) { + $GLOBALS['dbi']->selectDb($db); + $tmp_query = $GLOBALS['dbi']->getDefinition( + $db, 'FUNCTION', $function_name + ); + // collect for later display + $GLOBALS['sql_query'] .= "\n" . $tmp_query; + $GLOBALS['dbi']->selectDb($_REQUEST['newname']); + $GLOBALS['dbi']->query($tmp_query); + } + } +} + +/** + * Get sql query and create database before copy + * + * @return string $sql_query + */ +function PMA_getSqlQueryAndCreateDbBeforeCopy() +{ + // lower_case_table_names=1 `DB` becomes `db` + if (! PMA_DRIZZLE) { + $lower_case_table_names = $GLOBALS['dbi']->fetchValue( + 'SHOW VARIABLES LIKE "lower_case_table_names"', 0, 1 + ); + if ($lower_case_table_names === '1') { + $_REQUEST['newname'] = $GLOBALS['PMA_String']->strtolower( + $_REQUEST['newname'] + ); + } + } + + $local_query = 'CREATE DATABASE IF NOT EXISTS ' + . PMA_Util::backquote($_REQUEST['newname']); + if (isset($_REQUEST['db_collation'])) { + $local_query .= ' DEFAULT' + . PMA_generateCharsetQueryPart($_REQUEST['db_collation']); + } + $local_query .= ';'; + $sql_query = $local_query; + // save the original db name because Tracker.class.php which + // may be called under $GLOBALS['dbi']->query() changes $GLOBALS['db'] + // for some statements, one of which being CREATE DATABASE + $original_db = $GLOBALS['db']; + $GLOBALS['dbi']->query($local_query); + $GLOBALS['db'] = $original_db; + + // Set the SQL mode to NO_AUTO_VALUE_ON_ZERO to prevent MySQL from creating + // export statements it cannot import + $sql_set_mode = "SET SQL_MODE='NO_AUTO_VALUE_ON_ZERO'"; + $GLOBALS['dbi']->query($sql_set_mode); + + // rebuild the database list because PMA_Table::moveCopy + // checks in this list if the target db exists + $GLOBALS['pma']->databases->build(); + + return $sql_query; +} + +/** + * remove all foreign key constraints and return + * sql constraints query for full database + * + * @param array $tables_full array of all tables in given db or dbs + * @param object $export_sql_plugin export plugin instance + * @param boolean $move whether database name is empty or not + * @param string $db database name + * + * @return string sql constraints query for full databases + */ +function PMA_getSqlConstraintsQueryForFullDb( + $tables_full, $export_sql_plugin, $move, $db +) { + global $sql_constraints, $sql_drop_foreign_keys; + $sql_constraints_query_full_db = array(); + foreach ($tables_full as $each_table => $tmp) { + /* Following globals are set in getTableDef */ + $sql_constraints = ''; + $sql_drop_foreign_keys = ''; + $export_sql_plugin->getTableDef( + $db, $each_table, "\n", '', false, false + ); + if ($move && ! empty($sql_drop_foreign_keys)) { + $GLOBALS['dbi']->query($sql_drop_foreign_keys); + } + // keep the constraint we just dropped + if (! empty($sql_constraints)) { + $sql_constraints_query_full_db[] = $sql_constraints; + } + } + return $sql_constraints_query_full_db; +} + +/** + * Get views as an array and create SQL view stand-in + * + * @param array $tables_full array of all tables in given db or dbs + * @param object $export_sql_plugin export plugin instance + * @param string $db database name + * + * @return array $views + */ +function PMA_getViewsAndCreateSqlViewStandIn( + $tables_full, $export_sql_plugin, $db +) { + $views = array(); + foreach ($tables_full as $each_table => $tmp) { + // to be able to rename a db containing views, + // first all the views are collected and a stand-in is created + // the real views are created after the tables + if (PMA_Table::isView($db, $each_table)) { + $views[] = $each_table; + // Create stand-in definition to resolve view dependencies + $sql_view_standin = $export_sql_plugin->getTableDefStandIn( + $db, $each_table, "\n" + ); + $GLOBALS['dbi']->selectDb($_REQUEST['newname']); + $GLOBALS['dbi']->query($sql_view_standin); + $GLOBALS['sql_query'] .= "\n" . $sql_view_standin; + } + } + return $views; +} + +/** + * Get sql query for copy/rename table and boolean for whether copy/rename or not + * + * @param array $tables_full array of all tables in given db or dbs + * @param string $sql_query sql query for all operations + * @param boolean $move whether database name is empty or not + * @param string $db database name + * + * @return array ($sql_query, $error) + */ +function PMA_getSqlQueryForCopyTable($tables_full, $sql_query, $move, $db) +{ + $error = false; + foreach ($tables_full as $each_table => $tmp) { + // skip the views; we have creted stand-in definitions + if (PMA_Table::isView($db, $each_table)) { + continue; + } + $back = $sql_query; + $sql_query = ''; + + // value of $what for this table only + $this_what = $_REQUEST['what']; + + // do not copy the data from a Merge table + // note: on the calling FORM, 'data' means 'structure and data' + if (PMA_Table::isMerge($db, $each_table)) { + if ($this_what == 'data') { + $this_what = 'structure'; + } + if ($this_what == 'dataonly') { + $this_what = 'nocopy'; + } + } + + if ($this_what != 'nocopy') { + // keep the triggers from the original db+table + // (third param is empty because delimiters are only intended + // for importing via the mysql client or our Import feature) + $triggers = $GLOBALS['dbi']->getTriggers($db, $each_table, ''); + + if (! PMA_Table::moveCopy( + $db, $each_table, $_REQUEST['newname'], $each_table, + (isset($this_what) ? $this_what : 'data'), + $move, 'db_copy' + )) { + $error = true; + // $sql_query is filled by PMA_Table::moveCopy() + $sql_query = $back . $sql_query; + break; + } + // apply the triggers to the destination db+table + if ($triggers) { + $GLOBALS['dbi']->selectDb($_REQUEST['newname']); + foreach ($triggers as $trigger) { + $GLOBALS['dbi']->query($trigger['create']); + $GLOBALS['sql_query'] .= "\n" . $trigger['create'] . ';'; + } + } + + // this does not apply to a rename operation + if (isset($_REQUEST['add_constraints']) + && ! empty($GLOBALS['sql_constraints_query']) + ) { + $GLOBALS['sql_constraints_query_full_db'][] + = $GLOBALS['sql_constraints_query']; + unset($GLOBALS['sql_constraints_query']); + } + } + // $sql_query is filled by PMA_Table::moveCopy() + $sql_query = $back . $sql_query; + } + return array($sql_query, $error); +} + +/** + * Run the EVENT definition for selected database + * + * to avoid selecting alternatively the current and new db + * we would need to modify the CREATE definitions to qualify + * the db name + * + * @param string $db database name + * + * @return void + */ +function PMA_runEventDefinitionsForDb($db) +{ + $event_names = $GLOBALS['dbi']->fetchResult( + 'SELECT EVENT_NAME FROM information_schema.EVENTS WHERE EVENT_SCHEMA= \'' + . PMA_Util::sqlAddSlashes($db, true) . '\';' + ); + if ($event_names) { + foreach ($event_names as $event_name) { + $GLOBALS['dbi']->selectDb($db); + $tmp_query = $GLOBALS['dbi']->getDefinition($db, 'EVENT', $event_name); + // collect for later display + $GLOBALS['sql_query'] .= "\n" . $tmp_query; + $GLOBALS['dbi']->selectDb($_REQUEST['newname']); + $GLOBALS['dbi']->query($tmp_query); + } + } +} + +/** + * Handle the views, return the boolean value whether table rename/copy or not + * + * @param array $views views as an array + * @param boolean $move whether database name is empty or not + * @param string $db database name + * + * @return boolean $_error whether table rename/copy or not + */ +function PMA_handleTheViews($views, $move, $db) +{ + $_error = false; + // temporarily force to add DROP IF EXIST to CREATE VIEW query, + // to remove stand-in VIEW that was created earlier + // ( $_REQUEST['drop_if_exists'] is used in moveCopy() ) + if (isset($_REQUEST['drop_if_exists'])) { + $temp_drop_if_exists = $_REQUEST['drop_if_exists']; + } + $_REQUEST['drop_if_exists'] = 'true'; + + foreach ($views as $view) { + $copying_succeeded = PMA_Table::moveCopy( + $db, $view, $_REQUEST['newname'], $view, 'structure', $move, 'db_copy' + ); + if (! $copying_succeeded) { + $_error = true; + break; + } + } + unset($_REQUEST['drop_if_exists']); + if (isset($temp_drop_if_exists)) { + // restore previous value + $_REQUEST['drop_if_exists'] = $temp_drop_if_exists; + } + return $_error; +} + +/** + * Create all accumulated constraaints + * + * @return void + */ +function PMA_createAllAccumulatedConstraints() +{ + $GLOBALS['dbi']->selectDb($_REQUEST['newname']); + foreach ($GLOBALS['sql_constraints_query_full_db'] as $one_query) { + $GLOBALS['dbi']->query($one_query); + // and prepare to display them + $GLOBALS['sql_query'] .= "\n" . $one_query; + } + unset($GLOBALS['sql_constraints_query_full_db']); +} + +/** + * Duplicate the bookmarks for the db (done once for each db) + * + * @param boolean $_error whether table rename/copy or not + * @param string $db database name + * + * @return void + */ +function PMA_duplicateBookmarks($_error, $db) +{ + if (! $_error && $db != $_REQUEST['newname']) { + $get_fields = array('user', 'label', 'query'); + $where_fields = array('dbase' => $db); + $new_fields = array('dbase' => $_REQUEST['newname']); + PMA_Table::duplicateInfo( + 'bookmarkwork', 'bookmark', $get_fields, + $where_fields, $new_fields + ); + } +} + +/** + * Get the HTML snippet for order the table + * + * @param array $columns columns array + * + * @return string $html_out + */ +function PMA_getHtmlForOrderTheTable($columns) +{ + $html_output = '
    '; + $html_output .= '
    '; + $html_output .= PMA_URL_getHiddenInputs( + $GLOBALS['db'], $GLOBALS['table'] + ); + $html_output .= '
    ' + . '' . __('Alter table order by') . '' + . ' ' . __('(singly)') . ' ' + . '
    ' + . '' + . '' + . '' + . '' + . '
    ' + . '
    ' + . '' + . '' + . '
    ' + . '
    ' + . '
    '; + + return $html_output; +} + +/** + * Get the HTML snippet for move table + * + * @return string $html_output + */ +function PMA_getHtmlForMoveTable() +{ + $html_output = '
    '; + $html_output .= '
    ' + . PMA_URL_getHiddenInputs($GLOBALS['db'], $GLOBALS['table']); + + $html_output .= '' + . '' + . '
    '; + + $html_output .= '' . __('Move table to (database.table):') + . ''; + + if (count($GLOBALS['pma']->databases) > $GLOBALS['cfg']['MaxDbList']) { + $html_output .= ''; + } else { + $html_output .= ''; + } + $html_output .= ' . '; + $html_output .= '
    '; + + // starting with MySQL 5.0.24, SHOW CREATE TABLE includes the AUTO_INCREMENT + // next value but users can decide if they want it or not for the operation + + $html_output .= '' + . '
    ' + . '
    '; + + $html_output .= '
    ' + . '' + . '
    ' + . '
    ' + . '
    '; + + return $html_output; +} + +/** + * Get the HTML div for Table option + * + * @param string $comment Comment + * @param array $tbl_collation table collation + * @param string $tbl_storage_engine table storage engine + * @param boolean $is_myisam_or_aria whether MYISAM | ARIA or not + * @param boolean $is_isam whether ISAM or not + * @param array $pack_keys pack keys + * @param string $auto_increment value of auto increment + * @param string $delay_key_write delay key write + * @param string $transactional value of transactional + * @param string $page_checksum value of page checksum + * @param boolean $is_innodb whether INNODB or not + * @param boolean $is_pbxt whether PBXT or not + * @param boolean $is_aria whether ARIA or not + * @param string $checksum the checksum + * + * @return string $html_output + */ +function PMA_getTableOptionDiv($comment, $tbl_collation, $tbl_storage_engine, + $is_myisam_or_aria, $is_isam, $pack_keys, $auto_increment, $delay_key_write, + $transactional, $page_checksum, $is_innodb, $is_pbxt, $is_aria, $checksum +) { + $html_output = '
    '; + $html_output .= '
    ' + . '' + . '' + . '
    ' + . '
    '; + + return $html_output; +} + +/** + * Get HTML fieldset for Table option, it contains HTML table for options + * + * @param string $comment Comment + * @param array $tbl_collation table collation + * @param string $tbl_storage_engine table storage engine + * @param boolean $is_myisam_or_aria whether MYISAM | ARIA or not + * @param boolean $is_isam whether ISAM or not + * @param array $pack_keys pack keys + * @param string $delay_key_write delay key write + * @param string $auto_increment value of auto increment + * @param string $transactional value of transactional + * @param string $page_checksum value of page checksum + * @param boolean $is_innodb whether INNODB or not + * @param boolean $is_pbxt whether PBXT or not + * @param boolean $is_aria whether ARIA or not + * @param string $checksum the checksum + * + * @return string $html_output + */ +function PMA_getTableOptionFieldset($comment, $tbl_collation, + $tbl_storage_engine, $is_myisam_or_aria, $is_isam, $pack_keys, + $delay_key_write, $auto_increment, $transactional, + $page_checksum, $is_innodb, $is_pbxt, $is_aria, $checksum +) { + $html_output = '
    ' + . '' . __('Table options') . ''; + + $html_output .= ''; + //Change table name + $html_output .= '' + . '' + . ''; + + //Table comments + $html_output .= '' + . '' + . ''; + + //Storage engine + $html_output .= '' + . '' + . ''; + + //Table character set + $html_output .= '' + . '' + . ''; + + if ($is_myisam_or_aria || $is_isam) { + $html_output .= '' + . '' + . '' + . ''; + } // end if (MYISAM|ISAM) + + if ($is_myisam_or_aria) { + $html_output .= PMA_getHtmlForTableRow( + 'new_checksum', + 'CHECKSUM', + $checksum + ); + + $html_output .= PMA_getHtmlForTableRow( + 'new_delay_key_write', + 'DELAY_KEY_WRITE', + $delay_key_write + ); + } // end if (MYISAM) + + if ($is_aria) { + $html_output .= PMA_getHtmlForTableRow( + 'new_transactional', + 'TRANSACTIONAL', + $transactional + ); + + $html_output .= PMA_getHtmlForTableRow( + 'new_page_checksum', + 'PAGE_CHECKSUM', + $page_checksum + ); + } // end if (ARIA) + + if (strlen($auto_increment) > 0 + && ($is_myisam_or_aria || $is_innodb || $is_pbxt) + ) { + $html_output .= '' + . '' + . ' '; + } // end if (MYISAM|INNODB) + + $possible_row_formats = PMA_getPossibleRowFormat(); + + // for MYISAM there is also COMPRESSED but it can be set only by the + // myisampack utility, so don't offer here the choice because if we + // try it inside an ALTER TABLE, MySQL (at least in 5.1.23-maria) + // does not return a warning + // (if the table was compressed, it can be seen on the Structure page) + + if (isset($possible_row_formats[$tbl_storage_engine])) { + $current_row_format = strtoupper($GLOBALS['showtable']['Row_format']); + $html_output .= '' + . ''; + } + $html_output .= '
    ' . __('Rename table to') . '' + . '' + . '
    ' . __('Table comments') . '' + . '' + . '
    ' . __('Storage Engine') + . PMA_Util::showMySQLDocu('Storage_engines') + . '' + . PMA_StorageEngine::getHtmlSelect( + 'new_tbl_storage_engine', null, $tbl_storage_engine + ) + . '
    ' . __('Collation') . '' + . PMA_generateCharsetDropdownBox( + PMA_CSDROPDOWN_COLLATION, + 'tbl_collation', null, $tbl_collation, false, 3 + ) + . '
    ' + . '
    ' + . ''; + $html_output .= PMA_Util::getDropdown( + 'new_row_format', $possible_row_formats[$tbl_storage_engine], + $current_row_format, 'new_row_format' + ); + $html_output .= '
    ' + . '
    '; + + return $html_output; +} + +/** + * Get the common HTML table row (tr) for new_checksum, new_delay_key_write, + * new_transactional and new_page_checksum + * + * @param string $attribute class, name and id attribute + * @param string $label label value + * @param string $val checksum, delay_key_write, transactional, page_checksum + * + * @return string $html_output + */ +function PMA_getHtmlForTableRow($attribute, $label, $val) +{ + return '' + . '' + . '' + . ''; +} + +/** + * Get array of possible row formats + * + * @return array $possible_row_formats + */ +function PMA_getPossibleRowFormat() +{ + // the outer array is for engines, the inner array contains the dropdown + // option values as keys then the dropdown option labels + + $possible_row_formats = array( + 'ARIA' => array( + 'FIXED' => 'FIXED', + 'DYNAMIC' => 'DYNAMIC', + 'PAGE' => 'PAGE' + ), + 'MARIA' => array( + 'FIXED' => 'FIXED', + 'DYNAMIC' => 'DYNAMIC', + 'PAGE' => 'PAGE' + ), + 'MYISAM' => array( + 'FIXED' => 'FIXED', + 'DYNAMIC' => 'DYNAMIC' + ), + 'PBXT' => array( + 'FIXED' => 'FIXED', + 'DYNAMIC' => 'DYNAMIC' + ), + 'INNODB' => array( + 'COMPACT' => 'COMPACT', + 'REDUNDANT' => 'REDUNDANT' + ) + ); + + $innodb_engine_plugin = PMA_StorageEngine::getEngine('innodb'); + $innodb_plugin_version = $innodb_engine_plugin->getInnodbPluginVersion(); + if (!empty($innodb_plugin_version)) { + $innodb_file_format = $innodb_engine_plugin->getInnodbFileFormat(); + } else { + $innodb_file_format = ''; + } + if ('Barracuda' == $innodb_file_format + && $innodb_engine_plugin->supportsFilePerTable() + ) { + $possible_row_formats['INNODB']['DYNAMIC'] = 'DYNAMIC'; + $possible_row_formats['INNODB']['COMPRESSED'] = 'COMPRESSED'; + } + + return $possible_row_formats; +} + +/** + * Get HTML div for copy table + * + * @return string $html_output + */ +function PMA_getHtmlForCopytable() +{ + $html_output = '
    '; + $html_output .= '
    ' + . PMA_URL_getHiddenInputs($GLOBALS['db'], $GLOBALS['table']) + . ''; + + $html_output .= '
    '; + $html_output .= '' + . __('Copy table to (database.table):') . ''; + + if (count($GLOBALS['pma']->databases) > $GLOBALS['cfg']['MaxDbList']) { + $html_output .= ''; + } else { + $html_output .= ''; + } + $html_output .= ' . '; + $html_output .= '
    '; + + $choices = array( + 'structure' => __('Structure only'), + 'data' => __('Structure and data'), + 'dataonly' => __('Data only')); + + $html_output .= PMA_Util::getRadioFields( + 'what', $choices, 'data', true + ); + + $html_output .= '' + . '
    ' + . '' + . '
    '; + + // display "Add constraints" choice only if there are + // foreign keys + if (PMA_getForeigners($GLOBALS['db'], $GLOBALS['table'], '', 'foreign')) { + $html_output .= ''; + $html_output .= '
    '; + } // endif + + if (isset($_COOKIE['pma_switch_to_new']) + && $_COOKIE['pma_switch_to_new'] == 'true' + ) { + $pma_switch_to_new = 'true'; + } + + $html_output .= ''); + $html_output .= '' + . '
    '; + + $html_output .= '
    ' + . '' + . '
    ' + . '
    ' + . '
    '; + + return $html_output; +} + +/** + * Get HTML snippet for table maintence + * + * @param boolean $is_myisam_or_aria whether MYISAM | ARIA or not + * @param boolean $is_innodb whether innodb or not + * @param boolean $is_berkeleydb whether berkeleydb or not + * @param array $url_params array of URL parameters + * + * @return string $html_output + */ +function PMA_getHtmlForTableMaintenance( + $is_myisam_or_aria, $is_innodb, $is_berkeleydb, $url_params +) { + $html_output = '
    '; + $html_output .= '
    ' + . '' . __('Table maintenance') . ''; + $html_output .= '
      '; + + // Note: BERKELEY (BDB) is no longer supported, starting with MySQL 5.1 + $html_output .= PMA_getListofMaintainActionLink( + $is_myisam_or_aria, $is_innodb, $url_params, $is_berkeleydb + ); + + $html_output .= '
    ' + . '
    ' + . '
    '; + + return $html_output; +} + +/** + * Get HTML 'li' having a link of maintain action + * + * @param boolean $is_myisam_or_aria whether MYISAM | ARIA or not + * @param boolean $is_innodb whether innodb or not + * @param array $url_params array of URL parameters + * @param boolean $is_berkeleydb whether berkeleydb or not + * + * @return string $html_output + */ +function PMA_getListofMaintainActionLink($is_myisam_or_aria, + $is_innodb, $url_params, $is_berkeleydb +) { + $html_output = ''; + + if ($is_myisam_or_aria || $is_innodb || $is_berkeleydb) { + if ($is_myisam_or_aria || $is_innodb) { + $params = array( + 'sql_query' => 'CHECK TABLE ' + . PMA_Util::backquote($GLOBALS['table']), + 'table_maintenance' => 'Go', + ); + $html_output .= PMA_getMaintainActionlink( + __('Check table'), + $params, + $url_params, + 'CHECK_TABLE' + ); + } + if ($is_innodb) { + $params = array( + 'sql_query' => 'ALTER TABLE ' + . PMA_Util::backquote($GLOBALS['table']) + . ' ENGINE = InnoDB;' + ); + $html_output .= PMA_getMaintainActionlink( + __('Defragment table'), + $params, + $url_params, + 'InnoDB_File_Defragmenting', + 'Table_types' + ); + } + if ($is_innodb || $is_myisam_or_aria || $is_berkeleydb) { + $params = array( + 'sql_query' => 'ANALYZE TABLE ' + . PMA_Util::backquote($GLOBALS['table']), + 'table_maintenance' => 'Go', + ); + $html_output .= PMA_getMaintainActionlink( + __('Analyze table'), + $params, + $url_params, + 'ANALYZE_TABLE' + ); + } + if ($is_myisam_or_aria && !PMA_DRIZZLE) { + $params = array( + 'sql_query' => 'REPAIR TABLE ' + . PMA_Util::backquote($GLOBALS['table']), + 'table_maintenance' => 'Go', + ); + $html_output .= PMA_getMaintainActionlink( + __('Repair table'), + $params, + $url_params, + 'REPAIR_TABLE' + ); + } + if (($is_myisam_or_aria || $is_innodb || $is_berkeleydb) + && !PMA_DRIZZLE + ) { + $params = array( + 'sql_query' => 'OPTIMIZE TABLE ' + . PMA_Util::backquote($GLOBALS['table']), + 'table_maintenance' => 'Go', + ); + $html_output .= PMA_getMaintainActionlink( + __('Optimize table'), + $params, + $url_params, + 'OPTIMIZE_TABLE' + ); + } + } // end MYISAM or BERKELEYDB case + + $params = array( + 'sql_query' => 'FLUSH TABLE ' + . PMA_Util::backquote($GLOBALS['table']), + 'message_to_show' => sprintf( + __('Table %s has been flushed'), + htmlspecialchars($GLOBALS['table']) + ), + 'reload' => 1, + ); + + $html_output .= PMA_getMaintainActionlink( + __('Flush the table (FLUSH)'), + $params, + $url_params, + 'FLUSH' + ); + + return $html_output; +} + +/** + * Get maintain action HTML link + * + * @param string $action action name + * @param array $params url parameters array + * @param array $url_params additional url parameters + * @param string $link contains name of page/anchor that is being linked + * + * @return string $html_output + */ +function PMA_getMaintainActionlink($action, $params, $url_params, $link) +{ + return '
  • ' + . '' + . $action + . '' + . PMA_Util::showMySQLDocu($link) + . '
  • '; +} + +/** + * Get HTML for Delete data or table (truncate table, drop table) + * + * @param array $truncate_table_url_params url parameter array for truncate table + * @param array $drop_table_url_params url parameter array for drop table + * + * @return string $html_output + */ +function PMA_getHtmlForDeleteDataOrTable( + $truncate_table_url_params, + $drop_table_url_params +) { + $html_output = '
    ' + . '
    ' + . '' . __('Delete data or table') . ''; + + $html_output .= '
      '; + + if (! empty($truncate_table_url_params)) { + $html_output .= PMA_getDeleteDataOrTablelink( + $truncate_table_url_params, + 'TRUNCATE_TABLE', + __('Empty the table (TRUNCATE)'), + 'truncate_tbl_anchor' + ); + } + if (!empty ($drop_table_url_params)) { + $html_output .= PMA_getDeleteDataOrTablelink( + $drop_table_url_params, + 'DROP_TABLE', + __('Delete the table (DROP)'), + 'drop_tbl_anchor' + ); + } + $html_output .= '
    '; + + return $html_output; +} + +/** + * Get the HTML link for Truncate table, Drop table and Drop db + * + * @param array $url_params url parameter array for delete data or table + * @param string $syntax TRUNCATE_TABLE or DROP_TABLE or DROP_DATABASE + * @param string $link link to be shown + * @param string $id id of the link + * + * @return String html output + */ +function PMA_getDeleteDataOrTablelink($url_params, $syntax, $link, $id) +{ + return '
  • ' + . $link . '' + . PMA_Util::showMySQLDocu($syntax) + . '
  • '; +} + +/** + * Get HTML snippet for partition maintenance + * + * @param array $partition_names array of partition names for a specific db/table + * @param array $url_params url parameters + * + * @return string $html_output + */ +function PMA_getHtmlForPartitionMaintenance($partition_names, $url_params) +{ + $choices = array( + 'ANALYZE' => __('Analyze'), + 'CHECK' => __('Check'), + 'OPTIMIZE' => __('Optimize'), + 'REBUILD' => __('Rebuild'), + 'REPAIR' => __('Repair') + ); + + $html_output = '
    ' + . '
    ' + . PMA_URL_getHiddenInputs($GLOBALS['db'], $GLOBALS['table']) + . '
    ' + . '' . __('Partition maintenance') . ''; + + $html_select = '' . "\n"; + $html_output .= sprintf(__('Partition %s'), $html_select); + + $html_output .= PMA_Util::getRadioFields( + 'partition_operation', $choices, '', false + ); + $html_output .= PMA_Util::showMySQLDocu('partitioning_maintenance'); + $this_url_params = array_merge( + $url_params, + array( + 'sql_query' => 'ALTER TABLE ' + . PMA_Util::backquote($GLOBALS['table']) + . ' REMOVE PARTITIONING;' + ) + ); + $html_output .= '
    ' + . __('Remove partitioning') . ''; + + $html_output .= '
    ' + . '
    ' + . '' + . '' + . '
    ' + . '
    ' + . '
    '; + + return $html_output; +} + +/** + * Get the HTML for Referential Integrity check + * + * @param array $foreign all Relations to foreign tables for a given table + * or optionally a given column in a table + * @param array $url_params array of url parameters + * + * @return string $html_output + */ +function PMA_getHtmlForReferentialIntegrityCheck($foreign, $url_params) +{ + $html_output = '
    ' + . '
    ' + . '' . __('Check referential integrity:') . ''; + + $html_output .= '
      '; + + foreach ($foreign as $master => $arr) { + $join_query = 'SELECT ' + . PMA_Util::backquote($GLOBALS['table']) . '.*' + . ' FROM ' . PMA_Util::backquote($GLOBALS['table']) + . ' LEFT JOIN ' + . PMA_Util::backquote($arr['foreign_db']) + . '.' + . PMA_Util::backquote($arr['foreign_table']); + if ($arr['foreign_table'] == $GLOBALS['table']) { + $foreign_table = $GLOBALS['table'] . '1'; + $join_query .= ' AS ' . PMA_Util::backquote($foreign_table); + } else { + $foreign_table = $arr['foreign_table']; + } + $join_query .= ' ON ' + . PMA_Util::backquote($GLOBALS['table']) . '.' + . PMA_Util::backquote($master) + . ' = ' + . PMA_Util::backquote($arr['foreign_db']) + . '.' + . PMA_Util::backquote($foreign_table) . '.' + . PMA_Util::backquote($arr['foreign_field']) + . ' WHERE ' + . PMA_Util::backquote($arr['foreign_db']) + . '.' + . PMA_Util::backquote($foreign_table) . '.' + . PMA_Util::backquote($arr['foreign_field']) + . ' IS NULL AND ' + . PMA_Util::backquote($GLOBALS['table']) . '.' + . PMA_Util::backquote($master) + . ' IS NOT NULL'; + $this_url_params = array_merge( + $url_params, + array('sql_query' => $join_query) + ); + + $html_output .= '
    • ' + . '' + . $master . ' -> ' . $arr['foreign_db'] . '.' + . $arr['foreign_table'] . '.' . $arr['foreign_field'] + . '
    • ' . "\n"; + } // foreach $foreign + $html_output .= '
    '; + + return $html_output; +} + +/** + * Reorder table based on request params + * + * @return array SQL query and result + */ +function PMA_getQueryAndResultForReorderingTable() +{ + $sql_query = 'ALTER TABLE ' + . PMA_Util::backquote($GLOBALS['table']) + . ' ORDER BY ' + . PMA_Util::backquote(urldecode($_REQUEST['order_field'])); + if (isset($_REQUEST['order_order']) + && $_REQUEST['order_order'] === 'desc' + ) { + $sql_query .= ' DESC'; + } + $sql_query .= ';'; + $result = $GLOBALS['dbi']->query($sql_query); + + return array($sql_query, $result); +} + +/** + * Get table alters array + * + * @param boolean $is_myisam_or_aria whether MYISAM | ARIA or not + * @param boolean $is_isam whether ISAM or not + * @param string $pack_keys pack keys + * @param string $checksum value of checksum + * @param boolean $is_aria whether ARIA or not + * @param string $page_checksum value of page checksum + * @param string $delay_key_write delay key write + * @param boolean $is_innodb whether INNODB or not + * @param boolean $is_pbxt whether PBXT or not + * @param string $row_format row format + * @param string $new_tbl_storage_engine table storage engine + * @param string $transactional value of transactional + * @param string $tbl_collation collation of the table + * + * @return array $table_alters + */ +function PMA_getTableAltersArray($is_myisam_or_aria, $is_isam, $pack_keys, + $checksum, $is_aria, $page_checksum, $delay_key_write, $is_innodb, + $is_pbxt, $row_format, $new_tbl_storage_engine, $transactional, $tbl_collation +) { + global $auto_increment; + + $table_alters = array(); + + if (isset($_REQUEST['comment']) + && urldecode($_REQUEST['prev_comment']) !== $_REQUEST['comment'] + ) { + $table_alters[] = 'COMMENT = \'' + . PMA_Util::sqlAddSlashes($_REQUEST['comment']) . '\''; + } + if (! empty($new_tbl_storage_engine) + && strtolower($new_tbl_storage_engine) !== strtolower($GLOBALS['tbl_storage_engine']) + ) { + $table_alters[] = 'ENGINE = ' . $new_tbl_storage_engine; + } + if (! empty($_REQUEST['tbl_collation']) + && $_REQUEST['tbl_collation'] !== $tbl_collation + ) { + $table_alters[] = 'DEFAULT ' + . PMA_generateCharsetQueryPart($_REQUEST['tbl_collation']); + } + + if (($is_myisam_or_aria || $is_isam) + && isset($_REQUEST['new_pack_keys']) + && $_REQUEST['new_pack_keys'] != (string)$pack_keys + ) { + $table_alters[] = 'pack_keys = ' . $_REQUEST['new_pack_keys']; + } + + $_REQUEST['new_checksum'] = empty($_REQUEST['new_checksum']) ? '0' : '1'; + if ($is_myisam_or_aria + && $_REQUEST['new_checksum'] !== $checksum + ) { + $table_alters[] = 'checksum = ' . $_REQUEST['new_checksum']; + } + + $_REQUEST['new_transactional'] + = empty($_REQUEST['new_transactional']) ? '0' : '1'; + if ($is_aria + && $_REQUEST['new_transactional'] !== $transactional + ) { + $table_alters[] = 'TRANSACTIONAL = ' . $_REQUEST['new_transactional']; + } + + $_REQUEST['new_page_checksum'] + = empty($_REQUEST['new_page_checksum']) ? '0' : '1'; + if ($is_aria + && $_REQUEST['new_page_checksum'] !== $page_checksum + ) { + $table_alters[] = 'PAGE_CHECKSUM = ' . $_REQUEST['new_page_checksum']; + } + + $_REQUEST['new_delay_key_write'] + = empty($_REQUEST['new_delay_key_write']) ? '0' : '1'; + if ($is_myisam_or_aria + && $_REQUEST['new_delay_key_write'] !== $delay_key_write + ) { + $table_alters[] = 'delay_key_write = ' . $_REQUEST['new_delay_key_write']; + } + + if (($is_myisam_or_aria || $is_innodb || $is_pbxt) + && ! empty($_REQUEST['new_auto_increment']) + && (! isset($auto_increment) + || $_REQUEST['new_auto_increment'] !== $auto_increment) + ) { + $table_alters[] = 'auto_increment = ' + . PMA_Util::sqlAddSlashes($_REQUEST['new_auto_increment']); + } + + if (($is_myisam_or_aria || $is_innodb || $is_pbxt) + && ! empty($_REQUEST['new_row_format']) + && (!strlen($row_format) + || strtolower($_REQUEST['new_row_format']) !== strtolower($row_format)) + ) { + $table_alters[] = 'ROW_FORMAT = ' + . PMA_Util::sqlAddSlashes($_REQUEST['new_row_format']); + } + + return $table_alters; +} + +/** + * set initial value of the set of variables, based on the current table engine + * + * @param string $tbl_storage_engine table storage engine + * + * @return array ($is_myisam_or_aria, $is_innodb, $is_isam, + * $is_berkeleydb, $is_aria, $is_pbxt) + */ +function PMA_setGlobalVariablesForEngine($tbl_storage_engine) +{ + $is_myisam_or_aria = $is_isam = $is_innodb = $is_berkeleydb + = $is_aria = $is_pbxt = false; + $upper_tbl_storage_engine = strtoupper($tbl_storage_engine); + + //Options that apply to MYISAM usually apply to ARIA + $is_myisam_or_aria = ($upper_tbl_storage_engine == 'MYISAM' + || $upper_tbl_storage_engine == 'ARIA' + || $upper_tbl_storage_engine == 'MARIA' + ); + $is_aria = ($upper_tbl_storage_engine == 'ARIA'); + + $is_isam = ($upper_tbl_storage_engine == 'ISAM'); + $is_innodb = ($upper_tbl_storage_engine == 'INNODB'); + $is_berkeleydb = ($upper_tbl_storage_engine == 'BERKELEYDB'); + $is_pbxt = ($upper_tbl_storage_engine == 'PBXT'); + + return array( + $is_myisam_or_aria, $is_innodb, $is_isam, + $is_berkeleydb, $is_aria, $is_pbxt + ); +} + +/** + * Get warning messages array + * + * @return array $warning_messages + */ +function PMA_getWarningMessagesArray() +{ + $warning_messages = array(); + foreach ($GLOBALS['dbi']->getWarnings() as $warning) { + // In MariaDB 5.1.44, when altering a table from Maria to MyISAM + // and if TRANSACTIONAL was set, the system reports an error; + // I discussed with a Maria developer and he agrees that this + // should not be reported with a Level of Error, so here + // I just ignore it. But there are other 1478 messages + // that it's better to show. + if (! ($_REQUEST['new_tbl_storage_engine'] == 'MyISAM' + && $warning['Code'] == '1478' + && $warning['Level'] == 'Error') + ) { + $warning_messages[] = $warning['Level'] . ': #' . $warning['Code'] + . ' ' . $warning['Message']; + } + } + return $warning_messages; +} + +/** + * Get SQL query and result after ran this SQL query for a partition operation + * has been requested by the user + * + * @return array $sql_query, $result + */ +function PMA_getQueryAndResultForPartition() +{ + $sql_query = 'ALTER TABLE ' + . PMA_Util::backquote($GLOBALS['table']) . ' ' + . $_REQUEST['partition_operation'] + . ' PARTITION ' + . $_REQUEST['partition_name'] . ';'; + $result = $GLOBALS['dbi']->query($sql_query); + + return array($sql_query, $result); +} + +?> diff --git a/phpMyAdmin/libraries/parse_analyze.inc.php b/phpMyAdmin/libraries/parse_analyze.inc.php new file mode 100644 index 0000000..eb7704e --- /dev/null +++ b/phpMyAdmin/libraries/parse_analyze.inc.php @@ -0,0 +1,144 @@ + $parsed_sql, + "analyzed_sql" => $analyzed_sql, + "reload" => $reload, + "drop_database" => $drop_database, + "is_explain" => $is_explain, + "is_delete" => $is_delete, + "is_affected" => $is_affected, + "is_replace" => $is_replace, + "is_insert" => $is_insert, + "is_maint" => $is_maint, + "is_show" => $is_show, + "is_analyse" => $is_analyse, + "is_export" => $is_export, + "is_group" => $is_group, + "is_func" => $is_func, + "is_count" => $is_count, + "is_select" => $is_select, + "is_procedure" => $is_procedure, + "is_subquery" => $is_subquery +); + + +// If the query is a Select, extract the db and table names and modify +// $db and $table, to have correct page headers, links and left frame. +// db and table name may be enclosed with backquotes, db is optionnal, +// query may contain aliases. + +/** + * @todo if there are more than one table name in the Select: + * - do not extract the first table name + * - do not show a table name in the page header + * - do not display the sub-pages links) + */ +if ($is_select) { + $prev_db = $db; + if (isset($analyzed_sql[0]['table_ref'][0]['table_true_name'])) { + $table = $analyzed_sql[0]['table_ref'][0]['table_true_name']; + } + if (isset($analyzed_sql[0]['table_ref'][0]['db']) + && strlen($analyzed_sql[0]['table_ref'][0]['db']) + ) { + $db = $analyzed_sql[0]['table_ref'][0]['db']; + } else { + $db = $prev_db; + } + // Don't change reload, if we already decided to reload in import + if (empty($reload) && empty($GLOBALS['is_ajax_request'])) { + $reload = ($db == $prev_db) ? 0 : 1; + } +} +?> diff --git a/phpMyAdmin/libraries/parse_analyze.lib.php b/phpMyAdmin/libraries/parse_analyze.lib.php deleted file mode 100644 index 6975920..0000000 --- a/phpMyAdmin/libraries/parse_analyze.lib.php +++ /dev/null @@ -1,59 +0,0 @@ - diff --git a/phpMyAdmin/libraries/php-gettext/gettext.inc b/phpMyAdmin/libraries/php-gettext/gettext.inc index c9f7dc0..00b9666 100644 --- a/phpMyAdmin/libraries/php-gettext/gettext.inc +++ b/phpMyAdmin/libraries/php-gettext/gettext.inc @@ -174,13 +174,14 @@ function _get_codeset($domain=null) { * Convert the given string to the encoding set by bind_textdomain_codeset. */ function _encode($text) { - $target_encoding = _get_codeset(); - if (function_exists("mb_detect_encoding")) { $source_encoding = mb_detect_encoding($text); - if ($source_encoding != $target_encoding) - $text = mb_convert_encoding($text, $target_encoding, $source_encoding); - } - return $text; + $target_encoding = _get_codeset(); + if ($source_encoding != $target_encoding) { + return mb_convert_encoding($text, $target_encoding, $source_encoding); + } + else { + return $text; + } } diff --git a/phpMyAdmin/libraries/phpseclib/Crypt/AES.php b/phpMyAdmin/libraries/phpseclib/Crypt/AES.php new file mode 100644 index 0000000..58c8b52 --- /dev/null +++ b/phpMyAdmin/libraries/phpseclib/Crypt/AES.php @@ -0,0 +1,612 @@ + + * setKey('abcdefghijklmnop'); + * + * $size = 10 * 1024; + * $plaintext = ''; + * for ($i = 0; $i < $size; $i++) { + * $plaintext.= 'a'; + * } + * + * echo $aes->decrypt($aes->encrypt($plaintext)); + * ?> + * + * + * 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 + * @author Jim Wigginton + * @copyright MMVIII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @version $Id: AES.php,v 1.7 2010/02/09 06:10:25 terrafrost Exp $ + * @link http://phpseclib.sourceforge.net + */ + +/** + * Include Crypt_Rijndael + */ +if (!class_exists('Crypt_Rijndael')) { + require_once 'Rijndael.php'; +} + +/**#@+ + * @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', -1); +/** + * 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', 1); +/** + * 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', 2); +/** + * 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', 3); +/** + * 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', 4); +/**#@-*/ + +/**#@+ + * @access private + * @see Crypt_AES::Crypt_AES() + */ +/** + * Toggles the internal implementation + */ +define('CRYPT_AES_MODE_INTERNAL', 1); +/** + * Toggles the mcrypt implementation + */ +define('CRYPT_AES_MODE_MCRYPT', 2); +/**#@-*/ + +/** + * Pure-PHP implementation of AES. + * + * @author Jim Wigginton + * @version 0.1.0 + * @access public + * @package Crypt_AES + */ +class Crypt_AES extends Crypt_Rijndael { + /** + * mcrypt resource for encryption + * + * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. + * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. + * + * @see Crypt_AES::encrypt() + * @var String + * @access private + */ + var $enmcrypt; + + /** + * mcrypt resource for decryption + * + * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. + * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. + * + * @see Crypt_AES::decrypt() + * @var String + * @access private + */ + var $demcrypt; + + /** + * mcrypt resource for CFB mode + * + * @see Crypt_AES::encrypt() + * @see Crypt_AES::decrypt() + * @var String + * @access private + */ + var $ecb; + + /** + * Default Constructor. + * + * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be + * CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC. If not explictly set, CRYPT_AES_MODE_CBC will be used. + * + * @param optional Integer $mode + * @return Crypt_AES + * @access public + */ + function Crypt_AES($mode = CRYPT_AES_MODE_CBC) + { + if ( !defined('CRYPT_AES_MODE') ) { + switch (true) { + case extension_loaded('mcrypt') && in_array('rijndael-128', mcrypt_list_algorithms()): + define('CRYPT_AES_MODE', CRYPT_AES_MODE_MCRYPT); + break; + default: + define('CRYPT_AES_MODE', CRYPT_AES_MODE_INTERNAL); + } + } + + switch ( CRYPT_AES_MODE ) { + case CRYPT_AES_MODE_MCRYPT: + switch ($mode) { + case CRYPT_AES_MODE_ECB: + $this->paddable = true; + $this->mode = MCRYPT_MODE_ECB; + break; + case CRYPT_AES_MODE_CTR: + // ctr doesn't have a constant associated with it even though it appears to be fairly widely + // supported. in lieu of knowing just how widely supported it is, i've, for now, opted not to + // include a compatibility layer. the layer has been implemented but, for now, is commented out. + $this->mode = 'ctr'; + //$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_AES_MODE_CTR; + break; + case CRYPT_AES_MODE_CFB: + $this->mode = 'ncfb'; + break; + case CRYPT_AES_MODE_OFB: + $this->mode = MCRYPT_MODE_NOFB; + break; + case CRYPT_AES_MODE_CBC: + default: + $this->paddable = true; + $this->mode = MCRYPT_MODE_CBC; + } + + $this->debuffer = $this->enbuffer = ''; + + break; + default: + switch ($mode) { + case CRYPT_AES_MODE_ECB: + $this->paddable = true; + $this->mode = CRYPT_RIJNDAEL_MODE_ECB; + break; + case CRYPT_AES_MODE_CTR: + $this->mode = CRYPT_RIJNDAEL_MODE_CTR; + break; + case CRYPT_AES_MODE_CFB: + $this->mode = CRYPT_RIJNDAEL_MODE_CFB; + break; + case CRYPT_AES_MODE_OFB: + $this->mode = CRYPT_RIJNDAEL_MODE_OFB; + break; + case CRYPT_AES_MODE_CBC: + default: + $this->paddable = true; + $this->mode = CRYPT_RIJNDAEL_MODE_CBC; + } + } + + if (CRYPT_AES_MODE == CRYPT_AES_MODE_INTERNAL) { + parent::Crypt_Rijndael($this->mode); + } + } + + /** + * Dummy function + * + * Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything. + * + * @access public + * @param Integer $length + */ + function setBlockLength($length) + { + return; + } + + + /** + * Sets the initialization vector. (optional) + * + * SetIV is not required when CRYPT_RIJNDAEL_MODE_ECB is being used. If not explictly set, it'll be assumed + * to be all zero's. + * + * @access public + * @param String $iv + */ + function setIV($iv) + { + parent::setIV($iv); + if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) { + $this->changed = true; + } + } + + /** + * Encrypts a message. + * + * $plaintext will be padded with up to 16 additional bytes. Other AES implementations may or may not pad in the + * same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following + * URL: + * + * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html} + * + * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does. + * strlen($plaintext) will still need to be a multiple of 16, however, arbitrary values can be added to make it that + * length. + * + * @see Crypt_AES::decrypt() + * @access public + * @param String $plaintext + */ + function encrypt($plaintext) + { + if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) { + $changed = $this->changed; + $this->_mcryptSetup(); + /* + if ($this->mode == CRYPT_AES_MODE_CTR) { + $iv = $this->encryptIV; + $xor = mcrypt_generic($this->enmcrypt, $this->_generate_xor(strlen($plaintext), $iv)); + $ciphertext = $plaintext ^ $xor; + if ($this->continuousBuffer) { + $this->encryptIV = $iv; + } + return $ciphertext; + } + */ + // re: http://phpseclib.sourceforge.net/cfb-demo.phps + // using mcrypt's default handing of CFB the above would output two different things. using phpseclib's + // rewritten CFB implementation the above outputs the same thing twice. + if ($this->mode == 'ncfb') { + if ($changed) { + $this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, ''); + mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); + } + + if (strlen($this->enbuffer)) { + $ciphertext = $plaintext ^ substr($this->encryptIV, strlen($this->enbuffer)); + $this->enbuffer.= $ciphertext; + if (strlen($this->enbuffer) == 16) { + $this->encryptIV = $this->enbuffer; + $this->enbuffer = ''; + mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); + } + $plaintext = substr($plaintext, strlen($ciphertext)); + } else { + $ciphertext = ''; + } + + $last_pos = strlen($plaintext) & 0xFFFFFFF0; + $ciphertext.= $last_pos ? mcrypt_generic($this->enmcrypt, substr($plaintext, 0, $last_pos)) : ''; + + if (strlen($plaintext) & 0xF) { + if (strlen($ciphertext)) { + $this->encryptIV = substr($ciphertext, -16); + } + $this->encryptIV = mcrypt_generic($this->ecb, $this->encryptIV); + $this->enbuffer = substr($plaintext, $last_pos) ^ $this->encryptIV; + $ciphertext.= $this->enbuffer; + } + + return $ciphertext; + } + + if ($this->paddable) { + $plaintext = $this->_pad($plaintext); + } + + $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); + + if (!$this->continuousBuffer) { + mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv); + } + + return $ciphertext; + } + + return parent::encrypt($plaintext); + } + + /** + * Decrypts a message. + * + * If strlen($ciphertext) is not a multiple of 16, null bytes will be added to the end of the string until it is. + * + * @see Crypt_AES::encrypt() + * @access public + * @param String $ciphertext + */ + function decrypt($ciphertext) + { + if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) { + $changed = $this->changed; + $this->_mcryptSetup(); + /* + if ($this->mode == CRYPT_AES_MODE_CTR) { + $iv = $this->decryptIV; + $xor = mcrypt_generic($this->enmcrypt, $this->_generate_xor(strlen($ciphertext), $iv)); + $plaintext = $ciphertext ^ $xor; + if ($this->continuousBuffer) { + $this->decryptIV = $iv; + } + return $plaintext; + } + */ + if ($this->mode == 'ncfb') { + if ($changed) { + $this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, ''); + mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); + } + + if (strlen($this->debuffer)) { + $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($this->debuffer)); + + $this->debuffer.= substr($ciphertext, 0, strlen($plaintext)); + if (strlen($this->debuffer) == 16) { + $this->decryptIV = $this->debuffer; + $this->debuffer = ''; + mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); + } + $ciphertext = substr($ciphertext, strlen($plaintext)); + } else { + $plaintext = ''; + } + + $last_pos = strlen($ciphertext) & 0xFFFFFFF0; + $plaintext.= $last_pos ? mdecrypt_generic($this->demcrypt, substr($ciphertext, 0, $last_pos)) : ''; + + if (strlen($ciphertext) & 0xF) { + if (strlen($plaintext)) { + $this->decryptIV = substr($ciphertext, $last_pos - 16, 16); + } + $this->decryptIV = mcrypt_generic($this->ecb, $this->decryptIV); + $this->debuffer = substr($ciphertext, $last_pos); + $plaintext.= $this->debuffer ^ $this->decryptIV; + } + + return $plaintext; + } + + if ($this->paddable) { + // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic : + // "The data is padded with "\0" to make sure the length of the data is n * blocksize." + $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 15) & 0xFFFFFFF0, chr(0)); + } + + $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); + + if (!$this->continuousBuffer) { + mcrypt_generic_init($this->demcrypt, $this->key, $this->iv); + } + + return $this->paddable ? $this->_unpad($plaintext) : $plaintext; + } + + return parent::decrypt($ciphertext); + } + + /** + * Setup mcrypt + * + * Validates all the variables. + * + * @access private + */ + function _mcryptSetup() + { + if (!$this->changed) { + return; + } + + if (!$this->explicit_key_length) { + // this just copied from Crypt_Rijndael::_setup() + $length = strlen($this->key) >> 2; + if ($length > 8) { + $length = 8; + } else if ($length < 4) { + $length = 4; + } + $this->Nk = $length; + $this->key_size = $length << 2; + } + + switch ($this->Nk) { + case 4: // 128 + $this->key_size = 16; + break; + case 5: // 160 + case 6: // 192 + $this->key_size = 24; + break; + case 7: // 224 + case 8: // 256 + $this->key_size = 32; + } + + $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, chr(0)); + $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, 16), 16, chr(0)); + + if (!isset($this->enmcrypt)) { + $mode = $this->mode; + //$mode = $this->mode == CRYPT_AES_MODE_CTR ? MCRYPT_MODE_ECB : $this->mode; + + $this->demcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, ''); + $this->enmcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, ''); + } // else should mcrypt_generic_deinit be called? + + mcrypt_generic_init($this->demcrypt, $this->key, $this->iv); + mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv); + + $this->changed = false; + } + + /** + * Encrypts a block + * + * Optimized over Crypt_Rijndael's implementation by means of loop unrolling. + * + * @see Crypt_Rijndael::_encryptBlock() + * @access private + * @param String $in + * @return String + */ + function _encryptBlock($in) + { + $state = unpack('N*word', $in); + + $Nr = $this->Nr; + $w = $this->w; + $t0 = $this->t0; + $t1 = $this->t1; + $t2 = $this->t2; + $t3 = $this->t3; + + // addRoundKey and reindex $state + $state = array( + $state['word1'] ^ $w[0][0], + $state['word2'] ^ $w[0][1], + $state['word3'] ^ $w[0][2], + $state['word4'] ^ $w[0][3] + ); + + // shiftRows + subWord + mixColumns + addRoundKey + // we could loop unroll this and use if statements to do more rounds as necessary, but, in my tests, that yields + // only a marginal improvement. since that also, imho, hinders the readability of the code, i've opted not to do it. + for ($round = 1; $round < $this->Nr; $round++) { + $state = array( + $t0[$state[0] & 0xFF000000] ^ $t1[$state[1] & 0x00FF0000] ^ $t2[$state[2] & 0x0000FF00] ^ $t3[$state[3] & 0x000000FF] ^ $w[$round][0], + $t0[$state[1] & 0xFF000000] ^ $t1[$state[2] & 0x00FF0000] ^ $t2[$state[3] & 0x0000FF00] ^ $t3[$state[0] & 0x000000FF] ^ $w[$round][1], + $t0[$state[2] & 0xFF000000] ^ $t1[$state[3] & 0x00FF0000] ^ $t2[$state[0] & 0x0000FF00] ^ $t3[$state[1] & 0x000000FF] ^ $w[$round][2], + $t0[$state[3] & 0xFF000000] ^ $t1[$state[0] & 0x00FF0000] ^ $t2[$state[1] & 0x0000FF00] ^ $t3[$state[2] & 0x000000FF] ^ $w[$round][3] + ); + + } + + // subWord + $state = array( + $this->_subWord($state[0]), + $this->_subWord($state[1]), + $this->_subWord($state[2]), + $this->_subWord($state[3]) + ); + + // shiftRows + addRoundKey + $state = array( + ($state[0] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[3] & 0x000000FF) ^ $this->w[$this->Nr][0], + ($state[1] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[0] & 0x000000FF) ^ $this->w[$this->Nr][1], + ($state[2] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[1] & 0x000000FF) ^ $this->w[$this->Nr][2], + ($state[3] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[2] & 0x000000FF) ^ $this->w[$this->Nr][3] + ); + + return pack('N*', $state[0], $state[1], $state[2], $state[3]); + } + + /** + * Decrypts a block + * + * Optimized over Crypt_Rijndael's implementation by means of loop unrolling. + * + * @see Crypt_Rijndael::_decryptBlock() + * @access private + * @param String $in + * @return String + */ + function _decryptBlock($in) + { + $state = unpack('N*word', $in); + + $Nr = $this->Nr; + $dw = $this->dw; + $dt0 = $this->dt0; + $dt1 = $this->dt1; + $dt2 = $this->dt2; + $dt3 = $this->dt3; + + // addRoundKey and reindex $state + $state = array( + $state['word1'] ^ $dw[$this->Nr][0], + $state['word2'] ^ $dw[$this->Nr][1], + $state['word3'] ^ $dw[$this->Nr][2], + $state['word4'] ^ $dw[$this->Nr][3] + ); + + + // invShiftRows + invSubBytes + invMixColumns + addRoundKey + for ($round = $this->Nr - 1; $round > 0; $round--) { + $state = array( + $dt0[$state[0] & 0xFF000000] ^ $dt1[$state[3] & 0x00FF0000] ^ $dt2[$state[2] & 0x0000FF00] ^ $dt3[$state[1] & 0x000000FF] ^ $dw[$round][0], + $dt0[$state[1] & 0xFF000000] ^ $dt1[$state[0] & 0x00FF0000] ^ $dt2[$state[3] & 0x0000FF00] ^ $dt3[$state[2] & 0x000000FF] ^ $dw[$round][1], + $dt0[$state[2] & 0xFF000000] ^ $dt1[$state[1] & 0x00FF0000] ^ $dt2[$state[0] & 0x0000FF00] ^ $dt3[$state[3] & 0x000000FF] ^ $dw[$round][2], + $dt0[$state[3] & 0xFF000000] ^ $dt1[$state[2] & 0x00FF0000] ^ $dt2[$state[1] & 0x0000FF00] ^ $dt3[$state[0] & 0x000000FF] ^ $dw[$round][3] + ); + } + + // invShiftRows + invSubWord + addRoundKey + $state = array( + $this->_invSubWord(($state[0] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[1] & 0x000000FF)) ^ $dw[0][0], + $this->_invSubWord(($state[1] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[2] & 0x000000FF)) ^ $dw[0][1], + $this->_invSubWord(($state[2] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[3] & 0x000000FF)) ^ $dw[0][2], + $this->_invSubWord(($state[3] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[0] & 0x000000FF)) ^ $dw[0][3] + ); + + return pack('N*', $state[0], $state[1], $state[2], $state[3]); + } +} + +// vim: ts=4:sw=4:et: +// vim6: fdl=1: +?> diff --git a/phpMyAdmin/libraries/phpseclib/Crypt/Rijndael.php b/phpMyAdmin/libraries/phpseclib/Crypt/Rijndael.php new file mode 100644 index 0000000..b5aef38 --- /dev/null +++ b/phpMyAdmin/libraries/phpseclib/Crypt/Rijndael.php @@ -0,0 +1,1479 @@ + + * setKey('abcdefghijklmnop'); + * + * $size = 10 * 1024; + * $plaintext = ''; + * for ($i = 0; $i < $size; $i++) { + * $plaintext.= 'a'; + * } + * + * echo $rijndael->decrypt($rijndael->encrypt($plaintext)); + * ?> + * + * + * 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_Rijndael + * @author Jim Wigginton + * @copyright MMVIII Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @version $Id: Rijndael.php,v 1.12 2010/02/09 06:10:26 terrafrost Exp $ + * @link http://phpseclib.sourceforge.net + */ + +/**#@+ + * @access public + * @see Crypt_Rijndael::encrypt() + * @see Crypt_Rijndael::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_RIJNDAEL_MODE_CTR', -1); +/** + * 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_RIJNDAEL_MODE_ECB', 1); +/** + * 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_RIJNDAEL_MODE_CBC', 2); +/** + * Encrypt / decrypt using the Cipher Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 + */ +define('CRYPT_RIJNDAEL_MODE_CFB', 3); +/** + * Encrypt / decrypt using the Cipher Feedback mode. + * + * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 + */ +define('CRYPT_RIJNDAEL_MODE_OFB', 4); +/**#@-*/ + +/**#@+ + * @access private + * @see Crypt_Rijndael::Crypt_Rijndael() + */ +/** + * Toggles the internal implementation + */ +define('CRYPT_RIJNDAEL_MODE_INTERNAL', 1); +/** + * Toggles the mcrypt implementation + */ +define('CRYPT_RIJNDAEL_MODE_MCRYPT', 2); +/**#@-*/ + +/** + * Pure-PHP implementation of Rijndael. + * + * @author Jim Wigginton + * @version 0.1.0 + * @access public + * @package Crypt_Rijndael + */ +class Crypt_Rijndael { + /** + * The Encryption Mode + * + * @see Crypt_Rijndael::Crypt_Rijndael() + * @var Integer + * @access private + */ + var $mode; + + /** + * The Key + * + * @see Crypt_Rijndael::setKey() + * @var String + * @access private + */ + var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + + /** + * The Initialization Vector + * + * @see Crypt_Rijndael::setIV() + * @var String + * @access private + */ + var $iv = ''; + + /** + * A "sliding" Initialization Vector + * + * @see Crypt_Rijndael::enableContinuousBuffer() + * @var String + * @access private + */ + var $encryptIV = ''; + + /** + * A "sliding" Initialization Vector + * + * @see Crypt_Rijndael::enableContinuousBuffer() + * @var String + * @access private + */ + var $decryptIV = ''; + + /** + * Continuous Buffer status + * + * @see Crypt_Rijndael::enableContinuousBuffer() + * @var Boolean + * @access private + */ + var $continuousBuffer = false; + + /** + * Padding status + * + * @see Crypt_Rijndael::enablePadding() + * @var Boolean + * @access private + */ + var $padding = true; + + /** + * Does the key schedule need to be (re)calculated? + * + * @see setKey() + * @see setBlockLength() + * @see setKeyLength() + * @var Boolean + * @access private + */ + var $changed = true; + + /** + * Has the key length explicitly been set or should it be derived from the key, itself? + * + * @see setKeyLength() + * @var Boolean + * @access private + */ + var $explicit_key_length = false; + + /** + * The Key Schedule + * + * @see _setup() + * @var Array + * @access private + */ + var $w; + + /** + * The Inverse Key Schedule + * + * @see _setup() + * @var Array + * @access private + */ + var $dw; + + /** + * The Block Length + * + * @see setBlockLength() + * @var Integer + * @access private + * @internal The max value is 32, the min value is 16. All valid values are multiples of 4. Exists in conjunction with + * $Nb because we need this value and not $Nb to pad strings appropriately. + */ + var $block_size = 16; + + /** + * The Block Length divided by 32 + * + * @see setBlockLength() + * @var Integer + * @access private + * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size + * because the encryption / decryption / key schedule creation requires this number and not $block_size. We could + * derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu + * of that, we'll just precompute it once. + * + */ + var $Nb = 4; + + /** + * The Key Length + * + * @see setKeyLength() + * @var Integer + * @access private + * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $key_size + * because the encryption / decryption / key schedule creation requires this number and not $key_size. We could + * derive this from $key_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu + * of that, we'll just precompute it once. + */ + var $key_size = 16; + + /** + * The Key Length divided by 32 + * + * @see setKeyLength() + * @var Integer + * @access private + * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4 + */ + var $Nk = 4; + + /** + * The Number of Rounds + * + * @var Integer + * @access private + * @internal The max value is 14, the min value is 10. + */ + var $Nr; + + /** + * Shift offsets + * + * @var Array + * @access private + */ + var $c; + + /** + * Precomputed mixColumns table + * + * @see Crypt_Rijndael() + * @var Array + * @access private + */ + var $t0; + + /** + * Precomputed mixColumns table + * + * @see Crypt_Rijndael() + * @var Array + * @access private + */ + var $t1; + + /** + * Precomputed mixColumns table + * + * @see Crypt_Rijndael() + * @var Array + * @access private + */ + var $t2; + + /** + * Precomputed mixColumns table + * + * @see Crypt_Rijndael() + * @var Array + * @access private + */ + var $t3; + + /** + * Precomputed invMixColumns table + * + * @see Crypt_Rijndael() + * @var Array + * @access private + */ + var $dt0; + + /** + * Precomputed invMixColumns table + * + * @see Crypt_Rijndael() + * @var Array + * @access private + */ + var $dt1; + + /** + * Precomputed invMixColumns table + * + * @see Crypt_Rijndael() + * @var Array + * @access private + */ + var $dt2; + + /** + * Precomputed invMixColumns table + * + * @see Crypt_Rijndael() + * @var Array + * @access private + */ + var $dt3; + + /** + * Is the mode one that is paddable? + * + * @see Crypt_Rijndael::Crypt_Rijndael() + * @var Boolean + * @access private + */ + var $paddable = false; + + /** + * Encryption buffer for CTR, OFB and CFB modes + * + * @see Crypt_Rijndael::encrypt() + * @var String + * @access private + */ + var $enbuffer = array('encrypted' => '', 'xor' => ''); + + /** + * Decryption buffer for CTR, OFB and CFB modes + * + * @see Crypt_Rijndael::decrypt() + * @var String + * @access private + */ + var $debuffer = array('ciphertext' => ''); + + /** + * Default Constructor. + * + * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be + * CRYPT_RIJNDAEL_MODE_ECB or CRYPT_RIJNDAEL_MODE_CBC. If not explictly set, CRYPT_RIJNDAEL_MODE_CBC will be used. + * + * @param optional Integer $mode + * @return Crypt_Rijndael + * @access public + */ + function Crypt_Rijndael($mode = CRYPT_RIJNDAEL_MODE_CBC) + { + switch ($mode) { + case CRYPT_RIJNDAEL_MODE_ECB: + case CRYPT_RIJNDAEL_MODE_CBC: + $this->paddable = true; + $this->mode = $mode; + break; + case CRYPT_RIJNDAEL_MODE_CTR: + case CRYPT_RIJNDAEL_MODE_CFB: + case CRYPT_RIJNDAEL_MODE_OFB: + $this->mode = $mode; + break; + default: + $this->paddable = true; + $this->mode = CRYPT_RIJNDAEL_MODE_CBC; + } + + $t3 = &$this->t3; + $t2 = &$this->t2; + $t1 = &$this->t1; + $t0 = &$this->t0; + + $dt3 = &$this->dt3; + $dt2 = &$this->dt2; + $dt1 = &$this->dt1; + $dt0 = &$this->dt0; + + // according to (section 5.2.1), + // precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so + // those are the names we'll use. + $t3 = array( + 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491, + 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC, + 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB, + 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B, + 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83, + 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A, + 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F, + 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA, + 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B, + 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713, + 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6, + 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85, + 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411, + 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B, + 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1, + 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF, + 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E, + 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6, + 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B, + 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD, + 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8, + 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2, + 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049, + 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810, + 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197, + 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F, + 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C, + 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927, + 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733, + 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5, + 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0, + 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C + ); + + $dt3 = array( + 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B, + 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5, + 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B, + 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E, + 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D, + 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9, + 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66, + 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED, + 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4, + 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD, + 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60, + 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79, + 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C, + 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24, + 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C, + 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814, + 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B, + 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084, + 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077, + 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22, + 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F, + 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582, + 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB, + 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF, + 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035, + 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17, + 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46, + 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D, + 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A, + 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678, + 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF, + 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0 + ); + + for ($i = 0; $i < 256; $i++) { + $t2[$i << 8] = (($t3[$i] << 8) & 0xFFFFFF00) | (($t3[$i] >> 24) & 0x000000FF); + $t1[$i << 16] = (($t3[$i] << 16) & 0xFFFF0000) | (($t3[$i] >> 16) & 0x0000FFFF); + $t0[$i << 24] = (($t3[$i] << 24) & 0xFF000000) | (($t3[$i] >> 8) & 0x00FFFFFF); + + $dt2[$i << 8] = (($this->dt3[$i] << 8) & 0xFFFFFF00) | (($dt3[$i] >> 24) & 0x000000FF); + $dt1[$i << 16] = (($this->dt3[$i] << 16) & 0xFFFF0000) | (($dt3[$i] >> 16) & 0x0000FFFF); + $dt0[$i << 24] = (($this->dt3[$i] << 24) & 0xFF000000) | (($dt3[$i] >> 8) & 0x00FFFFFF); + } + } + + /** + * Sets the key. + * + * Keys can be of any length. Rijndael, itself, requires the use of a key that's between 128-bits and 256-bits long and + * whose length is a multiple of 32. If the key is less than 256-bits and the key length isn't set, we round the length + * up to the closest valid key length, padding $key with null bytes. If the key is more than 256-bits, we trim the + * excess bits. + * + * If the key is not explicitly set, it'll be assumed to be all null bytes. + * + * @access public + * @param String $key + */ + function setKey($key) + { + $this->key = $key; + $this->changed = true; + } + + /** + * Sets the initialization vector. (optional) + * + * SetIV is not required when CRYPT_RIJNDAEL_MODE_ECB is being used. If not explictly set, it'll be assumed + * to be all zero's. + * + * @access public + * @param String $iv + */ + function setIV($iv) + { + $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, $this->block_size), $this->block_size, chr(0)); + } + + /** + * Sets the key length + * + * Valid key lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to + * 128. If the length is greater then 128 and invalid, it will be rounded down to the closest valid amount. + * + * @access public + * @param Integer $length + */ + function setKeyLength($length) + { + $length >>= 5; + if ($length > 8) { + $length = 8; + } else if ($length < 4) { + $length = 4; + } + $this->Nk = $length; + $this->key_size = $length << 2; + + $this->explicit_key_length = true; + $this->changed = true; + } + + /** + * Sets the password. + * + * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows: + * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}: + * $hash, $salt, $count + * Set $dkLen by calling setKeyLength() + * + * @param String $password + * @param optional String $method + * @access public + */ + function setPassword($password, $method = 'pbkdf2') + { + $key = ''; + + switch ($method) { + default: // 'pbkdf2' + list(, , $hash, $salt, $count) = func_get_args(); + if (!isset($hash)) { + $hash = 'sha1'; + } + // WPA and WPA use the SSID as the salt + if (!isset($salt)) { + $salt = 'phpseclib/salt'; + } + // RFC2898#section-4.2 uses 1,000 iterations by default + // WPA and WPA2 use 4,096. + if (!isset($count)) { + $count = 1000; + } + + if (!class_exists('Crypt_Hash')) { + require_once('Crypt/Hash.php'); + } + + $i = 1; + while (strlen($key) < $this->key_size) { // $dkLen == $this->key_size + //$dk.= $this->_pbkdf($password, $salt, $count, $i++); + $hmac = new Crypt_Hash(); + $hmac->setHash($hash); + $hmac->setKey($password); + $f = $u = $hmac->hash($salt . pack('N', $i++)); + for ($j = 2; $j <= $count; $j++) { + $u = $hmac->hash($u); + $f^= $u; + } + $key.= $f; + } + } + + $this->setKey(substr($key, 0, $this->key_size)); + } + + /** + * Sets the block length + * + * Valid block lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to + * 128. If the length is greater then 128 and invalid, it will be rounded down to the closest valid amount. + * + * @access public + * @param Integer $length + */ + function setBlockLength($length) + { + $length >>= 5; + if ($length > 8) { + $length = 8; + } else if ($length < 4) { + $length = 4; + } + $this->Nb = $length; + $this->block_size = $length << 2; + $this->changed = true; + } + + /** + * Generate CTR XOR encryption key + * + * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the + * plaintext / ciphertext in CTR mode. + * + * @see Crypt_Rijndael::decrypt() + * @see Crypt_Rijndael::encrypt() + * @access public + * @param Integer $length + * @param String $iv + */ + function _generate_xor($length, &$iv) + { + $xor = ''; + $block_size = $this->block_size; + $num_blocks = floor(($length + ($block_size - 1)) / $block_size); + for ($i = 0; $i < $num_blocks; $i++) { + $xor.= $iv; + for ($j = 4; $j <= $block_size; $j+=4) { + $temp = substr($iv, -$j, 4); + switch ($temp) { + case "\xFF\xFF\xFF\xFF": + $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4); + break; + case "\x7F\xFF\xFF\xFF": + $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4); + break 2; + default: + extract(unpack('Ncount', $temp)); + $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4); + break 2; + } + } + } + + return $xor; + } + + /** + * Encrypts a message. + * + * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other Rjindael + * implementations may or may not pad in the same manner. Other common approaches to padding and the reasons why it's + * necessary are discussed in the following + * URL: + * + * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html} + * + * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does. + * strlen($plaintext) will still need to be a multiple of 8, however, arbitrary values can be added to make it that + * length. + * + * @see Crypt_Rijndael::decrypt() + * @access public + * @param String $plaintext + */ + function encrypt($plaintext) + { + $this->_setup(); + if ($this->paddable) { + $plaintext = $this->_pad($plaintext); + } + + $block_size = $this->block_size; + $buffer = &$this->enbuffer; + $continuousBuffer = $this->continuousBuffer; + $ciphertext = ''; + switch ($this->mode) { + case CRYPT_RIJNDAEL_MODE_ECB: + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size)); + } + break; + case CRYPT_RIJNDAEL_MODE_CBC: + $xor = $this->encryptIV; + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $block = substr($plaintext, $i, $block_size); + $block = $this->_encryptBlock($block ^ $xor); + $xor = $block; + $ciphertext.= $block; + } + if ($this->continuousBuffer) { + $this->encryptIV = $xor; + } + break; + case CRYPT_RIJNDAEL_MODE_CTR: + $xor = $this->encryptIV; + if (!empty($buffer['encrypted'])) { + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $block = substr($plaintext, $i, $block_size); + $buffer['encrypted'].= $this->_encryptBlock($this->_generate_xor($block_size, $xor)); + $key = $this->_string_shift($buffer['encrypted'], $block_size); + $ciphertext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $block = substr($plaintext, $i, $block_size); + $key = $this->_encryptBlock($this->_generate_xor($block_size, $xor)); + $ciphertext.= $block ^ $key; + } + } + if ($this->continuousBuffer) { + $this->encryptIV = $xor; + if ($start = strlen($plaintext) % $block_size) { + $buffer['encrypted'] = substr($key, $start) . $buffer['encrypted']; + } + } + break; + case CRYPT_RIJNDAEL_MODE_CFB: + if (!empty($buffer['xor'])) { + $ciphertext = $plaintext ^ $buffer['xor']; + $iv = $buffer['encrypted'] . $ciphertext; + $start = strlen($ciphertext); + $buffer['encrypted'].= $ciphertext; + $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext)); + } else { + $ciphertext = ''; + $iv = $this->encryptIV; + $start = 0; + } + + for ($i = $start; $i < strlen($plaintext); $i+=$block_size) { + $block = substr($plaintext, $i, $block_size); + $xor = $this->_encryptBlock($iv); + $iv = $block ^ $xor; + if ($continuousBuffer && strlen($iv) != $block_size) { + $buffer = array( + 'encrypted' => $iv, + 'xor' => substr($xor, strlen($iv)) + ); + } + $ciphertext.= $iv; + } + + if ($this->continuousBuffer) { + $this->encryptIV = $iv; + } + break; + case CRYPT_RIJNDAEL_MODE_OFB: + $xor = $this->encryptIV; + if (strlen($buffer)) { + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $xor = $this->_encryptBlock($xor); + $buffer.= $xor; + $key = $this->_string_shift($buffer, $block_size); + $ciphertext.= substr($plaintext, $i, $block_size) ^ $key; + } + } else { + for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + $xor = $this->_encryptBlock($xor); + $ciphertext.= substr($plaintext, $i, $block_size) ^ $xor; + } + $key = $xor; + } + if ($this->continuousBuffer) { + $this->encryptIV = $xor; + if ($start = strlen($plaintext) % $block_size) { + $buffer = substr($key, $start) . $buffer; + } + } + } + + return $ciphertext; + } + + /** + * Decrypts a message. + * + * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until + * it is. + * + * @see Crypt_Rijndael::encrypt() + * @access public + * @param String $ciphertext + */ + function decrypt($ciphertext) + { + $this->_setup(); + + if ($this->paddable) { + // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic : + // "The data is padded with "\0" to make sure the length of the data is n * blocksize." + $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0)); + } + + $block_size = $this->block_size; + $buffer = &$this->debuffer; + $continuousBuffer = $this->continuousBuffer; + $plaintext = ''; + switch ($this->mode) { + case CRYPT_RIJNDAEL_MODE_ECB: + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size)); + } + break; + case CRYPT_RIJNDAEL_MODE_CBC: + $xor = $this->decryptIV; + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $block = substr($ciphertext, $i, $block_size); + $plaintext.= $this->_decryptBlock($block) ^ $xor; + $xor = $block; + } + if ($this->continuousBuffer) { + $this->decryptIV = $xor; + } + break; + case CRYPT_RIJNDAEL_MODE_CTR: + $xor = $this->decryptIV; + if (!empty($buffer['ciphertext'])) { + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $block = substr($ciphertext, $i, $block_size); + $buffer['ciphertext'].= $this->_encryptBlock($this->_generate_xor($block_size, $xor)); + $key = $this->_string_shift($buffer['ciphertext'], $block_size); + $plaintext.= $block ^ $key; + } + } else { + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $block = substr($ciphertext, $i, $block_size); + $key = $this->_encryptBlock($this->_generate_xor($block_size, $xor)); + $plaintext.= $block ^ $key; + } + } + if ($this->continuousBuffer) { + $this->decryptIV = $xor; + if ($start = strlen($ciphertext) % $block_size) { + $buffer['ciphertext'] = substr($key, $start) . $buffer['encrypted']; + } + } + break; + case CRYPT_RIJNDAEL_MODE_CFB: + if (!empty($buffer['ciphertext'])) { + $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext'])); + $buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext)); + if (strlen($buffer['ciphertext']) == $block_size) { + $xor = $this->_encryptBlock($buffer['ciphertext']); + $buffer['ciphertext'] = ''; + } + $start = strlen($plaintext); + $block = $this->decryptIV; + } else { + $plaintext = ''; + $xor = $this->_encryptBlock($this->decryptIV); + $start = 0; + } + + for ($i = $start; $i < strlen($ciphertext); $i+=$block_size) { + $block = substr($ciphertext, $i, $block_size); + $plaintext.= $block ^ $xor; + if ($continuousBuffer && strlen($block) != $block_size) { + $buffer['ciphertext'].= $block; + $block = $xor; + } else if (strlen($block) == $block_size) { + $xor = $this->_encryptBlock($block); + } + } + if ($this->continuousBuffer) { + $this->decryptIV = $block; + } + break; + case CRYPT_RIJNDAEL_MODE_OFB: + $xor = $this->decryptIV; + if (strlen($buffer)) { + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $xor = $this->_encryptBlock($xor); + $buffer.= $xor; + $key = $this->_string_shift($buffer, $block_size); + $plaintext.= substr($ciphertext, $i, $block_size) ^ $key; + } + } else { + for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + $xor = $this->_encryptBlock($xor); + $plaintext.= substr($ciphertext, $i, $block_size) ^ $xor; + } + $key = $xor; + } + if ($this->continuousBuffer) { + $this->decryptIV = $xor; + if ($start = strlen($ciphertext) % $block_size) { + $buffer = substr($key, $start) . $buffer; + } + } + } + + return $this->paddable ? $this->_unpad($plaintext) : $plaintext; + } + + /** + * Encrypts a block + * + * @access private + * @param String $in + * @return String + */ + function _encryptBlock($in) + { + $state = array(); + $words = unpack('N*word', $in); + + $w = $this->w; + $t0 = $this->t0; + $t1 = $this->t1; + $t2 = $this->t2; + $t3 = $this->t3; + $Nb = $this->Nb; + $Nr = $this->Nr; + $c = $this->c; + + // addRoundKey + $i = 0; + foreach ($words as $word) { + $state[] = $word ^ $w[0][$i++]; + } + + // fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components - + // subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding + // Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf. + // Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization. + // Unfortunately, the description given there is not quite correct. Per aes.spec.v316.pdf#page=19 [1], + // equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well. + + // [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf + $temp = array(); + for ($round = 1; $round < $Nr; $round++) { + $i = 0; // $c[0] == 0 + $j = $c[1]; + $k = $c[2]; + $l = $c[3]; + + while ($i < $this->Nb) { + $temp[$i] = $t0[$state[$i] & 0xFF000000] ^ + $t1[$state[$j] & 0x00FF0000] ^ + $t2[$state[$k] & 0x0000FF00] ^ + $t3[$state[$l] & 0x000000FF] ^ + $w[$round][$i]; + $i++; + $j = ($j + 1) % $Nb; + $k = ($k + 1) % $Nb; + $l = ($l + 1) % $Nb; + } + + for ($i = 0; $i < $Nb; $i++) { + $state[$i] = $temp[$i]; + } + } + + // subWord + for ($i = 0; $i < $Nb; $i++) { + $state[$i] = $this->_subWord($state[$i]); + } + + // shiftRows + addRoundKey + $i = 0; // $c[0] == 0 + $j = $c[1]; + $k = $c[2]; + $l = $c[3]; + while ($i < $this->Nb) { + $temp[$i] = ($state[$i] & 0xFF000000) ^ + ($state[$j] & 0x00FF0000) ^ + ($state[$k] & 0x0000FF00) ^ + ($state[$l] & 0x000000FF) ^ + $w[$Nr][$i]; + $i++; + $j = ($j + 1) % $Nb; + $k = ($k + 1) % $Nb; + $l = ($l + 1) % $Nb; + } + $state = $temp; + + array_unshift($state, 'N*'); + + return call_user_func_array('pack', $state); + } + + /** + * Decrypts a block + * + * @access private + * @param String $in + * @return String + */ + function _decryptBlock($in) + { + $state = array(); + $words = unpack('N*word', $in); + + $num_states = count($state); + $dw = $this->dw; + $dt0 = $this->dt0; + $dt1 = $this->dt1; + $dt2 = $this->dt2; + $dt3 = $this->dt3; + $Nb = $this->Nb; + $Nr = $this->Nr; + $c = $this->c; + + // addRoundKey + $i = 0; + foreach ($words as $word) { + $state[] = $word ^ $dw[$Nr][$i++]; + } + + $temp = array(); + for ($round = $Nr - 1; $round > 0; $round--) { + $i = 0; // $c[0] == 0 + $j = $Nb - $c[1]; + $k = $Nb - $c[2]; + $l = $Nb - $c[3]; + + while ($i < $Nb) { + $temp[$i] = $dt0[$state[$i] & 0xFF000000] ^ + $dt1[$state[$j] & 0x00FF0000] ^ + $dt2[$state[$k] & 0x0000FF00] ^ + $dt3[$state[$l] & 0x000000FF] ^ + $dw[$round][$i]; + $i++; + $j = ($j + 1) % $Nb; + $k = ($k + 1) % $Nb; + $l = ($l + 1) % $Nb; + } + + for ($i = 0; $i < $Nb; $i++) { + $state[$i] = $temp[$i]; + } + } + + // invShiftRows + invSubWord + addRoundKey + $i = 0; // $c[0] == 0 + $j = $Nb - $c[1]; + $k = $Nb - $c[2]; + $l = $Nb - $c[3]; + + while ($i < $Nb) { + $temp[$i] = $dw[0][$i] ^ + $this->_invSubWord(($state[$i] & 0xFF000000) | + ($state[$j] & 0x00FF0000) | + ($state[$k] & 0x0000FF00) | + ($state[$l] & 0x000000FF)); + $i++; + $j = ($j + 1) % $Nb; + $k = ($k + 1) % $Nb; + $l = ($l + 1) % $Nb; + } + + $state = $temp; + + array_unshift($state, 'N*'); + + return call_user_func_array('pack', $state); + } + + /** + * Setup Rijndael + * + * Validates all the variables and calculates $Nr - the number of rounds that need to be performed - and $w - the key + * key schedule. + * + * @access private + */ + function _setup() + { + // Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field. + // See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse + static $rcon = array(0, + 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, + 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, + 0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000, + 0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000, + 0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000, + 0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000 + ); + + if (!$this->changed) { + return; + } + + if (!$this->explicit_key_length) { + // we do >> 2, here, and not >> 5, as we do above, since strlen($this->key) tells us the number of bytes - not bits + $length = strlen($this->key) >> 2; + if ($length > 8) { + $length = 8; + } else if ($length < 4) { + $length = 4; + } + $this->Nk = $length; + $this->key_size = $length << 2; + } + + $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, chr(0)); + $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, chr(0)); + + // see Rijndael-ammended.pdf#page=44 + $this->Nr = max($this->Nk, $this->Nb) + 6; + + // shift offsets for Nb = 5, 7 are defined in Rijndael-ammended.pdf#page=44, + // "Table 8: Shift offsets in Shiftrow for the alternative block lengths" + // shift offsets for Nb = 4, 6, 8 are defined in Rijndael-ammended.pdf#page=14, + // "Table 2: Shift offsets for different block lengths" + switch ($this->Nb) { + case 4: + case 5: + case 6: + $this->c = array(0, 1, 2, 3); + break; + case 7: + $this->c = array(0, 1, 2, 4); + break; + case 8: + $this->c = array(0, 1, 3, 4); + } + + $key = $this->key; + + $w = array_values(unpack('N*words', $key)); + + $length = $this->Nb * ($this->Nr + 1); + for ($i = $this->Nk; $i < $length; $i++) { + $temp = $w[$i - 1]; + if ($i % $this->Nk == 0) { + // according to , "the size of an integer is platform-dependent". + // on a 32-bit machine, it's 32-bits, and on a 64-bit machine, it's 64-bits. on a 32-bit machine, + // 0xFFFFFFFF << 8 == 0xFFFFFF00, but on a 64-bit machine, it equals 0xFFFFFFFF00. as such, doing 'and' + // with 0xFFFFFFFF (or 0xFFFFFF00) on a 32-bit machine is unnecessary, but on a 64-bit machine, it is. + $temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); // rotWord + $temp = $this->_subWord($temp) ^ $rcon[$i / $this->Nk]; + } else if ($this->Nk > 6 && $i % $this->Nk == 4) { + $temp = $this->_subWord($temp); + } + $w[$i] = $w[$i - $this->Nk] ^ $temp; + } + + // convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns + // and generate the inverse key schedule. more specifically, + // according to (section 5.3.3), + // "The key expansion for the Inverse Cipher is defined as follows: + // 1. Apply the Key Expansion. + // 2. Apply InvMixColumn to all Round Keys except the first and the last one." + // also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher" + $temp = array(); + for ($i = $row = $col = 0; $i < $length; $i++, $col++) { + if ($col == $this->Nb) { + if ($row == 0) { + $this->dw[0] = $this->w[0]; + } else { + // subWord + invMixColumn + invSubWord = invMixColumn + $j = 0; + while ($j < $this->Nb) { + $dw = $this->_subWord($this->w[$row][$j]); + $temp[$j] = $this->dt0[$dw & 0xFF000000] ^ + $this->dt1[$dw & 0x00FF0000] ^ + $this->dt2[$dw & 0x0000FF00] ^ + $this->dt3[$dw & 0x000000FF]; + $j++; + } + $this->dw[$row] = $temp; + } + + $col = 0; + $row++; + } + $this->w[$row][$col] = $w[$i]; + } + + $this->dw[$row] = $this->w[$row]; + + $this->changed = false; + } + + /** + * Performs S-Box substitutions + * + * @access private + */ + function _subWord($word) + { + static $sbox0, $sbox1, $sbox2, $sbox3; + + if (empty($sbox0)) { + $sbox0 = array( + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, + 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, + 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, + 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, + 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, + 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, + 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, + 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, + 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, + 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, + 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 + ); + + $sbox1 = array(); + $sbox2 = array(); + $sbox3 = array(); + + for ($i = 0; $i < 256; $i++) { + $sbox1[$i << 8] = $sbox0[$i] << 8; + $sbox2[$i << 16] = $sbox0[$i] << 16; + $sbox3[$i << 24] = $sbox0[$i] << 24; + } + } + + return $sbox0[$word & 0x000000FF] | + $sbox1[$word & 0x0000FF00] | + $sbox2[$word & 0x00FF0000] | + $sbox3[$word & 0xFF000000]; + } + + /** + * Performs inverse S-Box substitutions + * + * @access private + */ + function _invSubWord($word) + { + static $sbox0, $sbox1, $sbox2, $sbox3; + + if (empty($sbox0)) { + $sbox0 = array( + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, + 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, + 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, + 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, + 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, + 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, + 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, + 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, + 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, + 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, + 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D + ); + + $sbox1 = array(); + $sbox2 = array(); + $sbox3 = array(); + + for ($i = 0; $i < 256; $i++) { + $sbox1[$i << 8] = $sbox0[$i] << 8; + $sbox2[$i << 16] = $sbox0[$i] << 16; + $sbox3[$i << 24] = $sbox0[$i] << 24; + } + } + + return $sbox0[$word & 0x000000FF] | + $sbox1[$word & 0x0000FF00] | + $sbox2[$word & 0x00FF0000] | + $sbox3[$word & 0xFF000000]; + } + + /** + * Pad "packets". + * + * Rijndael works by encrypting between sixteen and thirty-two bytes at a time, provided that number is also a multiple + * of four. If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to + * pad the input so that it is of the proper length. + * + * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH, + * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping + * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is + * transmitted separately) + * + * @see Crypt_Rijndael::disablePadding() + * @access public + */ + function enablePadding() + { + $this->padding = true; + } + + /** + * Do not pad packets. + * + * @see Crypt_Rijndael::enablePadding() + * @access public + */ + function disablePadding() + { + $this->padding = false; + } + + /** + * Pads a string + * + * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize. + * $block_size - (strlen($text) % $block_size) bytes are added, each of which is equal to + * chr($block_size - (strlen($text) % $block_size) + * + * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless + * and padding will, hence forth, be enabled. + * + * @see Crypt_Rijndael::_unpad() + * @access private + */ + function _pad($text) + { + $length = strlen($text); + + if (!$this->padding) { + if ($length % $this->block_size == 0) { + return $text; + } else { + user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})", E_USER_NOTICE); + $this->padding = true; + } + } + + $pad = $this->block_size - ($length % $this->block_size); + + return str_pad($text, $length + $pad, chr($pad)); + } + + /** + * Unpads a string. + * + * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong + * and false will be returned. + * + * @see Crypt_Rijndael::_pad() + * @access private + */ + function _unpad($text) + { + if (!$this->padding) { + return $text; + } + + $length = ord($text[strlen($text) - 1]); + + if (!$length || $length > $this->block_size) { + return false; + } + + return substr($text, 0, -$length); + } + + /** + * Treat consecutive "packets" as if they are a continuous buffer. + * + * Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets + * will yield different outputs: + * + * + * echo $rijndael->encrypt(substr($plaintext, 0, 16)); + * echo $rijndael->encrypt(substr($plaintext, 16, 16)); + * + * + * echo $rijndael->encrypt($plaintext); + * + * + * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates + * another, as demonstrated with the following: + * + * + * $rijndael->encrypt(substr($plaintext, 0, 16)); + * echo $rijndael->decrypt($des->encrypt(substr($plaintext, 16, 16))); + * + * + * echo $rijndael->decrypt($des->encrypt(substr($plaintext, 16, 16))); + * + * + * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different + * outputs. The reason is due to the fact that the initialization vector's change after every encryption / + * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant. + * + * Put another way, when the continuous buffer is enabled, the state of the Crypt_Rijndael() object changes after each + * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that + * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them), + * however, they are also less intuitive and more likely to cause you problems. + * + * @see Crypt_Rijndael::disableContinuousBuffer() + * @access public + */ + function enableContinuousBuffer() + { + $this->continuousBuffer = true; + } + + /** + * Treat consecutive packets as if they are a discontinuous buffer. + * + * The default behavior. + * + * @see Crypt_Rijndael::enableContinuousBuffer() + * @access public + */ + function disableContinuousBuffer() + { + $this->continuousBuffer = false; + $this->encryptIV = $this->iv; + $this->decryptIV = $this->iv; + } + + /** + * String Shift + * + * Inspired by array_shift + * + * @param String $string + * @param optional Integer $index + * @return String + * @access private + */ + function _string_shift(&$string, $index = 1) + { + $substr = substr($string, 0, $index); + $string = substr($string, $index); + return $substr; + } +} + +// vim: ts=4:sw=4:et: +// vim6: fdl=1: +?> diff --git a/phpMyAdmin/libraries/plugin_interface.lib.php b/phpMyAdmin/libraries/plugin_interface.lib.php index 63cde28..be7e593 100644 --- a/phpMyAdmin/libraries/plugin_interface.lib.php +++ b/phpMyAdmin/libraries/plugin_interface.lib.php @@ -7,16 +7,49 @@ */ /** - * array PMA_getPlugins(string $plugins_dir, mixed $plugin_param) + * Includes and instantiates the specified plugin type for a certain format * - * Reads all plugin information from directory $plugins_dir. + * @param string $plugin_type the type of the plugin (import, export, etc) + * @param string $plugin_format the format of the plugin (sql, xml, et ) + * @param string $plugins_dir directrory with plugins + * @param mixed $plugin_param parameter to plugin by which they can + * decide whether they can work * - * @param string $plugins_dir directrory with plugins - * @param mixed $plugin_param parameter to plugin by which they can decide whether they can work - * @return array list of plugins + * @return object|null new plugin instance */ -function PMA_getPlugins($plugins_dir, $plugin_param) +function PMA_getPlugin( + $plugin_type, + $plugin_format, + $plugins_dir, + $plugin_param = false +) { + $GLOBALS['plugin_param'] = $plugin_param; + $class_name = strtoupper($plugin_type[0]) + . strtolower(substr($plugin_type, 1)) + . strtoupper($plugin_format[0]) + . strtolower(substr($plugin_format, 1)); + $file = $class_name . ".class.php"; + if (is_file($plugins_dir . $file)) { + include_once $plugins_dir . $file; + return new $class_name; + } + + return null; +} + +/** + * Reads all plugin information from directory $plugins_dir + * + * @param string $plugin_type the type of the plugin (import, export, etc) + * @param string $plugins_dir directrory with plugins + * @param mixed $plugin_param parameter to plugin by which they can + * decide whether they can work + * + * @return array list of plugin instances + */ +function PMA_getPlugins($plugin_type, $plugins_dir, $plugin_param) { + $GLOBALS['plugin_param'] = $plugin_param; /* Scan for plugins */ $plugin_list = array(); if ($handle = @opendir($plugins_dir)) { @@ -25,8 +58,21 @@ function PMA_getPlugins($plugins_dir, $plugin_param) // (for example ._csv.php) so the following regexp // matches a file which does not start with a dot but ends // with ".php" - if (is_file($plugins_dir . $file) && preg_match('@^[^\.](.)*\.php$@i', $file)) { - include $plugins_dir . $file; + $class_type = strtoupper($plugin_type[0]) + . strtolower(substr($plugin_type, 1)); + if (is_file($plugins_dir . $file) + && preg_match( + '@^' . $class_type . '(.+)\.class\.php$@i', + $file, + $matches + ) + ) { + $GLOBALS['skip_import'] = false; + include_once $plugins_dir . $file; + if (! $GLOBALS['skip_import']) { + $class_name = $class_type . $matches[1]; + $plugin_list [] = new $class_name; + } } } } @@ -35,12 +81,11 @@ function PMA_getPlugins($plugins_dir, $plugin_param) } /** - * string PMA_getString(string $name) + * Returns locale string for $name or $name if no locale is found * - * returns locale string for $name or $name if no locale is found + * @param string $name for local string * - * @param string $name for local string - * @return string locale string for $name + * @return string locale string for $name */ function PMA_getString($name) { @@ -48,45 +93,58 @@ function PMA_getString($name) } /** - * string PMA_pluginCheckboxCheck(string $section, string $opt) + * Returns html input tag option 'checked' if plugin $opt + * should be set by config or request * - * returns html input tag option 'checked' if plugin $opt should be set by config or request + * @param string $section name of config section in + * $GLOBALS['cfg'][$section] for plugin + * @param string $opt name of option * - * @param string $section name of config section in - * $GLOBALS['cfg'][$section] for plugin - * @param string $opt name of option - * @return string hmtl input tag option 'checked' + * @return string hmtl input tag option 'checked' */ function PMA_pluginCheckboxCheck($section, $opt) { // If the form is being repopulated using $_GET data, that is priority - if (isset($_GET[$opt]) || ! isset($_GET['repopulate']) && ((isset($GLOBALS['timeout_passed']) && $GLOBALS['timeout_passed'] && isset($_REQUEST[$opt])) || - (isset($GLOBALS['cfg'][$section][$opt]) && $GLOBALS['cfg'][$section][$opt]))) { + if (isset($_GET[$opt]) + || ! isset($_GET['repopulate']) + && ((isset($GLOBALS['timeout_passed']) + && $GLOBALS['timeout_passed'] + && isset($_REQUEST[$opt])) + || (isset($GLOBALS['cfg'][$section][$opt]) + && $GLOBALS['cfg'][$section][$opt])) + ) { return ' checked="checked"'; } return ''; } /** - * string PMA_pluginGetDefault(string $section, string $opt) + * Returns default value for option $opt * - * returns default value for option $opt + * @param string $section name of config section in + * $GLOBALS['cfg'][$section] for plugin + * @param string $opt name of option * - * @param string $section name of config section in - * $GLOBALS['cfg'][$section] for plugin - * @param string $opt name of option - * @return string default value for option $opt + * @return string default value for option $opt */ function PMA_pluginGetDefault($section, $opt) { - if (isset($_GET[$opt])) { // If the form is being repopulated using $_GET data, that is priority + if (isset($_GET[$opt])) { + // If the form is being repopulated using $_GET data, that is priority return htmlspecialchars($_GET[$opt]); - } elseif (isset($GLOBALS['timeout_passed']) && $GLOBALS['timeout_passed'] && isset($_REQUEST[$opt])) { + } elseif (isset($GLOBALS['timeout_passed']) + && $GLOBALS['timeout_passed'] + && isset($_REQUEST[$opt]) + ) { return htmlspecialchars($_REQUEST[$opt]); } elseif (isset($GLOBALS['cfg'][$section][$opt])) { $matches = array(); /* Possibly replace localised texts */ - if (preg_match_all('/(str[A-Z][A-Za-z0-9]*)/', $GLOBALS['cfg'][$section][$opt], $matches)) { + if (preg_match_all( + '/(str[A-Z][A-Za-z0-9]*)/', + $GLOBALS['cfg'][$section][$opt], + $matches + )) { $val = $GLOBALS['cfg'][$section][$opt]; foreach ($matches[0] as $match) { if (isset($GLOBALS[$match])) { @@ -102,40 +160,16 @@ function PMA_pluginGetDefault($section, $opt) } /** - * string PMA_pluginIsActive(string $section, string $opt, string $val) - * - * returns html input tag option 'checked' if option $opt should be set by config or request - * - * @param string $section name of config section in - * $GLOBALS['cfg'][$section] for plugin - * @param string $opt name of option - * @param string $val value of option to check against - * @return string html input tag option 'checked' - */ -function PMA_pluginIsActive($section, $opt, $val) -{ - if (! empty($GLOBALS['timeout_passed']) && isset($_REQUEST[$opt])) { - if ($_REQUEST[$opt] == $val) { - return ' checked="checked"'; - } - } elseif (isset($GLOBALS['cfg'][$section][$opt]) && $GLOBALS['cfg'][$section][$opt] == $val) { - return ' checked="checked"'; - } - return ''; -} - -/** - * string PMA_pluginGetChoice(string $section, string $name, array &$list, string $cfgname) - * - * returns html select form element for plugin choice + * Returns html select form element for plugin choice * and hidden fields denoting whether each plugin must be exported as a file * - * @param string $section name of config section in - * $GLOBALS['cfg'][$section] for plugin - * @param string $name name of select element - * @param array &$list array with plugin configuration defined in plugin file - * @param string $cfgname name of config value, if none same as $name - * @return string html select tag + * @param string $section name of config section in + * $GLOBALS['cfg'][$section] for plugin + * @param string $name name of select element + * @param array &$list array with plugin instances + * @param string $cfgname name of config value, if none same as $name + * + * @return string html select tag */ function PMA_pluginGetChoice($section, $name, &$list, $cfgname = null) { @@ -144,168 +178,327 @@ function PMA_pluginGetChoice($section, $name, &$list, $cfgname = null) } $ret = '' . "\n"; // Whether each plugin has to be saved as a file - foreach ($list as $plugin_name => $val) { - $ret .= ''. "\n"; } + return $ret; } /** - * string PMA_pluginGetOneOption(string $section, string $plugin_name, string $id, array &$opt) - * - * returns single option in a list element + * Returns single option in a list element * * @param string $section name of config section in - * $GLOBALS['cfg'][$section] for plugin + * $GLOBALS['cfg'][$section] for plugin * @param string $plugin_name unique plugin name - * @param string $id option id - * @param array &$opt plugin option details - * @return string table row with option + * @param array &$propertyGroup options property main group instance + * @param boolean $is_subgroup if this group is a subgroup + * + * @return string table row with option */ -function PMA_pluginGetOneOption($section, $plugin_name, $id, &$opt) -{ +function PMA_pluginGetOneOption( + $section, + $plugin_name, + &$propertyGroup, + $is_subgroup = false +) { $ret = "\n"; - if ($opt['type'] == 'bool') { - $ret .= '
  • ' . "\n"; - $ret .= '' - . PMA_getString($opt['text']) . ''; - } elseif ($opt['type'] == 'text') { - $ret .= '
  • ' . "\n"; - $ret .= ''; - $ret .= ''; - } elseif ($opt['type'] == 'message_only') { - $ret .= '
  • ' . "\n"; - $ret .= '

    ' . PMA_getString($opt['text']) . '

    '; - } elseif ($opt['type'] == 'select') { - $ret .= '
  • ' . "\n"; - $ret .= ''; - $ret .= ''; - } elseif ($opt['type'] == 'radio') { - $default = PMA_pluginGetDefault($section, $plugin_name . '_' . $opt['name']); - foreach ($opt['values'] as $key => $val) { - $ret .= '
  • '; } - $ret .= ' />' . '
  • '; + $ret .= '
      '; } - } elseif ($opt['type'] == 'hidden') { - $ret .= '
    • '; - } elseif ($opt['type'] == 'begin_group') { - $ret .= '
      '; - if (isset($opt['text'])) { - $ret .= '

      ' . PMA_getString($opt['text']) . '

      '; + } + + if (! isset($properties)) { + $not_subgroup_header = true; + if (method_exists($propertyGroup, 'getProperties')) { + $properties = $propertyGroup->getProperties(); } - $ret .= '
        '; - } elseif ($opt['type'] == 'end_group') { - $ret .= '
      '; - } elseif ($opt['type'] == 'begin_subgroup') { - /* each subgroup can have a header, which may also be a form element */ - $ret .= PMA_pluginGetOneOption($section, $plugin_name, $id, $opt['subgroup_header']) . '
    • '; - } else { - $ret .= '>'; + } + + if (isset($properties)) { + foreach ($properties as $propertyItem) { + $property_class = get_class($propertyItem); + // if the property is a subgroup, we deal with it recursively + if (strpos($property_class, "Subgroup")) { + // for subgroups + // each subgroup can have a header, which may also be a form element + $subgroup_header = $propertyItem->getSubgroupHeader(); + if (isset($subgroup_header)) { + $ret .= PMA_pluginGetOneOption( + $section, + $plugin_name, + $subgroup_header + ); + } + + $ret .= '
    • getName() . '">'; + } else { + $ret .= '>'; + } + + $ret .= PMA_pluginGetOneOption( + $section, + $plugin_name, + $propertyItem, + true + ); + } else { + // single property item + switch ($property_class) { + case "BoolPropertyItem": + $ret .= '
    • ' . "\n"; + $ret .= 'getName() + ); + + if ($propertyItem->getForce() != null) { + // Same code is also few lines lower, update both if needed + $ret .= ' onclick="if (!this.checked && ' + . '(!document.getElementById(\'checkbox_' . $plugin_name + . '_' . $propertyItem->getForce() . '\') ' + . '|| !document.getElementById(\'checkbox_' + . $plugin_name . '_' . $propertyItem->getForce() + . '\').checked)) ' + . 'return false; else return true;"'; + } + $ret .= ' />'; + $ret .= ''; + break; + case "DocPropertyItem": + echo "DocPropertyItem"; + break; + case "HiddenPropertyItem": + $ret .= '
    • '; + break; + case "MessageOnlyPropertyItem": + $ret .= '
    • ' . "\n"; + $ret .= '

      ' . PMA_getString($propertyItem->getText()) . '

      '; + break; + case "RadioPropertyItem": + $default = PMA_pluginGetDefault( + $section, + $plugin_name . '_' . $propertyItem->getName() + ); + foreach ($propertyItem->getValues() as $key => $val) { + $ret .= '
    • ' + . PMA_getString($val) . '
    • '; + } + break; + case "SelectPropertyItem": + $ret .= '
    • ' . "\n"; + $ret .= ''; + $ret .= ''; + break; + case "TextPropertyItem": + case "NumberPropertyItem": + $ret .= '
    • ' . "\n"; + $ret .= ''; + $ret .= 'getSize() != null + ? ' size="' . $propertyItem->getSize() . '"' + : '') + . ($propertyItem->getLen() != null + ? ' maxlength="' . $propertyItem->getLen() . '"' + : '') + . ' />'; + break; + default:; + } + } } - } elseif ($opt['type'] == 'end_subgroup') { + } + + if ($is_subgroup) { + // end subgroup $ret .= '
    '; } else { - /* This should be seen only by plugin writers, so I do not thing this - * needs translation. */ - $ret .= 'UNKNOWN OPTION ' . $opt['type'] . ' IN IMPORT PLUGIN ' . $plugin_name . '!'; + // end main group + if (! empty($not_subgroup_header)) { + $ret .= ''; + } } - if (isset($opt['doc'])) { - if (count($opt['doc']) == 3) { - $ret .= PMA_showMySQLDocu($opt['doc'][0], $opt['doc'][1], false, $opt['doc'][2]); - } elseif (count($opt['doc']) == 1) { - $ret .= PMA_showDocu($opt['doc'][0]); - } else { - $ret .= PMA_showMySQLDocu($opt['doc'][0], $opt['doc'][1]); + + if (method_exists($propertyGroup, "getDoc")) { + $doc = $propertyGroup->getDoc(); + if ($doc != null) { + if (count($doc) == 3) { + $ret .= PMA_Util::showMySQLDocu( + $doc[1], + false, + $doc[2] + ); + } elseif (count($doc) == 1) { + $ret .= PMA_Util::showDocu('faq', $doc[0]); + } else { + $ret .= PMA_Util::showMySQLDocu( + $doc[1] + ); + } } } - // Close the list element after $opt['doc'] link is displayed - if ($opt['type'] == 'bool' || $opt['type'] == 'text' || $opt['type'] == 'message_only' || $opt['type'] == 'select') { - $ret .= ''; + // Close the list element after $doc link is displayed + if (isset($property_class)) { + if ($property_class == 'BoolPropertyItem' + || $property_class == 'MessageOnlyPropertyItem' + || $property_class == 'SelectPropertyItem' + || $property_class == 'TextPropertyItem' + ) { + $ret .= ''; + } } $ret .= "\n"; return $ret; } /** - * string PMA_pluginGetOptions(string $section, array &$list) + * Returns html div with editable options for plugin * - * return html div with editable options for plugin + * @param string $section name of config section in $GLOBALS['cfg'][$section] + * @param array &$list array with plugin instances * - * @param string $section name of config section in $GLOBALS['cfg'][$section] - * @param array &$list array with plugin configuration defined in plugin file - * @return string html fieldset with plugin options + * @return string html fieldset with plugin options */ function PMA_pluginGetOptions($section, &$list) { $ret = ''; - $default = PMA_pluginGetDefault('Export', 'format'); // Options for plugins that support them - foreach ($list as $plugin_name => $val) { - $ret .= '
    '; - $count = 0; - $ret .= '

    ' . PMA_getString($val['text']) . '

    '; - if (isset($val['options']) && count($val['options']) > 0) { - foreach ($val['options'] as $id => $opt) { - if ($opt['type'] != 'hidden' && $opt['type'] != 'begin_group' && $opt['type'] != 'end_group' && $opt['type'] != 'begin_subgroup' && $opt['type'] != 'end_subgroup') { - $count++; + foreach ($list as $plugin) { + $properties = $plugin->getProperties(); + if ($properties != null) { + $text = $properties->getText(); + $options = $properties->getOptions(); + } + + $plugin_name = strtolower(substr(get_class($plugin), strlen($section))); + $ret .= '
    '; + $ret .= '

    ' . PMA_getString($text) . '

    '; + + $no_options = true; + if ($options != null && count($options) > 0) { + foreach ($options->getProperties() + as $propertyMainGroup + ) { + // check for hidden properties + $no_options = true; + foreach ($propertyMainGroup->getProperties() as $propertyItem) { + if (strcmp("HiddenPropertyItem", get_class($propertyItem))) { + $no_options = false; + break; + } } - $ret .= PMA_pluginGetOneOption($section, $plugin_name, $id, $opt); + + $ret .= PMA_pluginGetOneOption( + $section, + $plugin_name, + $propertyMainGroup + ); } } - if ($count == 0) { + + if ($no_options) { $ret .= '

    ' . __('This format has no options') . '

    '; } $ret .= '
    '; diff --git a/phpMyAdmin/libraries/plugins/AuthenticationPlugin.class.php b/phpMyAdmin/libraries/plugins/AuthenticationPlugin.class.php new file mode 100644 index 0000000..3ddf55e --- /dev/null +++ b/phpMyAdmin/libraries/plugins/AuthenticationPlugin.class.php @@ -0,0 +1,51 @@ + authentication failed + * + * @return boolean + */ + abstract public function authFails(); +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/ExportPlugin.class.php b/phpMyAdmin/libraries/plugins/ExportPlugin.class.php new file mode 100644 index 0000000..ecfde15 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/ExportPlugin.class.php @@ -0,0 +1,206 @@ +properties; + } + + /** + * Sets the export plugins properties and is implemented by each export + * plugin + * + * @return void + */ + abstract protected function setProperties(); +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/ImportPlugin.class.php b/phpMyAdmin/libraries/plugins/ImportPlugin.class.php new file mode 100644 index 0000000..4ef4deb --- /dev/null +++ b/phpMyAdmin/libraries/plugins/ImportPlugin.class.php @@ -0,0 +1,59 @@ +properties; + } + + /** + * Sets the export plugins properties and is implemented by each import + * plugin + * + * @return void + */ + abstract protected function setProperties(); +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/PluginManager.class.php b/phpMyAdmin/libraries/plugins/PluginManager.class.php new file mode 100644 index 0000000..3485981 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/PluginManager.class.php @@ -0,0 +1,132 @@ +_storage = new SplObjectStorage(); + } + + /** + * Attaches an SplObserver so that it can be notified of updates + * + * @param SplObserver $observer The SplObserver to attach + * + * @return void + */ + function attach (SplObserver $observer ) + { + $this->_storage->attach($observer); + } + + /** + * Detaches an observer from the subject to no longer notify it of updates + * + * @param SplObserver $observer The SplObserver to detach + * + * @return void + */ + function detach (SplObserver $observer) + { + $this->_storage->detach($observer); + } + + /** + * It is called after setStatus() was run by a certain plugin, and has + * the role of sending a notification to all of the plugins in $_storage, + * by calling the update() method for each of them. + * + * @todo implement + * @return void + */ + function notify () + { + } + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + /** + * Gets the list with all the plugins that attach to it + * + * @return SplObjectStorage + */ + public function getStorage() + { + return $this->_storage; + } + + /** + * Setter for $_storage + * + * @param SplObjectStorage $_storage the list with all the plugins that + * attach to it + * + * @return void + */ + public function setStorage($_storage) + { + $this->_storage = $_storage; + } + + /** + * Gets the information about the current plugin state + * It is called by all the plugins in $_storage in their update() method + * + * @return string + */ + public function getStatus() + { + return $this->_status; + } + + /** + * Setter for $_status + * If a plugin changes its status, this has to be remembered in order to + * notify the rest of the plugins that they should update + * + * @param string $_status contains information about the current plugin state + * + * @return void + */ + public function setStatus($_status) + { + $this->_status = $_status; + } +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/PluginObserver.class.php b/phpMyAdmin/libraries/plugins/PluginObserver.class.php new file mode 100644 index 0000000..82a2fdc --- /dev/null +++ b/phpMyAdmin/libraries/plugins/PluginObserver.class.php @@ -0,0 +1,91 @@ +_pluginManager = $pluginManager; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * TODO Declare this function abstract, removing its body, + * as soon as we drop support for PHP 5.3.x. + * See bug #3625 + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + * + * @throws Exception + */ + public function update (SplSubject $subject) + { + throw new Exception( + 'PluginObserver::update must be overridden in child classes.' + ); + } + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the PluginManager instance that contains the list with all the + * plugins that attached to it + * + * @return PluginManager + */ + public function getPluginManager() + { + return $this->_pluginManager; + } + + /** + * Setter for $_pluginManager + * + * @param PluginManager $_pluginManager the private instance that it will + * attach to + * + * @return void + */ + public function setPluginManager($_pluginManager) + { + $this->_pluginManager = $_pluginManager; + } +} +?> diff --git a/phpMyAdmin/libraries/plugins/TransformationsInterface.int.php b/phpMyAdmin/libraries/plugins/TransformationsInterface.int.php new file mode 100644 index 0000000..1bcb8af --- /dev/null +++ b/phpMyAdmin/libraries/plugins/TransformationsInterface.int.php @@ -0,0 +1,49 @@ + diff --git a/phpMyAdmin/libraries/plugins/TransformationsPlugin.class.php b/phpMyAdmin/libraries/plugins/TransformationsPlugin.class.php new file mode 100644 index 0000000..02ed816 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/TransformationsPlugin.class.php @@ -0,0 +1,51 @@ + diff --git a/phpMyAdmin/libraries/plugins/UploadInterface.int.php b/phpMyAdmin/libraries/plugins/UploadInterface.int.php new file mode 100644 index 0000000..ab660d6 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/UploadInterface.int.php @@ -0,0 +1,36 @@ +upload plugins + * + * @package PhpMyAdmin + */ +if (! defined('PHPMYADMIN')) { + exit; +} + +/** + * Provides a common interface that will have to implemented by all of the + * import->upload plugins. + * + * @package PhpMyAdmin + */ +interface UploadInterface +{ + /** + * Gets the specific upload ID Key + * + * @return string ID Key + */ + public static function getIdKey(); + + /** + * Returns upload status. + * + * @param string $id upload id + * + * @return array|null + */ + public static function getUploadStatus($id); +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/auth/AuthenticationConfig.class.php b/phpMyAdmin/libraries/plugins/auth/AuthenticationConfig.class.php new file mode 100644 index 0000000..6f7e4e4 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/auth/AuthenticationConfig.class.php @@ -0,0 +1,174 @@ + authentication failed + * + * @global string the MySQL error message PHP returns + * @global string the connection type (persistent or not) + * @global string the MySQL server port to use + * @global string the MySQL socket port to use + * @global array the current server settings + * @global string the font face to use in case of failure + * @global string the default font size to use in case of failure + * @global string the big font size to use in case of failure + * @global boolean tell the "PMA_mysqlDie()" function headers have been + * sent + * + * @return boolean always true (no return indeed) + */ + public function authFails() + { + $conn_error = $GLOBALS['dbi']->getError(); + if (! $conn_error) { + $conn_error = __('Cannot connect: invalid settings.'); + } + + /* HTML header */ + $response = PMA_Response::getInstance(); + $response->getFooter()->setMinimal(); + $header = $response->getHeader(); + $header->setBodyId('loginform'); + $header->setTitle(__('Access denied')); + $header->disableMenu(); + echo '

    +
    +

    '; + echo sprintf(__('Welcome to %s'), ' phpMyAdmin '); + echo '

    +
    +
    + + + + + + + ' . "\n"; + if (count($GLOBALS['cfg']['Servers']) > 1) { + // offer a chance to login to other servers if the current one failed + include_once './libraries/select_server.lib.php'; + echo '' . "\n"; + echo ' ' . "\n"; + echo '' . "\n"; + } + echo '
    '; + if (isset($GLOBALS['allowDeny_forbidden']) + && $GLOBALS['allowDeny_forbidden'] + ) { + trigger_error(__('Access denied'), E_USER_NOTICE); + } else { + // Check whether user has configured something + if ($GLOBALS['PMA_Config']->source_mtime == 0) { + echo '

    ' . sprintf( + __( + 'You probably did not create a configuration file.' + . ' You might want to use the %1$ssetup script%2$s to' + . ' create one.' + ), + '', + '' + ) . '

    ' . "\n"; + } elseif (! isset($GLOBALS['errno']) + || (isset($GLOBALS['errno']) && $GLOBALS['errno'] != 2002) + && $GLOBALS['errno'] != 2003 + ) { + // if we display the "Server not responding" error, do not confuse + // users by telling them they have a settings problem + // (note: it's true that they could have a badly typed host name, + // but anyway the current message tells that the server + // rejected the connection, which is not really what happened) + // 2002 is the error given by mysqli + // 2003 is the error given by mysql + trigger_error( + __( + 'phpMyAdmin tried to connect to the MySQL server, and the' + . ' server rejected the connection. You should check the' + . ' host, username and password in your configuration and' + . ' make sure that they correspond to the information given' + . ' by the administrator of the MySQL server.' + ), E_USER_WARNING + ); + } + echo PMA_Util::mysqlDie( + $conn_error, '', true, '', false + ); + } + $GLOBALS['error_handler']->dispUserErrors(); + echo '
    ' . "\n"; + echo '' + . __('Retry to connect') + . '' . "\n"; + echo '
    ' . "\n"; + echo PMA_selectServer(true, true); + echo '
    ' . "\n"; + if (!defined('TESTSUITE')) { + exit; + } + return true; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } +} diff --git a/phpMyAdmin/libraries/plugins/auth/AuthenticationCookie.class.php b/phpMyAdmin/libraries/plugins/auth/AuthenticationCookie.class.php new file mode 100644 index 0000000..6d326c3 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/auth/AuthenticationCookie.class.php @@ -0,0 +1,807 @@ +setCookie( + 'pma_mcrypt_iv', + base64_encode($iv) + ); + } +} + +/** + * Handles the cookie authentication method + * + * @package PhpMyAdmin-Authentication + */ +class AuthenticationCookie extends AuthenticationPlugin +{ + /** + * Displays authentication form + * + * this function MUST exit/quit the application + * + * @global string $conn_error the last connection error + * + * @return boolean|void + */ + public function auth() + { + global $conn_error; + + $response = PMA_Response::getInstance(); + if ($response->isAjax()) { + $response->isSuccess(false); + + $login_link = '

    [ ' . + sprintf( + '', + $GLOBALS['cfg']['PmaAbsoluteUri'], + __('Log in') + ) + . ' ]'; + + if (! empty($conn_error)) { + + $conn_error .= $login_link; + + $response->addJSON( + 'message', + PMA_Message::error( + $conn_error + ) + ); + } else { + $response->addJSON( + 'message', + PMA_Message::error( + __('Your session has expired. Please log in again.') . + $login_link + ) + ); + } + if (defined('TESTSUITE')) { + return true; + } else { + exit; + } + } + + /* Perform logout to custom URL */ + if (! empty($_REQUEST['old_usr']) + && ! empty($GLOBALS['cfg']['Server']['LogoutURL']) + ) { + PMA_sendHeaderLocation($GLOBALS['cfg']['Server']['LogoutURL']); + if (defined('TESTSUITE')) { + return true; + } else { + exit; + } + } + + // No recall if blowfish secret is not configured as it would produce + // garbage + if ($GLOBALS['cfg']['LoginCookieRecall'] + && ! empty($GLOBALS['cfg']['blowfish_secret']) + ) { + $default_user = $GLOBALS['PHP_AUTH_USER']; + $default_server = $GLOBALS['pma_auth_server']; + $autocomplete = ''; + } else { + $default_user = ''; + $default_server = ''; + // skip the IE autocomplete feature. + $autocomplete = ' autocomplete="off"'; + } + + $response->getFooter()->setMinimal(); + $header = $response->getHeader(); + $header->setBodyId('loginform'); + $header->setTitle('phpMyAdmin'); + $header->disableMenu(); + $header->disableWarnings(); + + if (file_exists(CUSTOM_HEADER_FILE)) { + include CUSTOM_HEADER_FILE; + } + echo ' +
    + +

    '; + echo sprintf( + __('Welcome to %s'), + 'phpMyAdmin' + ); + echo "

    "; + + // Show error message + if (! empty($conn_error)) { + PMA_Message::rawError($conn_error)->display(); + } + + echo "\n"; + + echo "
    "; + // Displays the languages form + if (empty($GLOBALS['cfg']['Lang'])) { + include_once './libraries/display_select_lang.lib.php'; + // use fieldset, don't show doc link + echo PMA_getLanguageSelectorHtml(true, false); + } + echo '
    +
    + + '; + + // BEGIN Swekey Integration + Swekey_login('input_username', 'input_go'); + // END Swekey Integration + + if ($GLOBALS['error_handler']->hasDisplayErrors()) { + echo '
    '; + $GLOBALS['error_handler']->dispErrors(); + echo '
    '; + } + echo '
    '; + if (file_exists(CUSTOM_FOOTER_FILE)) { + include CUSTOM_FOOTER_FILE; + } + if (! defined('TESTSUITE')) { + exit; + } else { + return true; + } + } + + /** + * Gets advanced authentication settings + * + * this function DOES NOT check authentication - it just checks/provides + * authentication credentials required to connect to the MySQL server + * usually with $GLOBALS['dbi']->connect() + * + * it returns false if something is missing - which usually leads to + * auth() which displays login form + * + * it returns true if all seems ok which usually leads to auth_set_user() + * + * it directly switches to authFails() if user inactivity timout is reached + * + * @todo AllowArbitraryServer on does not imply that the user wants an + * arbitrary server, or? so we should also check if this is filled + * and not only if allowed + * + * @return boolean whether we get authentication settings or not + */ + public function authCheck() + { + global $conn_error; + + // Initialization + /** + * @global $GLOBALS['pma_auth_server'] the user provided server to + * connect to + */ + $GLOBALS['pma_auth_server'] = ''; + + $GLOBALS['PHP_AUTH_USER'] = $GLOBALS['PHP_AUTH_PW'] = ''; + $GLOBALS['from_cookie'] = false; + + // BEGIN Swekey Integration + if (! Swekey_Auth_check()) { + return false; + } + // END Swekey Integration + + if (defined('PMA_CLEAR_COOKIES')) { + foreach ($GLOBALS['cfg']['Servers'] as $key => $val) { + $GLOBALS['PMA_Config']->removeCookie('pmaPass-' . $key); + $GLOBALS['PMA_Config']->removeCookie('pmaServer-' . $key); + $GLOBALS['PMA_Config']->removeCookie('pmaUser-' . $key); + } + return false; + } + + // We already have one correct captcha. + $skip = false; + if ( isset($_SESSION['last_valid_captcha']) + && $_SESSION['last_valid_captcha'] + ) { + $skip = true; + } + + // Verify Captcha if it is required. + if ( !empty($GLOBALS['cfg']['CaptchaLoginPrivateKey']) + && !empty($GLOBALS['cfg']['CaptchaLoginPublicKey']) + && !$skip + ) { + if ( !empty($_POST["recaptcha_challenge_field"]) + && !empty($_POST["recaptcha_response_field"]) + ) { + include_once 'libraries/plugins/auth/recaptchalib.php'; + + // Use private key to verify captcha status. + $resp = recaptcha_check_answer( + $GLOBALS['cfg']['CaptchaLoginPrivateKey'], + $_SERVER["REMOTE_ADDR"], + $_POST["recaptcha_challenge_field"], + $_POST["recaptcha_response_field"] + ); + + // Check if the captcha entered is valid, if not stop the login. + if ( !$resp->is_valid ) { + $conn_error = __('Entered captcha is wrong, try again!'); + $_SESSION['last_valid_captcha'] = false; + return false; + } else { + $_SESSION['last_valid_captcha'] = true; + } + } elseif (! empty($_POST["recaptcha_challenge_field"]) + && empty($_POST["recaptcha_response_field"]) + ) { + $conn_error = __('Please enter correct captcha!'); + return false; + } else { + if (! isset($_SESSION['last_valid_captcha']) + || ! $_SESSION['last_valid_captcha'] + ) { + return false; + } + } + } + + if (! empty($_REQUEST['old_usr'])) { + // The user wants to be logged out + // -> delete his choices that were stored in session + + // according to the PHP manual we should do this before the destroy: + //$_SESSION = array(); + + if (! defined('TESTSUITE')) { + session_destroy(); + // $_SESSION array is not immediately emptied + $_SESSION['last_valid_captcha'] = false; + } + // -> delete password cookie(s) + if ($GLOBALS['cfg']['LoginCookieDeleteAll']) { + foreach ($GLOBALS['cfg']['Servers'] as $key => $val) { + $GLOBALS['PMA_Config']->removeCookie('pmaPass-' . $key); + if (isset($_COOKIE['pmaPass-' . $key])) { + unset($_COOKIE['pmaPass-' . $key]); + } + } + } else { + $GLOBALS['PMA_Config']->removeCookie( + 'pmaPass-' . $GLOBALS['server'] + ); + if (isset($_COOKIE['pmaPass-' . $GLOBALS['server']])) { + unset($_COOKIE['pmaPass-' . $GLOBALS['server']]); + } + } + } + + if (! empty($_REQUEST['pma_username'])) { + // The user just logged in + $GLOBALS['PHP_AUTH_USER'] = $_REQUEST['pma_username']; + $GLOBALS['PHP_AUTH_PW'] = empty($_REQUEST['pma_password']) + ? '' + : $_REQUEST['pma_password']; + if ($GLOBALS['cfg']['AllowArbitraryServer'] + && isset($_REQUEST['pma_servername']) + ) { + $GLOBALS['pma_auth_server'] = $_REQUEST['pma_servername']; + } + return true; + } + + // At the end, try to set the $GLOBALS['PHP_AUTH_USER'] + // and $GLOBALS['PHP_AUTH_PW'] variables from cookies + + // servername + if ($GLOBALS['cfg']['AllowArbitraryServer'] + && ! empty($_COOKIE['pmaServer-' . $GLOBALS['server']]) + ) { + $GLOBALS['pma_auth_server'] + = $_COOKIE['pmaServer-' . $GLOBALS['server']]; + } + + // username + if (empty($_COOKIE['pmaUser-' . $GLOBALS['server']])) { + return false; + } + + $GLOBALS['PHP_AUTH_USER'] = $this->blowfishDecrypt( + $_COOKIE['pmaUser-' . $GLOBALS['server']], + $this->_getBlowfishSecret() + ); + + // user was never logged in since session start + if (empty($_SESSION['last_access_time'])) { + return false; + } + + // User inactive too long + $last_access_time = time() - $GLOBALS['cfg']['LoginCookieValidity']; + if ($_SESSION['last_access_time'] < $last_access_time + ) { + PMA_Util::cacheUnset('is_create_db_priv', true); + PMA_Util::cacheUnset('is_process_priv', true); + PMA_Util::cacheUnset('is_reload_priv', true); + PMA_Util::cacheUnset('db_to_create', true); + PMA_Util::cacheUnset('dbs_where_create_table_allowed', true); + $GLOBALS['no_activity'] = true; + $this->authFails(); + if (! defined('TESTSUITE')) { + exit; + } else { + return false; + } + } + + // password + if (empty($_COOKIE['pmaPass-' . $GLOBALS['server']])) { + return false; + } + + $GLOBALS['PHP_AUTH_PW'] = $this->blowfishDecrypt( + $_COOKIE['pmaPass-' . $GLOBALS['server']], + $this->_getBlowfishSecret() + ); + + if ($GLOBALS['PHP_AUTH_PW'] == "\xff(blank)") { + $GLOBALS['PHP_AUTH_PW'] = ''; + } + + $GLOBALS['from_cookie'] = true; + + return true; + } + + /** + * Set the user and password after last checkings if required + * + * @return boolean always true + */ + public function authSetUser() + { + global $cfg; + + // Ensures valid authentication mode, 'only_db', bookmark database and + // table names and relation table name are used + if ($cfg['Server']['user'] != $GLOBALS['PHP_AUTH_USER']) { + foreach ($cfg['Servers'] as $idx => $current) { + if ($current['host'] == $cfg['Server']['host'] + && $current['port'] == $cfg['Server']['port'] + && $current['socket'] == $cfg['Server']['socket'] + && $current['ssl'] == $cfg['Server']['ssl'] + && $current['connect_type'] == $cfg['Server']['connect_type'] + && $current['user'] == $GLOBALS['PHP_AUTH_USER'] + ) { + $GLOBALS['server'] = $idx; + $cfg['Server'] = $current; + break; + } + } // end foreach + } // end if + + if ($GLOBALS['cfg']['AllowArbitraryServer'] + && ! empty($GLOBALS['pma_auth_server']) + ) { + /* Allow to specify 'host port' */ + $parts = explode(' ', $GLOBALS['pma_auth_server']); + if (count($parts) == 2) { + $tmp_host = $parts[0]; + $tmp_port = $parts[1]; + } else { + $tmp_host = $GLOBALS['pma_auth_server']; + $tmp_port = ''; + } + if ($cfg['Server']['host'] != $GLOBALS['pma_auth_server']) { + $cfg['Server']['host'] = $tmp_host; + if (! empty($tmp_port)) { + $cfg['Server']['port'] = $tmp_port; + } + } + unset($tmp_host, $tmp_port, $parts); + } + $cfg['Server']['user'] = $GLOBALS['PHP_AUTH_USER']; + $cfg['Server']['password'] = $GLOBALS['PHP_AUTH_PW']; + + // Avoid showing the password in phpinfo()'s output + unset($GLOBALS['PHP_AUTH_PW']); + unset($_SERVER['PHP_AUTH_PW']); + + $_SESSION['last_access_time'] = time(); + + // Name and password cookies need to be refreshed each time + // Duration = one month for username + $GLOBALS['PMA_Config']->setCookie( + 'pmaUser-' . $GLOBALS['server'], + $this->blowfishEncrypt( + $cfg['Server']['user'], + $this->_getBlowfishSecret() + ) + ); + + // Duration = as configured + $GLOBALS['PMA_Config']->setCookie( + 'pmaPass-' . $GLOBALS['server'], + $this->blowfishEncrypt( + ! empty($cfg['Server']['password']) + ? $cfg['Server']['password'] : "\xff(blank)", + $this->_getBlowfishSecret() + ), + null, + $GLOBALS['cfg']['LoginCookieStore'] + ); + + // Set server cookies if required (once per session) and, in this case, + // force reload to ensure the client accepts cookies + if (! $GLOBALS['from_cookie']) { + if ($GLOBALS['cfg']['AllowArbitraryServer']) { + if (! empty($GLOBALS['pma_auth_server'])) { + // Duration = one month for servername + $GLOBALS['PMA_Config']->setCookie( + 'pmaServer-' . $GLOBALS['server'], + $cfg['Server']['host'] + ); + } else { + // Delete servername cookie + $GLOBALS['PMA_Config']->removeCookie( + 'pmaServer-' . $GLOBALS['server'] + ); + } + } + + // URL where to go: + $redirect_url = $cfg['PmaAbsoluteUri'] . 'index.php'; + + // any parameters to pass? + $url_params = array(); + if (strlen($GLOBALS['db'])) { + $url_params['db'] = $GLOBALS['db']; + } + if (strlen($GLOBALS['table'])) { + $url_params['table'] = $GLOBALS['table']; + } + // any target to pass? + if (! empty($GLOBALS['target']) + && $GLOBALS['target'] != 'index.php' + ) { + $url_params['target'] = $GLOBALS['target']; + } + + /** + * Clear user cache. + */ + PMA_Util::clearUserCache(); + + PMA_Response::getInstance()->disable(); + + PMA_sendHeaderLocation( + $redirect_url . PMA_URL_getCommon($url_params, '&'), + true + ); + if (! defined('TESTSUITE')) { + exit; + } else { + return false; + } + } // end if + + return true; + + } + + /** + * User is not allowed to login to MySQL -> authentication failed + * + * prepares error message and switches to auth() which display the error + * and the login form + * + * this function MUST exit/quit the application, + * currently doen by call to auth() + * + * @return void + */ + public function authFails() + { + global $conn_error; + + // Deletes password cookie and displays the login form + $GLOBALS['PMA_Config']->removeCookie('pmaPass-' . $GLOBALS['server']); + + if (! empty($GLOBALS['login_without_password_is_forbidden'])) { + $conn_error = __( + 'Login without a password is forbidden by configuration' + . ' (see AllowNoPassword)' + ); + } elseif (! empty($GLOBALS['allowDeny_forbidden'])) { + $conn_error = __('Access denied'); + } elseif (! empty($GLOBALS['no_activity'])) { + $conn_error = sprintf( + __('No activity within %s seconds; please log in again.'), + $GLOBALS['cfg']['LoginCookieValidity'] + ); + } elseif ($GLOBALS['dbi']->getError()) { + $conn_error = '#' . $GLOBALS['errno'] . ' ' + . __('Cannot log in to the MySQL server'); + } else { + $conn_error = __('Cannot log in to the MySQL server'); + } + + // needed for PHP-CGI (not need for FastCGI or mod-php) + header('Cache-Control: no-store, no-cache, must-revalidate'); + header('Pragma: no-cache'); + + $this->auth(); + } + + /** + * Returns blowfish secret or generates one if needed. + * + * @return string + */ + private function _getBlowfishSecret() + { + if (empty($GLOBALS['cfg']['blowfish_secret'])) { + if (empty($_SESSION['auto_blowfish_secret'])) { + // this returns 23 characters + $_SESSION['auto_blowfish_secret'] = uniqid('', true); + } + return $_SESSION['auto_blowfish_secret']; + } else { + // apply md5() to work around too long secrets (returns 32 characters) + return md5($GLOBALS['cfg']['blowfish_secret']); + } + } + + /** + * Encryption using blowfish algorithm (mcrypt) + * or phpseclib's AES if mcrypt not available + * + * @param string $data original data + * @param string $secret the secret + * + * @return string the encrypted result + */ + public function blowfishEncrypt($data, $secret) + { + global $iv; + if (! function_exists('mcrypt_encrypt')) { + /** + * This library uses mcrypt when available, so + * we could always call it instead of having an + * if/then/else logic, however the include_once + * call is costly + */ + include_once "./libraries/phpseclib/Crypt/AES.php"; + $cipher = new Crypt_AES(CRYPT_AES_MODE_ECB); + $cipher->setKey($secret); + return base64_encode($cipher->encrypt($data)); + } else { + return base64_encode( + mcrypt_encrypt( + MCRYPT_BLOWFISH, + $secret, + $data, + MCRYPT_MODE_CBC, + $iv + ) + ); + } + } + + /** + * Decryption using blowfish algorithm (mcrypt) + * or phpseclib's AES if mcrypt not available + * + * @param string $encdata encrypted data + * @param string $secret the secret + * + * @return string original data + */ + public function blowfishDecrypt($encdata, $secret) + { + global $iv; + if (! function_exists('mcrypt_encrypt')) { + include_once "./libraries/phpseclib/Crypt/AES.php"; + $cipher = new Crypt_AES(CRYPT_AES_MODE_ECB); + $cipher->setKey($secret); + return $cipher->decrypt(base64_decode($encdata)); + } else { + $data = base64_decode($encdata); + $decrypted = mcrypt_decrypt( + MCRYPT_BLOWFISH, + $secret, + $data, + MCRYPT_MODE_CBC, + $iv + ); + return trim($decrypted); + } + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } +} diff --git a/phpMyAdmin/libraries/plugins/auth/AuthenticationHttp.class.php b/phpMyAdmin/libraries/plugins/auth/AuthenticationHttp.class.php new file mode 100644 index 0000000..75273b1 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/auth/AuthenticationHttp.class.php @@ -0,0 +1,261 @@ +getFooter()->setMinimal(); + $header = $response->getHeader(); + $header->setTitle(__('Access denied')); + $header->disableMenu(); + $header->setBodyId('loginform'); + + $response->addHTML('

    '); + $response->addHTML(sprintf(__('Welcome to %s'), ' phpMyAdmin')); + $response->addHTML('

    '); + $response->addHTML('

    '); + $response->addHTML( + PMA_Message::error( + __('Wrong username/password. Access denied.') + ) + ); + $response->addHTML('

    '); + + if (file_exists(CUSTOM_FOOTER_FILE)) { + include CUSTOM_FOOTER_FILE; + } + + if (! defined('TESTSUITE')) { + exit; + } else { + return false; + } + } + + /** + * Gets advanced authentication settings + * + * @global string $PHP_AUTH_USER the username if register_globals is on + * @global string $PHP_AUTH_PW the password if register_globals is on + * @global array the array of server variables if + * register_globals is off + * @global array the array of environment variables if + * register_globals is off + * @global string the username for the ? server + * @global string the password for the ? server + * @global string the username for the WebSite Professional + * server + * @global string the password for the WebSite Professional + * server + * @global string the username of the user who logs out + * + * @return boolean whether we get authentication settings or not + */ + public function authCheck() + { + global $PHP_AUTH_USER, $PHP_AUTH_PW; + + // Grabs the $PHP_AUTH_USER variable whatever are the values of the + // 'register_globals' and the 'variables_order' directives + if (empty($PHP_AUTH_USER)) { + if (PMA_getenv('PHP_AUTH_USER')) { + $PHP_AUTH_USER = PMA_getenv('PHP_AUTH_USER'); + } elseif (PMA_getenv('REMOTE_USER')) { + // CGI, might be encoded, see below + $PHP_AUTH_USER = PMA_getenv('REMOTE_USER'); + } elseif (PMA_getenv('REDIRECT_REMOTE_USER')) { + // CGI, might be encoded, see below + $PHP_AUTH_USER = PMA_getenv('REDIRECT_REMOTE_USER'); + } elseif (PMA_getenv('AUTH_USER')) { + // WebSite Professional + $PHP_AUTH_USER = PMA_getenv('AUTH_USER'); + } elseif (PMA_getenv('HTTP_AUTHORIZATION') + && false === strpos(PMA_getenv('HTTP_AUTHORIZATION'), '<') + ) { + // IIS, might be encoded, see below; also prevent XSS + $PHP_AUTH_USER = PMA_getenv('HTTP_AUTHORIZATION'); + } elseif (PMA_getenv('Authorization')) { + // FastCGI, might be encoded, see below + $PHP_AUTH_USER = PMA_getenv('Authorization'); + } + } + // Grabs the $PHP_AUTH_PW variable whatever are the values of the + // 'register_globals' and the 'variables_order' directives + if (empty($PHP_AUTH_PW)) { + if (PMA_getenv('PHP_AUTH_PW')) { + $PHP_AUTH_PW = PMA_getenv('PHP_AUTH_PW'); + } elseif (PMA_getenv('REMOTE_PASSWORD')) { + // Apache/CGI + $PHP_AUTH_PW = PMA_getenv('REMOTE_PASSWORD'); + } elseif (PMA_getenv('AUTH_PASSWORD')) { + // WebSite Professional + $PHP_AUTH_PW = PMA_getenv('AUTH_PASSWORD'); + } + } + + // Decode possibly encoded information (used by IIS/CGI/FastCGI) + // (do not use explode() because a user might have a colon in his password + if (strcmp(substr($PHP_AUTH_USER, 0, 6), 'Basic ') == 0) { + $usr_pass = base64_decode(substr($PHP_AUTH_USER, 6)); + if (! empty($usr_pass)) { + $colon = strpos($usr_pass, ':'); + if ($colon) { + $PHP_AUTH_USER = substr($usr_pass, 0, $colon); + $PHP_AUTH_PW = substr($usr_pass, $colon + 1); + } + unset($colon); + } + unset($usr_pass); + } + + // User logged out -> ensure the new username is not the same + $old_usr = isset($_REQUEST['old_usr']) ? $_REQUEST['old_usr'] : ''; + if (! empty($old_usr) + && (isset($PHP_AUTH_USER) && $old_usr == $PHP_AUTH_USER) + ) { + $PHP_AUTH_USER = ''; + // -> delete user's choices that were stored in session + if (! defined('TESTSUITE')) { + session_destroy(); + } + } + + // Returns whether we get authentication settings or not + if (empty($PHP_AUTH_USER)) { + return false; + } else { + return true; + } + } + + /** + * Set the user and password after last checkings if required + * + * @global array $cfg the valid servers settings + * @global integer $server the id of the current server + * @global array the current server settings + * @global string $PHP_AUTH_USER the current username + * @global string $PHP_AUTH_PW the current password + * + * @return boolean always true + */ + public function authSetUser() + { + global $cfg, $server; + global $PHP_AUTH_USER, $PHP_AUTH_PW; + + // Ensures valid authentication mode, 'only_db', bookmark database and + // table names and relation table name are used + if ($cfg['Server']['user'] != $PHP_AUTH_USER) { + $servers_cnt = count($cfg['Servers']); + for ($i = 1; $i <= $servers_cnt; $i++) { + if (isset($cfg['Servers'][$i]) + && ($cfg['Servers'][$i]['host'] == $cfg['Server']['host'] + && $cfg['Servers'][$i]['user'] == $PHP_AUTH_USER) + ) { + $server = $i; + $cfg['Server'] = $cfg['Servers'][$i]; + break; + } + } // end for + } // end if + + $cfg['Server']['user'] = $PHP_AUTH_USER; + $cfg['Server']['password'] = $PHP_AUTH_PW; + + // Avoid showing the password in phpinfo()'s output + unset($GLOBALS['PHP_AUTH_PW']); + unset($_SERVER['PHP_AUTH_PW']); + + return true; + } + + /** + * User is not allowed to login to MySQL -> authentication failed + * + * @return boolean always true (no return indeed) + */ + public function authFails() + { + $error = $GLOBALS['dbi']->getError(); + if ($error && $GLOBALS['errno'] != 1045) { + PMA_fatalError($error); + } else { + $this->auth(); + return true; + } + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } +} diff --git a/phpMyAdmin/libraries/plugins/auth/AuthenticationSignon.class.php b/phpMyAdmin/libraries/plugins/auth/AuthenticationSignon.class.php new file mode 100644 index 0000000..4586af9 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/auth/AuthenticationSignon.class.php @@ -0,0 +1,299 @@ + authentication failed + * + * @return boolean always true (no return indeed) + */ + public function authFails() + { + /* Session name */ + $session_name = $GLOBALS['cfg']['Server']['SignonSession']; + + /* Does session exist? */ + if (isset($_COOKIE[$session_name])) { + /* End current session */ + if (! defined('TESTSUITE')) { + session_write_close(); + } + + /* Load single signon session */ + session_name($session_name); + session_id($_COOKIE[$session_name]); + if (! defined('TESTSUITE')) { + session_start(); + } + + /* Set error message */ + if (! empty($GLOBALS['login_without_password_is_forbidden'])) { + $_SESSION['PMA_single_signon_error_message'] = __( + 'Login without a password is forbidden by configuration ' + . '(see AllowNoPassword)' + ); + } elseif (! empty($GLOBALS['allowDeny_forbidden'])) { + $_SESSION['PMA_single_signon_error_message'] = __('Access denied'); + } elseif (! empty($GLOBALS['no_activity'])) { + $_SESSION['PMA_single_signon_error_message'] = sprintf( + __('No activity within %s seconds; please log in again.'), + $GLOBALS['cfg']['LoginCookieValidity'] + ); + } elseif ($GLOBALS['dbi']->getError()) { + $_SESSION['PMA_single_signon_error_message'] = PMA_sanitize( + $GLOBALS['dbi']->getError() + ); + } else { + $_SESSION['PMA_single_signon_error_message'] = __( + 'Cannot log in to the MySQL server' + ); + } + } + $this->auth(); + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } +} diff --git a/phpMyAdmin/libraries/plugins/auth/recaptchalib.php b/phpMyAdmin/libraries/plugins/auth/recaptchalib.php new file mode 100644 index 0000000..32c4f4d --- /dev/null +++ b/phpMyAdmin/libraries/plugins/auth/recaptchalib.php @@ -0,0 +1,277 @@ + $value ) + $req .= $key . '=' . urlencode( stripslashes($value) ) . '&'; + + // Cut the last '&' + $req=substr($req,0,strlen($req)-1); + return $req; +} + + + +/** + * Submits an HTTP POST to a reCAPTCHA server + * @param string $host + * @param string $path + * @param array $data + * @param int port + * @return array response + */ +function _recaptcha_http_post($host, $path, $data, $port = 80) { + + $req = _recaptcha_qsencode ($data); + + $http_request = "POST $path HTTP/1.0\r\n"; + $http_request .= "Host: $host\r\n"; + $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n"; + $http_request .= "Content-Length: " . strlen($req) . "\r\n"; + $http_request .= "User-Agent: reCAPTCHA/PHP\r\n"; + $http_request .= "\r\n"; + $http_request .= $req; + + $response = ''; + if( false == ( $fs = @fsockopen($host, $port, $errno, $errstr, 10) ) ) { + die ('Could not open socket'); + } + + fwrite($fs, $http_request); + + while ( !feof($fs) ) + $response .= fgets($fs, 1160); // One TCP-IP packet + fclose($fs); + $response = explode("\r\n\r\n", $response, 2); + + return $response; +} + + + +/** + * Gets the challenge HTML (javascript and non-javascript version). + * This is called from the browser, and the resulting reCAPTCHA HTML widget + * is embedded within the HTML form it was called from. + * @param string $pubkey A public key for reCAPTCHA + * @param string $error The error given by reCAPTCHA (optional, default is null) + * @param boolean $use_ssl Should the request be made over ssl? (optional, default is false) + + * @return string - The HTML to be embedded in the user's form. + */ +function recaptcha_get_html ($pubkey, $error = null, $use_ssl = false) +{ + if ($pubkey == null || $pubkey == '') { + die ("To use reCAPTCHA you must get an API key from https://www.google.com/recaptcha/admin/create"); + } + + if ($use_ssl) { + $server = RECAPTCHA_API_SECURE_SERVER; + } else { + $server = RECAPTCHA_API_SERVER; + } + + $errorpart = ""; + if ($error) { + $errorpart = "&error=" . $error; + } + return ' + + '; +} + + + + +/** + * A ReCaptchaResponse is returned from recaptcha_check_answer() + */ +class ReCaptchaResponse { + var $is_valid; + var $error; +} + + +/** + * Calls an HTTP POST function to verify if the user's guess was correct + * @param string $privkey + * @param string $remoteip + * @param string $challenge + * @param string $response + * @param array $extra_params an array of extra variables to post to the server + * @return ReCaptchaResponse + */ +function recaptcha_check_answer ($privkey, $remoteip, $challenge, $response, $extra_params = array()) +{ + if ($privkey == null || $privkey == '') { + die ("To use reCAPTCHA you must get an API key from https://www.google.com/recaptcha/admin/create"); + } + + if ($remoteip == null || $remoteip == '') { + die ("For security reasons, you must pass the remote ip to reCAPTCHA"); + } + + + + //discard spam submissions + if ($challenge == null || strlen($challenge) == 0 || $response == null || strlen($response) == 0) { + $recaptcha_response = new ReCaptchaResponse(); + $recaptcha_response->is_valid = false; + $recaptcha_response->error = 'incorrect-captcha-sol'; + return $recaptcha_response; + } + + $response = _recaptcha_http_post (RECAPTCHA_VERIFY_SERVER, "/recaptcha/api/verify", + array ( + 'privatekey' => $privkey, + 'remoteip' => $remoteip, + 'challenge' => $challenge, + 'response' => $response + ) + $extra_params + ); + + $answers = explode ("\n", $response [1]); + $recaptcha_response = new ReCaptchaResponse(); + + if (trim ($answers [0]) == 'true') { + $recaptcha_response->is_valid = true; + } + else { + $recaptcha_response->is_valid = false; + $recaptcha_response->error = $answers [1]; + } + return $recaptcha_response; + +} + +/** + * gets a URL where the user can sign up for reCAPTCHA. If your application + * has a configuration page where you enter a key, you should provide a link + * using this function. + * @param string $domain The domain where the page is hosted + * @param string $appname The name of your application + */ +function recaptcha_get_signup_url ($domain = null, $appname = null) { + return "https://www.google.com/recaptcha/admin/create?" . _recaptcha_qsencode (array ('domains' => $domain, 'app' => $appname)); +} + +function _recaptcha_aes_pad($val) { + $block_size = 16; + $numpad = $block_size - (strlen ($val) % $block_size); + return str_pad($val, strlen ($val) + $numpad, chr($numpad)); +} + +/* Mailhide related code */ + +function _recaptcha_aes_encrypt($val,$ky) { + if (! function_exists ("mcrypt_encrypt")) { + die ("To use reCAPTCHA Mailhide, you need to have the mcrypt php module installed."); + } + $mode=MCRYPT_MODE_CBC; + $enc=MCRYPT_RIJNDAEL_128; + $val=_recaptcha_aes_pad($val); + return mcrypt_encrypt($enc, $ky, $val, $mode, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); +} + + +function _recaptcha_mailhide_urlbase64 ($x) { + return strtr(base64_encode ($x), '+/', '-_'); +} + +/* gets the reCAPTCHA Mailhide url for a given email, public key and private key */ +function recaptcha_mailhide_url($pubkey, $privkey, $email) { + if ($pubkey == '' || $pubkey == null || $privkey == "" || $privkey == null) { + die ("To use reCAPTCHA Mailhide, you have to sign up for a public and private key, " . + "you can do so at http://www.google.com/recaptcha/mailhide/apikey"); + } + + + $ky = pack('H*', $privkey); + $cryptmail = _recaptcha_aes_encrypt ($email, $ky); + + return "http://www.google.com/recaptcha/mailhide/d?k=" . $pubkey . "&c=" . _recaptcha_mailhide_urlbase64 ($cryptmail); +} + +/** + * gets the parts of the email to expose to the user. + * eg, given johndoe@example,com return ["john", "example.com"]. + * the email is then displayed as john...@example.com + */ +function _recaptcha_mailhide_email_parts ($email) { + $arr = preg_split("/@/", $email ); + + if (strlen ($arr[0]) <= 4) { + $arr[0] = substr ($arr[0], 0, 1); + } else if (strlen ($arr[0]) <= 6) { + $arr[0] = substr ($arr[0], 0, 3); + } else { + $arr[0] = substr ($arr[0], 0, 4); + } + return $arr; +} + +/** + * Gets html to display an email address given a public an private key. + * to get a key, go to: + * + * http://www.google.com/recaptcha/mailhide/apikey + */ +function recaptcha_mailhide_html($pubkey, $privkey, $email) { + $emailparts = _recaptcha_mailhide_email_parts ($email); + $url = recaptcha_mailhide_url ($pubkey, $privkey, $email); + + return htmlentities($emailparts[0]) . "...@" . htmlentities ($emailparts [1]); + +} + + +?> diff --git a/phpMyAdmin/libraries/auth/swekey/authentication.inc.php b/phpMyAdmin/libraries/plugins/auth/swekey/authentication.inc.php similarity index 100% rename from phpMyAdmin/libraries/auth/swekey/authentication.inc.php rename to phpMyAdmin/libraries/plugins/auth/swekey/authentication.inc.php diff --git a/phpMyAdmin/libraries/auth/swekey/musbe-ca.crt b/phpMyAdmin/libraries/plugins/auth/swekey/musbe-ca.crt similarity index 100% rename from phpMyAdmin/libraries/auth/swekey/musbe-ca.crt rename to phpMyAdmin/libraries/plugins/auth/swekey/musbe-ca.crt diff --git a/phpMyAdmin/libraries/auth/swekey/swekey.auth.lib.php b/phpMyAdmin/libraries/plugins/auth/swekey/swekey.auth.lib.php similarity index 66% rename from phpMyAdmin/libraries/auth/swekey/swekey.auth.lib.php rename to phpMyAdmin/libraries/plugins/auth/swekey/swekey.auth.lib.php index df7e56e..9c36efc 100644 --- a/phpMyAdmin/libraries/auth/swekey/swekey.auth.lib.php +++ b/phpMyAdmin/libraries/plugins/auth/swekey/swekey.auth.lib.php @@ -1,12 +1,17 @@ \n"; -// if (file_exists($caFile)) -// echo "\n"; + // echo "\n\n"; + // if (file_exists($caFile)) + // echo "\n"; } if (file_exists($caFile)) { Swekey_SetCAFile($caFile); - } elseif (! empty($caFile) && (substr($_SESSION['SWEKEY']['CONF_SERVER_CHECK'], 0, 8) == "https://")) { + } elseif (! empty($caFile) + && (substr($_SESSION['SWEKEY']['CONF_SERVER_CHECK'], 0, 8) == "https://")) { return "Internal Error: CA File $caFile not found"; } @@ -153,7 +182,7 @@ function timedCheck() $res = Swekey_CheckOtp($swekey_id, $_SESSION['SWEKEY']['RND_TOKEN'], $swekey_otp); unset($_SESSION['SWEKEY']['RND_TOKEN']); if (! $res) { - $result = __('Hardware authentication failed') . ' (' . Swekey_GetLastError() . ')'; + $result = __('Hardware authentication failed!') . ' (' . Swekey_GetLastError() . ')'; } else { $_SESSION['SWEKEY']['AUTHENTICATED_SWEKEY'] = $swekey_id; $_SESSION['SWEKEY']['FORCE_USER'] = $_SESSION['SWEKEY']['VALID_SWEKEYS'][$swekey_id]; @@ -162,7 +191,7 @@ function timedCheck() } else { $result = __('No valid authentication key plugged'); if ($_SESSION['SWEKEY']['CONF_DEBUG']) { - $result .= "
    " . htmlspecialchars($swekey_id); + $result .= "
    " . htmlspecialchars($swekey_id); } unset($_SESSION['SWEKEY']['CONF_LOADED']); // reload the conf file } @@ -173,26 +202,27 @@ function timedCheck() $_SESSION['SWEKEY']['RND_TOKEN'] = Swekey_GetFastRndToken(); if (strlen($_SESSION['SWEKEY']['RND_TOKEN']) != 64) { - $result = __('Hardware authentication failed') . ' (' . Swekey_GetLastError() . ')'; + $result = __('Hardware authentication failed!') . ' (' . Swekey_GetLastError() . ')'; unset($_SESSION['SWEKEY']['CONF_LOADED']); // reload the conf file } if (! isset($swekey_id)) { ?> display(); if ($GLOBALS['error_handler']->hasDisplayErrors()) { @@ -219,7 +249,7 @@ function Swekey_login($input_name, $input_go) if (empty($_SESSION['SWEKEY']['FORCE_USER'])) { echo 'var user = null;'; } else { - echo 'var user = "'.$_SESSION['SWEKEY']['FORCE_USER'].'";'; + echo 'var user = "'.$_SESSION['SWEKEY']['FORCE_USER'].'";'; } ?> @@ -233,24 +263,22 @@ function open_swekey_site() var swekey_status = document.createElement('img'); swekey_status.setAttribute('onclick', 'open_swekey_site()'); swekey_status.setAttribute('style', 'width:8px; height:16px; border:0px; vspace:0px; hspace:0px; frameborder:no'); - if (user == null) - { + if (user == null) { swekey_status.setAttribute('src', 'http://artwork.swekey.com/unplugged-8x16.png'); //swekey_status.setAttribute('title', 'No swekey plugged'); input_go.disabled = true; - } - else - { + } else { swekey_status.setAttribute('src', 'http://artwork.swekey.com/plugged-8x16.png'); //swekey_status.setAttribute('title', 'swekey plugged'); input_username.value = user; } - input_username.readOnly = true; + input_username.readOnly = true; - if (input_username.nextSibling == null) + if (input_username.nextSibling == null) { input_username.parentNode.appendChild(swekey_status); - else + } else { input_username.parentNode.insertBefore(swekey_status, input_username.nextSibling); + } '; diff --git a/phpMyAdmin/libraries/auth/swekey/swekey.php b/phpMyAdmin/libraries/plugins/auth/swekey/swekey.php similarity index 72% rename from phpMyAdmin/libraries/auth/swekey/swekey.php rename to phpMyAdmin/libraries/plugins/auth/swekey/swekey.php index 3c6bd80..d495d45 100644 --- a/phpMyAdmin/libraries/auth/swekey/swekey.php +++ b/phpMyAdmin/libraries/plugins/auth/swekey/swekey.php @@ -18,25 +18,25 @@ /** * Errors codes */ -define ("SWEKEY_ERR_INVALID_DEV_STATUS", 901); // The satus of the device is not SWEKEY_STATUS_OK -define ("SWEKEY_ERR_INTERNAL", 902); // Should never occurd -define ("SWEKEY_ERR_OUTDATED_RND_TOKEN", 910); // You random token is too old -define ("SWEKEY_ERR_INVALID_OTP", 911); // The otp was not correct +define("SWEKEY_ERR_INVALID_DEV_STATUS", 901); // The satus of the device is not SWEKEY_STATUS_OK +define("SWEKEY_ERR_INTERNAL", 902); // Should never occurd +define("SWEKEY_ERR_OUTDATED_RND_TOKEN", 910); // You random token is too old +define("SWEKEY_ERR_INVALID_OTP", 911); // The otp was not correct /** * Those errors are considered as an attack and your site will be blacklisted during one minute * if you receive one of those errors */ -define ("SWEKEY_ERR_BADLY_ENCODED_REQUEST", 920); -define ("SWEKEY_ERR_INVALID_RND_TOKEN", 921); -define ("SWEKEY_ERR_DEV_NOT_FOUND", 922); +define("SWEKEY_ERR_BADLY_ENCODED_REQUEST", 920); +define("SWEKEY_ERR_INVALID_RND_TOKEN", 921); +define("SWEKEY_ERR_DEV_NOT_FOUND", 922); /** * Default values for configuration. */ -define ('SWEKEY_DEFAULT_CHECK_SERVER', 'https://auth-check.musbe.net'); -define ('SWEKEY_DEFAULT_RND_SERVER', 'https://auth-rnd-gen.musbe.net'); -define ('SWEKEY_DEFAULT_STATUS_SERVER', 'https://auth-status.musbe.net'); +define('SWEKEY_DEFAULT_CHECK_SERVER', 'https://auth-check.musbe.net'); +define('SWEKEY_DEFAULT_RND_SERVER', 'https://auth-rnd-gen.musbe.net'); +define('SWEKEY_DEFAULT_STATUS_SERVER', 'https://auth-status.musbe.net'); /** * The last error of an operation is alway put in this global var @@ -54,81 +54,92 @@ */ global $gSwekeyCheckServer; -if (! isset($gSwekeyCheckServer)) +if (! isset($gSwekeyCheckServer)) { $gSwekeyCheckServer = SWEKEY_DEFAULT_CHECK_SERVER; +} global $gSwekeyRndTokenServer; -if (! isset($gSwekeyRndTokenServer)) +if (! isset($gSwekeyRndTokenServer)) { $gSwekeyRndTokenServer = SWEKEY_DEFAULT_RND_SERVER; +} global $gSwekeyStatusServer; -if (! isset($gSwekeyStatusServer)) +if (! isset($gSwekeyStatusServer)) { $gSwekeyStatusServer = SWEKEY_DEFAULT_STATUS_SERVER; +} global $gSwekeyCA; global $gSwekeyTokenCacheEnabled; -if (! isset($gSwekeyTokenCacheEnabled)) +if (! isset($gSwekeyTokenCacheEnabled)) { $gSwekeyTokenCacheEnabled = true; +} /** * Change the address of the Check server. * If $server is empty the default value 'http://auth-check.musbe.net' will be used * - * @param server The protocol and hostname to use - * @access public + * @param server The protocol and hostname to use + * + * @access public */ function Swekey_SetCheckServer($server) { global $gSwekeyCheckServer; - if (empty($server)) + if (empty($server)) { $gSwekeyCheckServer = SWEKEY_DEFAULT_CHECK_SERVER; - else + } else { $gSwekeyCheckServer = $server; + } } /** * Change the address of the Random Token Generator server. * If $server is empty the default value 'http://auth-rnd-gen.musbe.net' will be used * - * @param server The protocol and hostname to use - * @access public + * @param server The protocol and hostname to use + * + * @access public */ function Swekey_SetRndTokenServer($server) { global $gSwekeyRndTokenServer; - if (empty($server)) + if (empty($server)) { $gSwekeyRndTokenServer = SWEKEY_DEFAULT_RND_SERVER; - else + } else { $gSwekeyRndTokenServer = $server; + } } /** * Change the address of the Satus server. * If $server is empty the default value 'http://auth-status.musbe.net' will be used * - * @param server The protocol and hostname to use - * @access public + * @param server The protocol and hostname to use + * + * @access public */ function Swekey_SetStatusServer($server) { global $gSwekeyStatusServer; - if (empty($server)) + if (empty($server)) { $gSwekeyStatusServer = SWEKEY_DEFAULT_STATUS_SERVER; - else + } else { $gSwekeyStatusServer = $server; + } } /** * Change the certificat file in case of the the severs use https instead of http * - * @param cafile The path of the crt file to use - * @access public + * @param cafile The path of the crt file to use + * + * @access public */ function Swekey_SetCAFile($cafile) { global $gSwekeyCA; - $gSwekeyCA = $cafile; + $gSwekeyCA = $cafile; } /** @@ -136,8 +147,9 @@ function Swekey_SetCAFile($cafile) * Because everybody has full access to the cache file, it can be a DOS vulnerability * So disable it if you are running in a non secure enviromnement * - * @param $enable - * @access public + * @param $enable + * + * @access public */ function Swekey_EnableTokenCache($enable) { @@ -149,8 +161,8 @@ function Swekey_EnableTokenCache($enable) /** * Return the last error. * - * @return The Last Error - * @access public + * @return The Last Error + * @access public */ function Swekey_GetLastError() { @@ -161,8 +173,8 @@ function Swekey_GetLastError() /** * Return the last result. * - * @return The Last Error - * @access public + * @return The Last Error + * @access public */ function Swekey_GetLastResult() { @@ -174,10 +186,11 @@ function Swekey_GetLastResult() * Send a synchronous request to the server. * This function manages timeout then will not block if one of the server is down * - * @param url The url to get - * @param response_code The response code - * @return The body of the response or "" in case of error - * @access private + * @param url The url to get + * @param response_code The response code + * + * @return The body of the response or "" in case of error + * @access private */ function Swekey_HttpGet($url, &$response_code) { @@ -271,8 +284,7 @@ function Swekey_HttpGet($url, &$response_code) $res = $reply->getBody(); $info = $r->getResponseInfo(); $response_code = $info['response_code']; - if ($response_code != 200) - { + if ($response_code != 200) { $gSwekeyLastError = $response_code; error_log("SWEKEY_ERROR:Error ".$gSwekeyLastError." getting ".$url); return ""; @@ -298,8 +310,8 @@ function Swekey_HttpGet($url, &$response_code) $res = @file_get_contents($url); $response_code = substr($http_response_header[0], 9, 3); //HTTP/1.0 if ($response_code == 200) { - $gSwekeyLastResult = $res; - return $res; + $gSwekeyLastResult = $res; + return $res; } $gSwekeyLastError = $response_code; @@ -311,7 +323,7 @@ function Swekey_HttpGet($url, &$response_code) * Get a Random Token from a Token Server * The RT is a 64 vhars hexadecimal value * You should better use Swekey_GetFastRndToken() for performance - * @access public + * @access public */ function Swekey_GetRndToken() { @@ -323,7 +335,7 @@ function Swekey_GetRndToken() * Get a Half Random Token from a Token Server * The RT is a 64 vhars hexadecimal value * Use this value if you want to make your own Swekey_GetFastRndToken() - * @access public + * @access public */ function Swekey_GetHalfRndToken() { @@ -337,7 +349,7 @@ function Swekey_GetHalfRndToken() * This function get a new random token and reuse it. * Token are refetched from the server only once every 30 seconds. * You should always use this function to get half random token. - * @access public + * @access public */ function Swekey_GetFastHalfRndToken() { @@ -389,7 +401,7 @@ function Swekey_GetFastHalfRndToken() } } - return $res."00000000000000000000000000000000"; + return $res."00000000000000000000000000000000"; } /** @@ -398,14 +410,14 @@ function Swekey_GetFastHalfRndToken() * This function generates a unique random token for each call but call the * server only once every 30 seconds. * You should always use this function to get random token. - * @access public + * @access public */ function Swekey_GetFastRndToken() { $res = Swekey_GetFastHalfRndToken(); - if (strlen($res) == 64) - return substr($res, 0, 32).strtoupper(md5("Musbe Authentication Key" + mt_rand() + date(DATE_ATOM))); - + if (strlen($res) == 64) { + return substr($res, 0, 32).strtoupper(md5("Musbe Authentication Key" . mt_rand() . date(DATE_ATOM))); + } return ""; } @@ -413,11 +425,12 @@ function Swekey_GetFastRndToken() /** * Checks that an OTP generated by a Swekey is valid * - * @param id The id of the swekey - * @param rt The random token used to generate the otp - * @param otp The otp generated by the swekey - * @return true or false - * @access public + * @param id The id of the swekey + * @param rt The random token used to generate the otp + * @param otp The otp generated by the swekey + * + * @return true or false + * @access public */ function Swekey_CheckOtp($id, $rt, $otp) { @@ -430,46 +443,58 @@ function Swekey_CheckOtp($id, $rt, $otp) * Values that are associated with a key. * The following values can be returned by the Swekey_GetStatus() function */ -define ("SWEKEY_STATUS_OK", 0); -define ("SWEKEY_STATUS_NOT_FOUND", 1); // The key does not exist in the db -define ("SWEKEY_STATUS_INACTIVE", 2); // The key has never been activated -define ("SWEKEY_STATUS_LOST", 3); // The user has lost his key -define ("SWEKEY_STATUS_STOLEN", 4); // The key was stolen -define ("SWEKEY_STATUS_FEE_DUE", 5); // The annual fee was not paid -define ("SWEKEY_STATUS_OBSOLETE", 6); // The hardware is no longer supported -define ("SWEKEY_STATUS_UNKOWN", 201); // We could not connect to the authentication server +define("SWEKEY_STATUS_OK", 0); +define("SWEKEY_STATUS_NOT_FOUND", 1); // The key does not exist in the db +define("SWEKEY_STATUS_INACTIVE", 2); // The key has never been activated +define("SWEKEY_STATUS_LOST", 3); // The user has lost his key +define("SWEKEY_STATUS_STOLEN", 4); // The key was stolen +define("SWEKEY_STATUS_FEE_DUE", 5); // The annual fee was not paid +define("SWEKEY_STATUS_OBSOLETE", 6); // The hardware is no longer supported +define("SWEKEY_STATUS_UNKOWN", 201); // We could not connect to the authentication server /** * Values that are associated with a key. * The Javascript Api can also return the following values */ -define ("SWEKEY_STATUS_REPLACED", 100); // This key has been replaced by a backup key -define ("SWEKEY_STATUS_BACKUP_KEY", 101); // This key is a backup key that is not activated yet -define ("SWEKEY_STATUS_NOTPLUGGED", 200); // This key is not plugged in the computer +define("SWEKEY_STATUS_REPLACED", 100); // This key has been replaced by a backup key +define("SWEKEY_STATUS_BACKUP_KEY", 101); // This key is a backup key that is not activated yet +define("SWEKEY_STATUS_NOTPLUGGED", 200); // This key is not plugged in the computer /** * Return the text corresponding to the integer status of a key * - * @param status The status - * @return The text corresponding to the status - * @access public + * @param status The status + * + * @return The text corresponding to the status + * @access public */ function Swekey_GetStatusStr($status) { switch($status) { - case SWEKEY_STATUS_OK : return 'OK'; - case SWEKEY_STATUS_NOT_FOUND : return 'Key does not exist in the db'; - case SWEKEY_STATUS_INACTIVE : return 'Key not activated'; - case SWEKEY_STATUS_LOST : return 'Key was lost'; - case SWEKEY_STATUS_STOLEN : return 'Key was stolen'; - case SWEKEY_STATUS_FEE_DUE : return 'The annual fee was not paid'; - case SWEKEY_STATUS_OBSOLETE : return 'Key no longer supported'; - case SWEKEY_STATUS_REPLACED : return 'This key has been replaced by a backup key'; - case SWEKEY_STATUS_BACKUP_KEY : return 'This key is a backup key that is not activated yet'; - case SWEKEY_STATUS_NOTPLUGGED : return 'This key is not plugged in the computer'; - case SWEKEY_STATUS_UNKOWN : return 'Unknow Status, could not connect to the authentication server'; + case SWEKEY_STATUS_OK : + return 'OK'; + case SWEKEY_STATUS_NOT_FOUND : + return 'Key does not exist in the db'; + case SWEKEY_STATUS_INACTIVE : + return 'Key not activated'; + case SWEKEY_STATUS_LOST : + return 'Key was lost'; + case SWEKEY_STATUS_STOLEN : + return 'Key was stolen'; + case SWEKEY_STATUS_FEE_DUE : + return 'The annual fee was not paid'; + case SWEKEY_STATUS_OBSOLETE : + return 'Key no longer supported'; + case SWEKEY_STATUS_REPLACED : + return 'This key has been replaced by a backup key'; + case SWEKEY_STATUS_BACKUP_KEY : + return 'This key is a backup key that is not activated yet'; + case SWEKEY_STATUS_NOTPLUGGED : + return 'This key is not plugged in the computer'; + case SWEKEY_STATUS_UNKOWN : + return 'Unknow Status, could not connect to the authentication server'; } return 'unknown status '.$status; } @@ -478,17 +503,19 @@ function Swekey_GetStatusStr($status) * If your web site requires a key to login you should check that the key * is still valid (has not been lost or stolen) before requiring it. * A key can be authenticated only if its status is SWEKEY_STATUS_OK - * @param id The id of the swekey - * @return The status of the swekey - * @access public + * + * @param id The id of the swekey + * + * @return The status of the swekey + * @access public */ function Swekey_GetStatus($id) { global $gSwekeyStatusServer; $res = Swekey_HttpGet($gSwekeyStatusServer.'/GET-STATUS/'.$id, $response_code); - if ($response_code == 200) + if ($response_code == 200) { return intval($res); - + } return SWEKEY_STATUS_UNKOWN; } diff --git a/phpMyAdmin/libraries/plugins/export/ExportCodegen.class.php b/phpMyAdmin/libraries/plugins/export/ExportCodegen.class.php new file mode 100644 index 0000000..4495e7e --- /dev/null +++ b/phpMyAdmin/libraries/plugins/export/ExportCodegen.class.php @@ -0,0 +1,423 @@ +initSpecificVariables(); + $this->setProperties(); + } + + /** + * Initialize the local variables that are used for export CodeGen + * + * @return void + */ + protected function initSpecificVariables() + { + $this->_setCgFormats( + array( + "NHibernate C# DO", + "NHibernate XML" + ) + ); + + $this->_setCgHandlers( + array( + "_handleNHibernateCSBody", + "_handleNHibernateXMLBody" + ) + ); + } + + /** + * Sets the export CodeGen properties + * + * @return void + */ + protected function setProperties() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/HiddenPropertyItem.class.php"; + include_once "$props/options/items/SelectPropertyItem.class.php"; + + $exportPluginProperties = new ExportPluginProperties(); + $exportPluginProperties->setText('CodeGen'); + $exportPluginProperties->setExtension('cs'); + $exportPluginProperties->setMimeType('text/cs'); + $exportPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $exportPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create primary items and add them to the group + $leaf = new HiddenPropertyItem(); + $leaf->setName("structure_or_data"); + $generalOptions->addProperty($leaf); + $leaf = new SelectPropertyItem(); + $leaf->setName("format"); + $leaf->setText(__('Format:')); + $leaf->setValues($this->_getCgFormats()); + $generalOptions->addProperty($leaf); + // add the main group to the root group + $exportSpecificOptions->addProperty($generalOptions); + + // set the options for the export plugin property item + $exportPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $exportPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Outputs export header + * + * @return bool Whether it succeeded + */ + public function exportHeader () + { + return true; + } + + /** + * Outputs export footer + * + * @return bool Whether it succeeded + */ + public function exportFooter () + { + return true; + } + + /** + * Outputs database header + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + return true; + } + + /** + * Outputs database footer + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBFooter ($db) + { + return true; + } + + /** + * Outputs CREATE DATABASE statement + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + return true; + } + + /** + * Outputs the content of a table in NHibernate format + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $sql_query SQL query for obtaining data + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + $CG_FORMATS = $this->_getCgFormats(); + $CG_HANDLERS = $this->_getCgHandlers(); + + $format = $GLOBALS['codegen_format']; + if (isset($CG_FORMATS[$format])) { + return PMA_exportOutputHandler( + $this->$CG_HANDLERS[$format]($db, $table, $crlf) + ); + } + return PMA_exportOutputHandler(sprintf("%s is not supported.", $format)); + } + + /** + * Used to make identifiers (from table or database names) + * + * @param string $str name to be converted + * @param bool $ucfirst whether to make the first character uppercase + * + * @return string identifier + */ + public static function cgMakeIdentifier($str, $ucfirst = true) + { + // remove unsafe characters + $str = preg_replace('/[^\p{L}\p{Nl}_]/u', '', $str); + // make sure first character is a letter or _ + if (! preg_match('/^\pL/u', $str)) { + $str = '_' . $str; + } + if ($ucfirst) { + $str = ucfirst($str); + } + return $str; + } + + /** + * C# Handler + * + * @param string $db database name + * @param string $table table name + * @param string $crlf line separator + * + * @return string containing C# code lines, separated by "\n" + */ + private function _handleNHibernateCSBody($db, $table, $crlf) + { + $lines = array(); + + $result = $GLOBALS['dbi']->query( + sprintf( + 'DESC %s.%s', PMA_Util::backquote($db), + PMA_Util::backquote($table) + ) + ); + if ($result) { + $tableProperties = array(); + while ($row = $GLOBALS['dbi']->fetchRow($result)) { + $tableProperties[] = new TableProperty($row); + } + $GLOBALS['dbi']->freeResult($result); + $lines[] = 'using System;'; + $lines[] = 'using System.Collections;'; + $lines[] = 'using System.Collections.Generic;'; + $lines[] = 'using System.Text;'; + $lines[] = 'namespace ' . ExportCodegen::cgMakeIdentifier($db); + $lines[] = '{'; + $lines[] = ' #region ' . ExportCodegen::cgMakeIdentifier($table); + $lines[] = ' public class ' . ExportCodegen::cgMakeIdentifier($table); + $lines[] = ' {'; + $lines[] = ' #region Member Variables'; + foreach ($tableProperties as $tableProperty) { + $lines[] = $tableProperty->formatCs( + ' protected #dotNetPrimitiveType# _#name#;' + ); + } + $lines[] = ' #endregion'; + $lines[] = ' #region Constructors'; + $lines[] = ' public ' + . ExportCodegen::cgMakeIdentifier($table) . '() { }'; + $temp = array(); + foreach ($tableProperties as $tableProperty) { + if (! $tableProperty->isPK()) { + $temp[] = $tableProperty->formatCs( + '#dotNetPrimitiveType# #name#' + ); + } + } + $lines[] = ' public ' + . ExportCodegen::cgMakeIdentifier($table) + . '(' + . implode(', ', $temp) + . ')'; + $lines[] = ' {'; + foreach ($tableProperties as $tableProperty) { + if (! $tableProperty->isPK()) { + $lines[] = $tableProperty->formatCs( + ' this._#name#=#name#;' + ); + } + } + $lines[] = ' }'; + $lines[] = ' #endregion'; + $lines[] = ' #region Public Properties'; + foreach ($tableProperties as $tableProperty) { + $lines[] = $tableProperty->formatCs( + ' public virtual #dotNetPrimitiveType# #ucfirstName#' + . "\n" + . ' {' . "\n" + . ' get {return _#name#;}' . "\n" + . ' set {_#name#=value;}' . "\n" + . ' }' + ); + } + $lines[] = ' #endregion'; + $lines[] = ' }'; + $lines[] = ' #endregion'; + $lines[] = '}'; + } + return implode("\n", $lines); + } + + /** + * XML Handler + * + * @param string $db database name + * @param string $table table name + * @param string $crlf line separator + * + * @return string containing XML code lines, separated by "\n" + */ + private function _handleNHibernateXMLBody($db, $table, $crlf) + { + $lines = array(); + $lines[] = ''; + $lines[] = ''; + $lines[] = ' '; + $result = $GLOBALS['dbi']->query( + sprintf( + "DESC %s.%s", PMA_Util::backquote($db), + PMA_Util::backquote($table) + ) + ); + if ($result) { + while ($row = $GLOBALS['dbi']->fetchRow($result)) { + $tableProperty = new TableProperty($row); + if ($tableProperty->isPK()) { + $lines[] = $tableProperty->formatXml( + ' ' . "\n" + . ' ' . "\n" + . ' ' . "\n" + . ' ' + ); + } else { + $lines[] = $tableProperty->formatXml( + ' ' . "\n" + . ' ' . "\n" + . ' ' + ); + } + } + $GLOBALS['dbi']->freeResult($result); + } + $lines[] = ' '; + $lines[] = ''; + return implode("\n", $lines); + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Getter for CodeGen formats + * + * @return array + */ + private function _getCgFormats() + { + return $this->_cgFormats; + } + + /** + * Setter for CodeGen formats + * + * @param array $CG_FORMATS contains CodeGen Formats + * + * @return void + */ + private function _setCgFormats($CG_FORMATS) + { + $this->_cgFormats = $CG_FORMATS; + } + + /** + * Getter for CodeGen handlers + * + * @return array + */ + private function _getCgHandlers() + { + return $this->_cgHandlers; + } + + /** + * Setter for CodeGen handlers + * + * @param array $CG_HANDLERS contains CodeGen handler methods + * + * @return void + */ + private function _setCgHandlers($CG_HANDLERS) + { + $this->_cgHandlers = $CG_HANDLERS; + } +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/export/ExportCsv.class.php b/phpMyAdmin/libraries/plugins/export/ExportCsv.class.php new file mode 100644 index 0000000..22cbd63 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/export/ExportCsv.class.php @@ -0,0 +1,321 @@ +setProperties(); + } + + /** + * Sets the export CSV properties + * + * @return void + */ + protected function setProperties() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/TextPropertyItem.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + include_once "$props/options/items/HiddenPropertyItem.class.php"; + + $exportPluginProperties = new ExportPluginProperties(); + $exportPluginProperties->setText('CSV'); + $exportPluginProperties->setExtension('csv'); + $exportPluginProperties->setMimeType('text/comma-separated-values'); + $exportPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $exportPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create leaf items and add them to the group + $leaf = new TextPropertyItem(); + $leaf->setName("separator"); + $leaf->setText(__('Columns separated with:')); + $generalOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("enclosed"); + $leaf->setText(__('Columns enclosed with:')); + $generalOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("escaped"); + $leaf->setText(__('Columns escaped with:')); + $generalOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("terminated"); + $leaf->setText(__('Lines terminated with:')); + $generalOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName('null'); + $leaf->setText(__('Replace NULL with:')); + $generalOptions->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName('removeCRLF'); + $leaf->setText( + __('Remove carriage return/line feed characters within columns') + ); + $generalOptions->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName('columns'); + $leaf->setText(__('Put columns names in the first row')); + $generalOptions->addProperty($leaf); + $leaf = new HiddenPropertyItem(); + $leaf->setName('structure_or_data'); + $generalOptions->addProperty($leaf); + // add the main group to the root group + $exportSpecificOptions->addProperty($generalOptions); + + // set the options for the export plugin property item + $exportPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $exportPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Outputs export header + * + * @return bool Whether it succeeded + */ + public function exportHeader () + { + global $what, $csv_terminated, $csv_separator, $csv_enclosed, $csv_escaped; + + // Here we just prepare some values for export + if ($what == 'excel') { + $csv_terminated = "\015\012"; + switch($GLOBALS['excel_edition']) { + case 'win': + // as tested on Windows with Excel 2002 and Excel 2007 + $csv_separator = ';'; + break; + case 'mac_excel2003': + $csv_separator = ';'; + break; + case 'mac_excel2008': + $csv_separator = ','; + break; + } + $csv_enclosed = '"'; + $csv_escaped = '"'; + if (isset($GLOBALS['excel_columns'])) { + $GLOBALS['csv_columns'] = 'yes'; + } + } else { + if (empty($csv_terminated) || strtolower($csv_terminated) == 'auto') { + $csv_terminated = $GLOBALS['crlf']; + } else { + $csv_terminated = str_replace('\\r', "\015", $csv_terminated); + $csv_terminated = str_replace('\\n', "\012", $csv_terminated); + $csv_terminated = str_replace('\\t', "\011", $csv_terminated); + } // end if + $csv_separator = str_replace('\\t', "\011", $csv_separator); + } + + return true; + } + + /** + * Outputs export footer + * + * @return bool Whether it succeeded + */ + public function exportFooter () + { + return true; + } + + /** + * Outputs database header + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + return true; + } + + /** + * Outputs database footer + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBFooter ($db) + { + return true; + } + + /** + * Outputs CREATE DATABASE statement + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + return true; + } + + /** + * Outputs the content of a table in CSV format + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $sql_query SQL query for obtaining data + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + global $what, $csv_terminated, $csv_separator, $csv_enclosed, $csv_escaped; + + // Gets the data from the database + $result = $GLOBALS['dbi']->query( + $sql_query, null, PMA_DatabaseInterface::QUERY_UNBUFFERED + ); + $fields_cnt = $GLOBALS['dbi']->numFields($result); + + // If required, get fields name at the first line + if (isset($GLOBALS['csv_columns'])) { + $schema_insert = ''; + for ($i = 0; $i < $fields_cnt; $i++) { + if ($csv_enclosed == '') { + $schema_insert .= stripslashes( + $GLOBALS['dbi']->fieldName($result, $i) + ); + } else { + $schema_insert .= $csv_enclosed + . str_replace( + $csv_enclosed, + $csv_escaped . $csv_enclosed, + stripslashes($GLOBALS['dbi']->fieldName($result, $i)) + ) + . $csv_enclosed; + } + $schema_insert .= $csv_separator; + } // end for + $schema_insert = trim(substr($schema_insert, 0, -1)); + if (! PMA_exportOutputHandler($schema_insert . $csv_terminated)) { + return false; + } + } // end if + + // Format the data + while ($row = $GLOBALS['dbi']->fetchRow($result)) { + $schema_insert = ''; + for ($j = 0; $j < $fields_cnt; $j++) { + if (! isset($row[$j]) || is_null($row[$j])) { + $schema_insert .= $GLOBALS[$what . '_null']; + } elseif ($row[$j] == '0' || $row[$j] != '') { + // always enclose fields + if ($what == 'excel') { + $row[$j] = preg_replace("/\015(\012)?/", "\012", $row[$j]); + } + // remove CRLF characters within field + if (isset($GLOBALS[$what . '_removeCRLF']) + && $GLOBALS[$what . '_removeCRLF'] + ) { + $row[$j] = str_replace( + "\n", + "", + str_replace( + "\r", + "", + $row[$j] + ) + ); + } + if ($csv_enclosed == '') { + $schema_insert .= $row[$j]; + } else { + // also double the escape string if found in the data + if ($csv_escaped != $csv_enclosed) { + $schema_insert .= $csv_enclosed + . str_replace( + $csv_enclosed, + $csv_escaped . $csv_enclosed, + str_replace( + $csv_escaped, + $csv_escaped . $csv_escaped, + $row[$j] + ) + ) + . $csv_enclosed; + } else { + // avoid a problem when escape string equals enclose + $schema_insert .= $csv_enclosed + . str_replace( + $csv_enclosed, + $csv_escaped . $csv_enclosed, + $row[$j] + ) + . $csv_enclosed; + } + } + } else { + $schema_insert .= ''; + } + if ($j < $fields_cnt-1) { + $schema_insert .= $csv_separator; + } + } // end for + + if (! PMA_exportOutputHandler($schema_insert . $csv_terminated)) { + return false; + } + } // end while + $GLOBALS['dbi']->freeResult($result); + + return true; + } +} +?> diff --git a/phpMyAdmin/libraries/plugins/export/ExportExcel.class.php b/phpMyAdmin/libraries/plugins/export/ExportExcel.class.php new file mode 100644 index 0000000..1bb1060 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/export/ExportExcel.class.php @@ -0,0 +1,105 @@ +setText('CSV for MS Excel'); + $exportPluginProperties->setExtension('csv'); + $exportPluginProperties->setMimeType('text/comma-separated-values'); + $exportPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $exportPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create primary items and add them to the group + $leaf = new TextPropertyItem(); + $leaf->setName('null'); + $leaf->setText(__('Replace NULL with:')); + $generalOptions->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName('removeCRLF'); + $leaf->setText( + __('Remove carriage return/line feed characters within columns') + ); + $generalOptions->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName('columns'); + $leaf->setText(__('Put columns names in the first row')); + $generalOptions->addProperty($leaf); + $leaf = new SelectPropertyItem(); + $leaf->setName('edition'); + $leaf->setValues( + array( + 'win' => 'Windows', + 'mac_excel2003' => 'Excel 2003 / Macintosh', + 'mac_excel2008' => 'Excel 2008 / Macintosh' + ) + ); + $leaf->setText(__('Excel edition:')); + $generalOptions->addProperty($leaf); + $leaf = new HiddenPropertyItem(); + $leaf->setName('structure_or_data'); + $generalOptions->addProperty($leaf); + // add the main group to the root group + $exportSpecificOptions->addProperty($generalOptions); + + // set the options for the export plugin property item + $exportPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $exportPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/export/ExportHtmlword.class.php b/phpMyAdmin/libraries/plugins/export/ExportHtmlword.class.php new file mode 100644 index 0000000..edd24aa --- /dev/null +++ b/phpMyAdmin/libraries/plugins/export/ExportHtmlword.class.php @@ -0,0 +1,647 @@ +setProperties(); + } + + /** + * Sets the export HTML-Word properties + * + * @return void + */ + protected function setProperties() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/RadioPropertyItem.class.php"; + include_once "$props/options/items/TextPropertyItem.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + + $exportPluginProperties = new ExportPluginProperties(); + $exportPluginProperties->setText('Microsoft Word 2000'); + $exportPluginProperties->setExtension('doc'); + $exportPluginProperties->setMimeType('application/vnd.ms-word'); + $exportPluginProperties->setForceFile(true); + $exportPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $exportPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup(); + $exportSpecificOptions->setName("Format Specific Options"); + + // what to dump (structure/data/both) + $dumpWhat = new OptionsPropertyMainGroup(); + $dumpWhat->setName("dump_what"); + $dumpWhat->setText(__('Dump table')); + // create primary items and add them to the group + $leaf = new RadioPropertyItem(); + $leaf->setName("structure_or_data"); + $leaf->setValues( + array( + 'structure' => __('structure'), + 'data' => __('data'), + 'structure_and_data' => __('structure and data') + ) + ); + $dumpWhat->addProperty($leaf); + // add the main group to the root group + $exportSpecificOptions->addProperty($dumpWhat); + + // data options main group + $dataOptions = new OptionsPropertyMainGroup(); + $dataOptions->setName("dump_what"); + $dataOptions->setText(__('Data dump options')); + $dataOptions->setForce('structure'); + // create primary items and add them to the group + $leaf = new TextPropertyItem(); + $leaf->setName("null"); + $leaf->setText(__('Replace NULL with:')); + $dataOptions->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName("columns"); + $leaf->setText(__('Put columns names in the first row')); + $dataOptions->addProperty($leaf); + // add the main group to the root group + $exportSpecificOptions->addProperty($dataOptions); + + // set the options for the export plugin property item + $exportPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $exportPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Outputs export header + * + * @return bool Whether it succeeded + */ + public function exportHeader () + { + global $charset_of_file; + + return PMA_exportOutputHandler( + ' + + + + + + + ' + ); + } + + /** + * Outputs export footer + * + * @return bool Whether it succeeded + */ + public function exportFooter () + { + return PMA_exportOutputHandler(''); + } + + /** + * Outputs database header + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + return PMA_exportOutputHandler( + '

    ' . __('Database') . ' ' . htmlspecialchars($db) . '

    ' + ); + } + + /** + * Outputs database footer + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBFooter ($db) + { + return true; + } + + /** + * Outputs CREATE DATABASE statement + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + return true; + } + + /** + * Outputs the content of a table in HTML-Word format + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $sql_query SQL query for obtaining data + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + global $what; + + if (! PMA_exportOutputHandler( + '

    ' + . __('Dumping data for table') . ' ' . htmlspecialchars($table) + . '

    ' + )) { + return false; + } + if (! PMA_exportOutputHandler( + '' + )) { + return false; + } + + // Gets the data from the database + $result = $GLOBALS['dbi']->query( + $sql_query, null, PMA_DatabaseInterface::QUERY_UNBUFFERED + ); + $fields_cnt = $GLOBALS['dbi']->numFields($result); + + // If required, get fields name at the first line + if (isset($GLOBALS['htmlword_columns'])) { + $schema_insert = ''; + for ($i = 0; $i < $fields_cnt; $i++) { + $schema_insert .= ''; + } // end for + $schema_insert .= ''; + if (! PMA_exportOutputHandler($schema_insert)) { + return false; + } + } // end if + + // Format the data + while ($row = $GLOBALS['dbi']->fetchRow($result)) { + $schema_insert = ''; + for ($j = 0; $j < $fields_cnt; $j++) { + if (! isset($row[$j]) || is_null($row[$j])) { + $value = $GLOBALS[$what . '_null']; + } elseif ($row[$j] == '0' || $row[$j] != '') { + $value = $row[$j]; + } else { + $value = ''; + } + $schema_insert .= ''; + } // end for + $schema_insert .= ''; + if (! PMA_exportOutputHandler($schema_insert)) { + return false; + } + } // end while + $GLOBALS['dbi']->freeResult($result); + if (! PMA_exportOutputHandler('
    ')) { + return false; + } + + return true; + } + + /** + * Returns a stand-in CREATE definition to resolve view dependencies + * + * @param string $db the database name + * @param string $view the view name + * @param string $crlf the end of line sequence + * + * @return string resulting definition + */ + public function getTableDefStandIn($db, $view, $crlf) + { + $schema_insert = '' + . '' + . '' + . '' + . '' + . '' + . ''; + + /** + * Get the unique keys in the view + */ + $unique_keys = array(); + $keys = $GLOBALS['dbi']->getTableIndexes($db, $view); + foreach ($keys as $key) { + if ($key['Non_unique'] == 0) { + $unique_keys[] = $key['Column_name']; + } + } + + $columns = $GLOBALS['dbi']->getColumns($db, $view); + foreach ($columns as $column) { + $schema_insert .= $this->formatOneColumnDefinition( + $column, + $unique_keys + ); + $schema_insert .= ''; + } + + $schema_insert .= '
    '; + return $schema_insert; + } + + /** + * Returns $table's CREATE definition + * + * @param string $db the database name + * @param string $table the table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param bool $do_relation whether to include relation comments + * @param bool $do_comments whether to include the pmadb-style column + * comments as comments in the structure; + * this is deprecated but the parameter is + * left here because export.php calls + * PMA_exportStructure() also for other + * export types which use this parameter + * @param bool $do_mime whether to include mime comments + * @param bool $show_dates whether to include creation/update/check dates + * @param bool $add_semicolon whether to add semicolon and end-of-line + * at the end + * @param bool $view whether we're handling a view + * + * @return string resulting schema + */ + public function getTableDef( + $db, + $table, + $crlf, + $error_url, + $do_relation, + $do_comments, + $do_mime, + $show_dates = false, + $add_semicolon = true, + $view = false + ) { + // set $cfgRelation here, because there is a chance that it's modified + // since the class initialization + global $cfgRelation; + + $schema_insert = ''; + + /** + * Gets fields properties + */ + $GLOBALS['dbi']->selectDb($db); + + // Check if we can use Relations + if ($do_relation && ! empty($cfgRelation['relation'])) { + // Find which tables are related with the current one and write it in + // an array + $res_rel = PMA_getForeigners($db, $table); + + if ($res_rel && count($res_rel) > 0) { + $have_rel = true; + } else { + $have_rel = false; + } + } else { + $have_rel = false; + } // end if + + /** + * Displays the table structure + */ + $schema_insert .= ''; + + $columns_cnt = 4; + if ($do_relation && $have_rel) { + $columns_cnt++; + } + if ($do_comments && $cfgRelation['commwork']) { + $columns_cnt++; + } + if ($do_mime && $cfgRelation['mimework']) { + $columns_cnt++; + } + + $schema_insert .= ''; + $schema_insert .= ''; + $schema_insert .= ''; + $schema_insert .= ''; + $schema_insert .= ''; + if ($do_relation && $have_rel) { + $schema_insert .= ''; + } + if ($do_comments) { + $schema_insert .= ''; + $comments = PMA_getComments($db, $table); + } + if ($do_mime && $cfgRelation['mimework']) { + $schema_insert .= ''; + $mime_map = PMA_getMIME($db, $table, true); + } + $schema_insert .= ''; + + $columns = $GLOBALS['dbi']->getColumns($db, $table); + /** + * Get the unique keys in the table + */ + $unique_keys = array(); + $keys = $GLOBALS['dbi']->getTableIndexes($db, $table); + foreach ($keys as $key) { + if ($key['Non_unique'] == 0) { + $unique_keys[] = $key['Column_name']; + } + } + foreach ($columns as $column) { + $schema_insert .= $this->formatOneColumnDefinition( + $column, + $unique_keys + ); + $field_name = $column['Field']; + + if ($do_relation && $have_rel) { + $schema_insert .= ''; + } + if ($do_comments && $cfgRelation['commwork']) { + $schema_insert .= ''; + } + if ($do_mime && $cfgRelation['mimework']) { + $schema_insert .= ''; + } + + $schema_insert .= ''; + } // end foreach + + $schema_insert .= '
    ' + . (isset($res_rel[$field_name]) + ? htmlspecialchars( + $res_rel[$field_name]['foreign_table'] + . ' (' . $res_rel[$field_name]['foreign_field'] + . ')' + ) + : '') . '' + . (isset($comments[$field_name]) + ? htmlspecialchars($comments[$field_name]) + : '') . '' + . (isset($mime_map[$field_name]) ? + htmlspecialchars( + str_replace('_', '/', $mime_map[$field_name]['mimetype']) + ) + : '') . '
    '; + return $schema_insert; + } + + /** + * Outputs triggers + * + * @param string $db database name + * @param string $table table name + * + * @return string Formatted triggers list + */ + protected function getTriggers($db, $table) + { + $dump = ''; + $dump .= ''; + $dump .= ''; + $dump .= ''; + $dump .= ''; + $dump .= ''; + $dump .= ''; + + $triggers = $GLOBALS['dbi']->getTriggers($db, $table); + + foreach ($triggers as $trigger) { + $dump .= ''; + $dump .= '' + . '' + . '' + . '' + . ''; + } + + $dump .= '
    '; + return $dump; + } + + /** + * Outputs table's structure + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $export_mode 'create_table', 'triggers', 'create_view', + * 'stand_in' + * @param string $export_type 'server', 'database', 'table' + * @param bool $do_relation whether to include relation comments + * @param bool $do_comments whether to include the pmadb-style column + * comments as comments in the structure; + * this is deprecated but the parameter is + * left here because export.php calls + * PMA_exportStructure() also for other + * export types which use this parameter + * @param bool $do_mime whether to include mime comments + * @param bool $dates whether to include creation/update/check dates + * + * @return bool Whether it succeeded + */ + public function exportStructure( + $db, + $table, + $crlf, + $error_url, + $export_mode, + $export_type, + $do_relation = false, + $do_comments = false, + $do_mime = false, + $dates = false + ) { + $dump = ''; + + switch($export_mode) { + case 'create_table': + $dump .= '

    ' + . __('Table structure for table') . ' ' . htmlspecialchars($table) + . '

    '; + $dump .= $this->getTableDef( + $db, $table, $crlf, $error_url, $do_relation, $do_comments, $do_mime, + $dates + ); + break; + case 'triggers': + $dump = ''; + $triggers = $GLOBALS['dbi']->getTriggers($db, $table); + if ($triggers) { + $dump .= '

    ' + . __('Triggers') . ' ' . htmlspecialchars($table) + . '

    '; + $dump .= $this->getTriggers($db, $table); + } + break; + case 'create_view': + $dump .= '

    ' + . __('Structure for view') . ' ' . htmlspecialchars($table) + . '

    '; + $dump .= $this->getTableDef( + $db, $table, $crlf, $error_url, $do_relation, $do_comments, $do_mime, + $dates, true, true + ); + break; + case 'stand_in': + $dump .= '

    ' + . __('Stand-in structure for view') . ' ' . htmlspecialchars($table) + . '

    '; + // export a stand-in definition to resolve view dependencies + $dump .= $this->getTableDefStandIn($db, $table, $crlf); + } // end switch + + return PMA_exportOutputHandler($dump); + } + + /** + * Formats the definition for one column + * + * @param array $column info about this column + * @param array $unique_keys unique keys of the table + * + * @return string Formatted column definition + */ + protected function formatOneColumnDefinition( + $column, $unique_keys + ) { + $definition = ''; + + $extracted_columnspec + = PMA_Util::extractColumnSpec($column['Type']); + + $type = htmlspecialchars($extracted_columnspec['print_type']); + if (empty($type)) { + $type = ' '; + } + + if (! isset($column['Default'])) { + if ($column['Null'] != 'NO') { + $column['Default'] = 'NULL'; + } + } + + $fmt_pre = ''; + $fmt_post = ''; + if (in_array($column['Field'], $unique_keys)) { + $fmt_pre = '' . $fmt_pre; + $fmt_post = $fmt_post . ''; + } + if ($column['Key'] == 'PRI') { + $fmt_pre = '' . $fmt_pre; + $fmt_post = $fmt_post . ''; + } + $definition .= '' . $fmt_pre + . htmlspecialchars($column['Field']) . $fmt_post . ''; + $definition .= '' . htmlspecialchars($type) + . ''; + $definition .= '' + . (($column['Null'] == '' || $column['Null'] == 'NO') + ? __('No') + : __('Yes')) + . ''; + $definition .= '' + . htmlspecialchars( + isset($column['Default']) + ? $column['Default'] + : '' + ) + . ''; + + return $definition; + } +} +?> diff --git a/phpMyAdmin/libraries/plugins/export/ExportJson.class.php b/phpMyAdmin/libraries/plugins/export/ExportJson.class.php new file mode 100644 index 0000000..59bc477 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/export/ExportJson.class.php @@ -0,0 +1,210 @@ +setProperties(); + } + + /** + * Sets the export JSON properties + * + * @return void + */ + protected function setProperties() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/HiddenPropertyItem.class.php"; + + $exportPluginProperties = new ExportPluginProperties(); + $exportPluginProperties->setText('JSON'); + $exportPluginProperties->setExtension('json'); + $exportPluginProperties->setMimeType('text/plain'); + $exportPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $exportPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create primary items and add them to the group + $leaf = new HiddenPropertyItem(); + $leaf->setName("structure_or_data"); + $generalOptions->addProperty($leaf); + // add the main group to the root group + $exportSpecificOptions->addProperty($generalOptions); + + // set the options for the export plugin property item + $exportPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $exportPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Outputs export header + * + * @return bool Whether it succeeded + */ + public function exportHeader () + { + PMA_exportOutputHandler( + '/**' . $GLOBALS['crlf'] + . ' Export to JSON plugin for PHPMyAdmin' . $GLOBALS['crlf'] + . ' @version 0.1' . $GLOBALS['crlf'] + . ' */' . $GLOBALS['crlf'] . $GLOBALS['crlf'] + ); + return true; + } + + /** + * Outputs export footer + * + * @return bool Whether it succeeded + */ + public function exportFooter () + { + return true; + } + + /** + * Outputs database header + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + PMA_exportOutputHandler('// Database \'' . $db . '\'' . $GLOBALS['crlf']); + return true; + } + + /** + * Outputs database footer + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBFooter ($db) + { + return true; + } + + /** + * Outputs CREATE DATABASE statement + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + return true; + } + + /** + * Outputs the content of a table in JSON format + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $sql_query SQL query for obtaining data + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + $result = $GLOBALS['dbi']->query( + $sql_query, null, PMA_DatabaseInterface::QUERY_UNBUFFERED + ); + $columns_cnt = $GLOBALS['dbi']->numFields($result); + + for ($i = 0; $i < $columns_cnt; $i++) { + $columns[$i] = stripslashes($GLOBALS['dbi']->fieldName($result, $i)); + } + unset($i); + + $buffer = ''; + $record_cnt = 0; + while ($record = $GLOBALS['dbi']->fetchRow($result)) { + + $record_cnt++; + + // Output table name as comment if this is the first record of the table + if ($record_cnt == 1) { + $buffer = '// ' . $db . '.' . $table . $crlf . $crlf; + $buffer .= '['; + } else { + $buffer = ', '; + } + + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + + $data = array(); + + for ($i = 0; $i < $columns_cnt; $i++) { + $data[$columns[$i]] = $record[$i]; + } + + if (! PMA_exportOutputHandler(json_encode($data))) { + return false; + } + } + + if ($record_cnt) { + if (! PMA_exportOutputHandler(']')) { + return false; + } + } + + $GLOBALS['dbi']->freeResult($result); + return true; + } +} +?> diff --git a/phpMyAdmin/libraries/plugins/export/ExportLatex.class.php b/phpMyAdmin/libraries/plugins/export/ExportLatex.class.php new file mode 100644 index 0000000..dbd55df --- /dev/null +++ b/phpMyAdmin/libraries/plugins/export/ExportLatex.class.php @@ -0,0 +1,657 @@ +initSpecificVariables(); + + $this->setProperties(); + } + + /** + * Initialize the local variables that are used for export Latex + * + * @return void + */ + protected function initSpecificVariables() + { + /* Messages used in default captions */ + $GLOBALS['strLatexContent'] = __('Content of table @TABLE@'); + $GLOBALS['strLatexContinued'] = __('(continued)'); + $GLOBALS['strLatexStructure'] = __('Structure of table @TABLE@'); + } + + /** + * Sets the export Latex properties + * + * @return void + */ + protected function setProperties() + { + global $plugin_param; + $hide_structure = false; + if ($plugin_param['export_type'] == 'table' + && ! $plugin_param['single_table'] + ) { + $hide_structure = true; + } + + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + include_once "$props/options/items/RadioPropertyItem.class.php"; + include_once "$props/options/items/TextPropertyItem.class.php"; + + $exportPluginProperties = new ExportPluginProperties(); + $exportPluginProperties->setText('LaTeX'); + $exportPluginProperties->setExtension('tex'); + $exportPluginProperties->setMimeType('application/x-tex'); + $exportPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $exportPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create primary items and add them to the group + $leaf = new BoolPropertyItem(); + $leaf->setName("caption"); + $leaf->setText(__('Include table caption')); + $generalOptions->addProperty($leaf); + // add the main group to the root group + $exportSpecificOptions->addProperty($generalOptions); + + // what to dump (structure/data/both) main group + $dumpWhat = new OptionsPropertyMainGroup(); + $dumpWhat->setName("dump_what"); + $dumpWhat->setText(__('Dump table')); + // create primary items and add them to the group + $leaf = new RadioPropertyItem(); + $leaf->setName("structure_or_data"); + $leaf->setValues( + array( + 'structure' => __('structure'), + 'data' => __('data'), + 'structure_and_data' => __('structure and data') + ) + ); + $dumpWhat->addProperty($leaf); + // add the main group to the root group + $exportSpecificOptions->addProperty($dumpWhat); + + // structure options main group + if (! $hide_structure) { + $structureOptions = new OptionsPropertyMainGroup(); + $structureOptions->setName("structure"); + $structureOptions->setText(__('Object creation options')); + $structureOptions->setForce('data'); + // create primary items and add them to the group + $leaf = new TextPropertyItem(); + $leaf->setName("structure_caption"); + $leaf->setText(__('Table caption:')); + $leaf->setDoc('faq6-27'); + $structureOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("structure_continued_caption"); + $leaf->setText(__('Table caption (continued):')); + $leaf->setDoc('faq6-27'); + $structureOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("structure_label"); + $leaf->setText(__('Label key:')); + $leaf->setDoc('faq6-27'); + $structureOptions->addProperty($leaf); + if (! empty($GLOBALS['cfgRelation']['relation'])) { + $leaf = new BoolPropertyItem(); + $leaf->setName("relation"); + $leaf->setText(__('Display foreign key relationships')); + $structureOptions->addProperty($leaf); + } + $leaf = new BoolPropertyItem(); + $leaf->setName("comments"); + $leaf->setText(__('Display comments')); + $structureOptions->addProperty($leaf); + if (! empty($GLOBALS['cfgRelation']['mimework'])) { + $leaf = new BoolPropertyItem(); + $leaf->setName("mime"); + $leaf->setText(__('Display MIME types')); + $structureOptions->addProperty($leaf); + } + // add the main group to the root group + $exportSpecificOptions->addProperty($structureOptions); + } + + // data options main group + $dataOptions = new OptionsPropertyMainGroup(); + $dataOptions->setName("data"); + $dataOptions->setText(__('Data dump options')); + $dataOptions->setForce('structure'); + // create primary items and add them to the group + $leaf = new BoolPropertyItem(); + $leaf->setName("columns"); + $leaf->setText(__('Put columns names in the first row:')); + $dataOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("data_caption"); + $leaf->setText(__('Table caption:')); + $leaf->setDoc('faq6-27'); + $dataOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("data_continued_caption"); + $leaf->setText(__('Table caption (continued):')); + $leaf->setDoc('faq6-27'); + $dataOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("data_label"); + $leaf->setText(__('Label key:')); + $leaf->setDoc('faq6-27'); + $dataOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName('null'); + $leaf->setText(__('Replace NULL with:')); + $dataOptions->addProperty($leaf); + // add the main group to the root group + $exportSpecificOptions->addProperty($dataOptions); + + // set the options for the export plugin property item + $exportPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $exportPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Outputs export header + * + * @return bool Whether it succeeded + */ + public function exportHeader () + { + global $crlf; + global $cfg; + + $head = '% phpMyAdmin LaTeX Dump' . $crlf + . '% version ' . PMA_VERSION . $crlf + . '% http://www.phpmyadmin.net' . $crlf + . '%' . $crlf + . '% ' . __('Host:') . ' ' . $cfg['Server']['host']; + if (! empty($cfg['Server']['port'])) { + $head .= ':' . $cfg['Server']['port']; + } + $head .= $crlf + . '% ' . __('Generation Time:') . ' ' + . PMA_Util::localisedDate() . $crlf + . '% ' . __('Server version:') . ' ' . PMA_MYSQL_STR_VERSION . $crlf + . '% ' . __('PHP Version:') . ' ' . phpversion() . $crlf; + return PMA_exportOutputHandler($head); + } + + /** + * Outputs export footer + * + * @return bool Whether it succeeded + */ + public function exportFooter () + { + return true; + } + + /** + * Outputs database header + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + global $crlf; + $head = '% ' . $crlf + . '% ' . __('Database:') . ' ' . '\'' . $db . '\'' . $crlf + . '% ' . $crlf; + return PMA_exportOutputHandler($head); + } + + /** + * Outputs database footer + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBFooter ($db) + { + return true; + } + + /** + * Outputs CREATE DATABASE statement + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + return true; + } + + /** + * Outputs the content of a table in JSON format + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $sql_query SQL query for obtaining data + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + $result = $GLOBALS['dbi']->tryQuery( + $sql_query, null, PMA_DatabaseInterface::QUERY_UNBUFFERED + ); + + $columns_cnt = $GLOBALS['dbi']->numFields($result); + for ($i = 0; $i < $columns_cnt; $i++) { + $columns[$i] = $GLOBALS['dbi']->fieldName($result, $i); + } + unset($i); + + $buffer = $crlf . '%' . $crlf . '% ' . __('Data:') . ' ' . $table + . $crlf . '%' . $crlf . ' \\begin{longtable}{|'; + + for ($index = 0; $index < $columns_cnt; $index++) { + $buffer .= 'l|'; + } + $buffer .= '} ' . $crlf ; + + $buffer .= ' \\hline \\endhead \\hline \\endfoot \\hline ' . $crlf; + if (isset($GLOBALS['latex_caption'])) { + $buffer .= ' \\caption{' + . PMA_Util::expandUserString( + $GLOBALS['latex_data_caption'], + array( + 'texEscape', + get_class($this), + 'libraries/plugins/export/' . get_class($this) . ".class.php" + ), + array('table' => $table, 'database' => $db) + ) + . '} \\label{' + . PMA_Util::expandUserString( + $GLOBALS['latex_data_label'], + null, + array('table' => $table, 'database' => $db) + ) + . '} \\\\'; + } + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + + // show column names + if (isset($GLOBALS['latex_columns'])) { + $buffer = '\\hline '; + for ($i = 0; $i < $columns_cnt; $i++) { + $buffer .= '\\multicolumn{1}{|c|}{\\textbf{' + . self::texEscape(stripslashes($columns[$i])) . '}} & '; + } + + $buffer = substr($buffer, 0, -2) . '\\\\ \\hline \hline '; + if (! PMA_exportOutputHandler($buffer . ' \\endfirsthead ' . $crlf)) { + return false; + } + if (isset($GLOBALS['latex_caption'])) { + if (! PMA_exportOutputHandler( + '\\caption{' + . PMA_Util::expandUserString( + $GLOBALS['latex_data_continued_caption'], + array( + 'texEscape', + get_class($this), + 'libraries/plugins/export/' + . get_class($this) . ".class.php" + ), + array('table' => $table, 'database' => $db) + ) + . '} \\\\ ' + )) { + return false; + } + } + if (! PMA_exportOutputHandler($buffer . '\\endhead \\endfoot' . $crlf)) { + return false; + } + } else { + if (! PMA_exportOutputHandler('\\\\ \hline')) { + return false; + } + } + + // print the whole table + while ($record = $GLOBALS['dbi']->fetchAssoc($result)) { + $buffer = ''; + // print each row + for ($i = 0; $i < $columns_cnt; $i++) { + if ((! function_exists('is_null') + || ! is_null($record[$columns[$i]])) + && isset($record[$columns[$i]]) + ) { + $column_value = self::texEscape( + stripslashes($record[$columns[$i]]) + ); + } else { + $column_value = $GLOBALS['latex_null']; + } + + // last column ... no need for & character + if ($i == ($columns_cnt - 1)) { + $buffer .= $column_value; + } else { + $buffer .= $column_value . " & "; + } + } + $buffer .= ' \\\\ \\hline ' . $crlf; + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + } + + $buffer = ' \\end{longtable}' . $crlf; + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + + $GLOBALS['dbi']->freeResult($result); + return true; + } // end getTableLaTeX + + /** + * Outputs table's structure + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $export_mode 'create_table', 'triggers', 'create_view', + * 'stand_in' + * @param string $export_type 'server', 'database', 'table' + * @param bool $do_relation whether to include relation comments + * @param bool $do_comments whether to include the pmadb-style column + * comments as comments in the structure; + * this is deprecated but the parameter is + * left here because export.php calls + * exportStructure() also for other + * export types which use this parameter + * @param bool $do_mime whether to include mime comments + * @param bool $dates whether to include creation/update/check dates + * + * @return bool Whether it succeeded + */ + public function exportStructure( + $db, + $table, + $crlf, + $error_url, + $export_mode, + $export_type, + $do_relation = false, + $do_comments = false, + $do_mime = false, + $dates = false + ) { + global $cfgRelation; + + /* We do not export triggers */ + if ($export_mode == 'triggers') { + return true; + } + + /** + * Get the unique keys in the table + */ + $unique_keys = array(); + $keys = $GLOBALS['dbi']->getTableIndexes($db, $table); + foreach ($keys as $key) { + if ($key['Non_unique'] == 0) { + $unique_keys[] = $key['Column_name']; + } + } + + /** + * Gets fields properties + */ + $GLOBALS['dbi']->selectDb($db); + + // Check if we can use Relations + if ($do_relation && ! empty($cfgRelation['relation'])) { + // Find which tables are related with the current one and write it in + // an array + $res_rel = PMA_getForeigners($db, $table); + + if ($res_rel && count($res_rel) > 0) { + $have_rel = true; + } else { + $have_rel = false; + } + } else { + $have_rel = false; + } // end if + + /** + * Displays the table structure + */ + $buffer = $crlf . '%' . $crlf . '% ' . __('Structure:') . ' ' . $table + . $crlf . '%' . $crlf . ' \\begin{longtable}{'; + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + + $columns_cnt = 4; + $alignment = '|l|c|c|c|'; + if ($do_relation && $have_rel) { + $columns_cnt++; + $alignment .= 'l|'; + } + if ($do_comments) { + $columns_cnt++; + $alignment .= 'l|'; + } + if ($do_mime && $cfgRelation['mimework']) { + $columns_cnt++; + $alignment .='l|'; + } + $buffer = $alignment . '} ' . $crlf ; + + $header = ' \\hline '; + $header .= '\\multicolumn{1}{|c|}{\\textbf{' . __('Column') + . '}} & \\multicolumn{1}{|c|}{\\textbf{' . __('Type') + . '}} & \\multicolumn{1}{|c|}{\\textbf{' . __('Null') + . '}} & \\multicolumn{1}{|c|}{\\textbf{' . __('Default') . '}}'; + if ($do_relation && $have_rel) { + $header .= ' & \\multicolumn{1}{|c|}{\\textbf{' . __('Links to') . '}}'; + } + if ($do_comments) { + $header .= ' & \\multicolumn{1}{|c|}{\\textbf{' . __('Comments') . '}}'; + $comments = PMA_getComments($db, $table); + } + if ($do_mime && $cfgRelation['mimework']) { + $header .= ' & \\multicolumn{1}{|c|}{\\textbf{MIME}}'; + $mime_map = PMA_getMIME($db, $table, true); + } + + // Table caption for first page and label + if (isset($GLOBALS['latex_caption'])) { + $buffer .= ' \\caption{' + . PMA_Util::expandUserString( + $GLOBALS['latex_structure_caption'], + array( + 'texEscape', + get_class($this), + 'libraries/plugins/export/' . get_class($this) . ".class.php" + ), + array('table' => $table, 'database' => $db) + ) + . '} \\label{' + . PMA_Util::expandUserString( + $GLOBALS['latex_structure_label'], + null, + array('table' => $table, 'database' => $db) + ) + . '} \\\\' . $crlf; + } + $buffer .= $header . ' \\\\ \\hline \\hline' . $crlf + . '\\endfirsthead' . $crlf; + // Table caption on next pages + if (isset($GLOBALS['latex_caption'])) { + $buffer .= ' \\caption{' + . PMA_Util::expandUserString( + $GLOBALS['latex_structure_continued_caption'], + array( + 'texEscape', + get_class($this), + 'libraries/plugins/export/' . get_class($this) . ".class.php" + ), + array('table' => $table, 'database' => $db) + ) + . '} \\\\ ' . $crlf; + } + $buffer .= $header . ' \\\\ \\hline \\hline \\endhead \\endfoot ' . $crlf; + + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + + $fields = $GLOBALS['dbi']->getColumns($db, $table); + foreach ($fields as $row) { + $extracted_columnspec + = PMA_Util::extractColumnSpec( + $row['Type'] + ); + $type = $extracted_columnspec['print_type']; + if (empty($type)) { + $type = ' '; + } + + if (! isset($row['Default'])) { + if ($row['Null'] != 'NO') { + $row['Default'] = 'NULL'; + } + } + + $field_name = $row['Field']; + + $local_buffer = $field_name . "\000" . $type . "\000" + . (($row['Null'] == '' || $row['Null'] == 'NO') + ? __('No') : __('Yes')) + . "\000" . (isset($row['Default']) ? $row['Default'] : ''); + + if ($do_relation && $have_rel) { + $local_buffer .= "\000"; + if (isset($res_rel[$field_name])) { + $local_buffer .= $res_rel[$field_name]['foreign_table'] . ' (' + . $res_rel[$field_name]['foreign_field'] . ')'; + } + } + if ($do_comments && $cfgRelation['commwork']) { + $local_buffer .= "\000"; + if (isset($comments[$field_name])) { + $local_buffer .= $comments[$field_name]; + } + } + if ($do_mime && $cfgRelation['mimework']) { + $local_buffer .= "\000"; + if (isset($mime_map[$field_name])) { + $local_buffer .= str_replace( + '_', + '/', + $mime_map[$field_name]['mimetype'] + ); + } + } + $local_buffer = self::texEscape($local_buffer); + if ($row['Key']=='PRI') { + $pos=strpos($local_buffer, "\000"); + $local_buffer = '\\textit{' + . substr($local_buffer, 0, $pos) + . '}' . substr($local_buffer, $pos); + } + if (in_array($field_name, $unique_keys)) { + $pos=strpos($local_buffer, "\000"); + $local_buffer = '\\textbf{' + . substr($local_buffer, 0, $pos) + . '}' . substr($local_buffer, $pos); + } + $buffer = str_replace("\000", ' & ', $local_buffer); + $buffer .= ' \\\\ \\hline ' . $crlf; + + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + } // end while + + $buffer = ' \\end{longtable}' . $crlf; + return PMA_exportOutputHandler($buffer); + } // end of the 'exportStructure' method + + /** + * Escapes some special characters for use in TeX/LaTeX + * + * @param string $string the string to convert + * + * @return string the converted string with escape codes + */ + public static function texEscape($string) + { + $escape = array('$', '%', '{', '}', '&', '#', '_', '^'); + $cnt_escape = count($escape); + for ($k = 0; $k < $cnt_escape; $k++) { + $string = str_replace($escape[$k], '\\' . $escape[$k], $string); + } + return $string; + } +} +?> diff --git a/phpMyAdmin/libraries/plugins/export/ExportMediawiki.class.php b/phpMyAdmin/libraries/plugins/export/ExportMediawiki.class.php new file mode 100644 index 0000000..7038144 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/export/ExportMediawiki.class.php @@ -0,0 +1,366 @@ +setProperties(); + } + + /** + * Sets the export MediaWiki properties + * + * @return void + */ + protected function setProperties() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/groups/OptionsPropertySubgroup.class.php"; + include_once "$props/options/items/MessageOnlyPropertyItem.class.php"; + include_once "$props/options/items/RadioPropertyItem.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + + $exportPluginProperties = new ExportPluginProperties(); + $exportPluginProperties->setText('MediaWiki Table'); + $exportPluginProperties->setExtension('mediawiki'); + $exportPluginProperties->setMimeType('text/plain'); + $exportPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $exportPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + $generalOptions->setText(__('Dump table')); + + // what to dump (structure/data/both) + $subgroup = new OptionsPropertySubgroup(); + $subgroup->setName("dump_table"); + $subgroup->setText("Dump table"); + $leaf = new RadioPropertyItem(); + $leaf->setName('structure_or_data'); + $leaf->setValues( + array( + 'structure' => __('structure'), + 'data' => __('data'), + 'structure_and_data' => __('structure and data') + ) + ); + $subgroup->setSubgroupHeader($leaf); + $generalOptions->addProperty($subgroup); + + // export table name + $leaf = new BoolPropertyItem(); + $leaf->setName("caption"); + $leaf->setText(__('Export table names')); + $generalOptions->addProperty($leaf); + + // export table headers + $leaf = new BoolPropertyItem(); + $leaf->setName("headers"); + $leaf->setText(__('Export table headers')); + $generalOptions->addProperty($leaf); + //add the main group to the root group + $exportSpecificOptions->addProperty($generalOptions); + + // set the options for the export plugin property item + $exportPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $exportPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Outputs export header + * + * @return bool Whether it succeeded + */ + public function exportHeader () + { + return true; + } + + /** + * Outputs export footer + * + * @return bool Whether it succeeded + */ + public function exportFooter () + { + return true; + } + + /** + * Outputs database header + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + return true; + } + + /** + * Outputs database footer + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBFooter ($db) + { + return true; + } + + /** + * Outputs CREATE DATABASE statement + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + return true; + } + + /** + * Outputs table's structure + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $export_mode 'create_table','triggers','create_view', + * 'stand_in' + * @param string $export_type 'server', 'database', 'table' + * @param bool $do_relation whether to include relation comments + * @param bool $do_comments whether to include the pmadb-style column + * comments as comments in the structure; this is + * deprecated but the parameter is left here + * because export.php calls exportStructure() + * also for other export types which use this + * parameter + * @param bool $do_mime whether to include mime comments + * @param bool $dates whether to include creation/update/check dates + * + * @return bool Whether it succeeded + */ + public function exportStructure( + $db, + $table, + $crlf, + $error_url, + $export_mode, + $export_type, + $do_relation = false, + $do_comments = false, + $do_mime = false, + $dates = false + ) { + switch($export_mode) { + case 'create_table': + $columns = $GLOBALS['dbi']->getColumns($db, $table); + $columns = array_values($columns); + $row_cnt = count($columns); + + // Print structure comment + $output = $this->_exportComment( + "Table structure for " + . PMA_Util::backquote($table) + ); + + // Begin the table construction + $output .= "{| class=\"wikitable\" style=\"text-align:center;\"" + . $this->_exportCRLF(); + + // Add the table name + if ($GLOBALS['mediawiki_caption']) { + $output .= "|+'''" . $table . "'''" . $this->_exportCRLF(); + } + + // Add the table headers + if ($GLOBALS['mediawiki_headers']) { + $output .= "|- style=\"background:#ffdead;\"" . $this->_exportCRLF(); + $output .= "! style=\"background:#ffffff\" | " + . $this->_exportCRLF(); + for ($i = 0; $i < $row_cnt; ++$i) { + $output .= " | " . $columns[$i]['Field']. $this->_exportCRLF(); + } + } + + // Add the table structure + $output .= "|-" . $this->_exportCRLF(); + $output .= "! Type" . $this->_exportCRLF(); + for ($i = 0; $i < $row_cnt; ++$i) { + $output .= " | " . $columns[$i]['Type'] . $this->_exportCRLF(); + } + + $output .= "|-" . $this->_exportCRLF(); + $output .= "! Null" . $this->_exportCRLF(); + for ($i = 0; $i < $row_cnt; ++$i) { + $output .= " | " . $columns[$i]['Null'] . $this->_exportCRLF(); + } + + $output .= "|-" . $this->_exportCRLF(); + $output .= "! Default" . $this->_exportCRLF(); + for ($i = 0; $i < $row_cnt; ++$i) { + $output .= " | " . $columns[$i]['Default'] . $this->_exportCRLF(); + } + + $output .= "|-" . $this->_exportCRLF(); + $output .= "! Extra" . $this->_exportCRLF(); + for ($i = 0; $i < $row_cnt; ++$i) { + $output .= " | " . $columns[$i]['Extra'] . $this->_exportCRLF(); + } + + $output .= "|}" . str_repeat($this->_exportCRLF(), 2); + break; + } // end switch + + return PMA_exportOutputHandler($output); + } + + /** + * Outputs the content of a table in MediaWiki format + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $sql_query SQL query for obtaining data + * + * @return bool Whether it succeeded + */ + public function exportData( + $db, + $table, + $crlf, + $error_url, + $sql_query + ) { + // Print data comment + $output = $this->_exportComment( + "Table data for ". PMA_Util::backquote($table) + ); + + // Begin the table construction + // Use the "wikitable" class for style + // Use the "sortable" class for allowing tables to be sorted by column + $output .= "{| class=\"wikitable sortable\" style=\"text-align:center;\"" + . $this->_exportCRLF(); + + // Add the table name + if ($GLOBALS['mediawiki_caption']) { + $output .= "|+'''" . $table . "'''" . $this->_exportCRLF(); + } + + // Add the table headers + if ($GLOBALS['mediawiki_headers']) { + // Get column names + $column_names = $GLOBALS['dbi']->getColumnNames($db, $table); + + // Add column names as table headers + if ( ! is_null($column_names) ) { + // Use '|-' for separating rows + $output .= "|-" . $this->_exportCRLF(); + + // Use '!' for separating table headers + foreach ($column_names as $column) { + $output .= " ! " . $column . "" . $this->_exportCRLF(); + } + } + } + + // Get the table data from the database + $result = $GLOBALS['dbi']->query( + $sql_query, null, PMA_DatabaseInterface::QUERY_UNBUFFERED + ); + $fields_cnt = $GLOBALS['dbi']->numFields($result); + + while ($row = $GLOBALS['dbi']->fetchRow($result)) { + $output .= "|-" . $this->_exportCRLF(); + + // Use '|' for separating table columns + for ($i = 0; $i < $fields_cnt; ++ $i) { + $output .= " | " . $row[$i] . "" . $this->_exportCRLF(); + } + } + + // End table construction + $output .= "|}" . str_repeat($this->_exportCRLF(), 2); + return PMA_exportOutputHandler($output); + } + + /** + * Outputs comments containing info about the exported tables + * + * @param string $text Text of comment + * + * @return string The formatted comment + */ + private function _exportComment($text = '') + { + // see http://www.mediawiki.org/wiki/Help:Formatting + $comment = $this->_exportCRLF(); + $comment .= '' . str_repeat($this->_exportCRLF(), 2); + + return $comment; + } + + /** + * Outputs CRLF + * + * @return string CRLF + */ + private function _exportCRLF() + { + // The CRLF expected by the mediawiki format is "\n" + return "\n"; + } +} +?> diff --git a/phpMyAdmin/libraries/plugins/export/ExportOds.class.php b/phpMyAdmin/libraries/plugins/export/ExportOds.class.php new file mode 100644 index 0000000..f3d40d2 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/export/ExportOds.class.php @@ -0,0 +1,336 @@ +setProperties(); + } + + /** + * Sets the export ODS properties + * + * @return void + */ + protected function setProperties() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/TextPropertyItem.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + include_once "$props/options/items/HiddenPropertyItem.class.php"; + + $exportPluginProperties = new ExportPluginProperties(); + $exportPluginProperties->setText('OpenDocument Spreadsheet'); + $exportPluginProperties->setExtension('ods'); + $exportPluginProperties->setMimeType( + 'application/vnd.oasis.opendocument.spreadsheet' + ); + $exportPluginProperties->setForceFile(true); + $exportPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $exportPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create primary items and add them to the group + $leaf = new TextPropertyItem(); + $leaf->setName("null"); + $leaf->setText(__('Replace NULL with:')); + $generalOptions->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName("columns"); + $leaf->setText(__('Put columns names in the first row')); + $generalOptions->addProperty($leaf); + $leaf = new HiddenPropertyItem(); + $leaf->setName("structure_or_data"); + $generalOptions->addProperty($leaf); + // add the main group to the root group + $exportSpecificOptions->addProperty($generalOptions); + + // set the options for the export plugin property item + $exportPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $exportPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Outputs export header + * + * @return bool Whether it succeeded + */ + public function exportHeader () + { + $GLOBALS['ods_buffer'] .= '' + . '' + . '' + . '' + . '' + . '/' + . '' + . '/' + . '' + . '' + . '' + . '' + . ':' + . '' + . ':' + . '' + . ' ' + . '' + . '' + . '' + . '' + . '/' + . '' + . '/' + . '' + . ' ' + . '' + . ':' + . '' + . ' ' + . '' + . '' + . '' + . '' + . '' + . '' + . '' + . ''; + return true; + } + + /** + * Outputs export footer + * + * @return bool Whether it succeeded + */ + public function exportFooter () + { + $GLOBALS['ods_buffer'] .= '' + . '' + . ''; + if (! PMA_exportOutputHandler( + PMA_createOpenDocument( + 'application/vnd.oasis.opendocument.spreadsheet', + $GLOBALS['ods_buffer'] + ) + )) { + return false; + } + return true; + } + + /** + * Outputs database header + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + return true; + } + + /** + * Outputs database footer + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBFooter ($db) + { + return true; + } + + /** + * Outputs CREATE DATABASE statement + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + return true; + } + + /** + * Outputs the content of a table in NHibernate format + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $sql_query SQL query for obtaining data + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + global $what; + + // Gets the data from the database + $result = $GLOBALS['dbi']->query( + $sql_query, null, PMA_DatabaseInterface::QUERY_UNBUFFERED + ); + $fields_cnt = $GLOBALS['dbi']->numFields($result); + $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result); + $field_flags = array(); + for ($j = 0; $j < $fields_cnt; $j++) { + $field_flags[$j] = $GLOBALS['dbi']->fieldFlags($result, $j); + } + + $GLOBALS['ods_buffer'] .= + ''; + + // If required, get fields name at the first line + if (isset($GLOBALS[$what . '_columns'])) { + $GLOBALS['ods_buffer'] .= ''; + for ($i = 0; $i < $fields_cnt; $i++) { + $GLOBALS['ods_buffer'] .= + '' + . '' + . htmlspecialchars( + stripslashes($GLOBALS['dbi']->fieldName($result, $i)) + ) + . '' + . ''; + } // end for + $GLOBALS['ods_buffer'] .= ''; + } // end if + + // Format the data + while ($row = $GLOBALS['dbi']->fetchRow($result)) { + $GLOBALS['ods_buffer'] .= ''; + for ($j = 0; $j < $fields_cnt; $j++) { + if (! isset($row[$j]) || is_null($row[$j])) { + $GLOBALS['ods_buffer'] .= + '' + . '' + . htmlspecialchars($GLOBALS[$what . '_null']) + . '' + . ''; + } elseif (stristr($field_flags[$j], 'BINARY') + && $fields_meta[$j]->blob + ) { + // ignore BLOB + $GLOBALS['ods_buffer'] .= + '' + . '' + . ''; + } elseif ($fields_meta[$j]->type == "date") { + $GLOBALS['ods_buffer'] .= + '' + . '' + . htmlspecialchars($row[$j]) + . '' + . ''; + } elseif ($fields_meta[$j]->type == "time") { + $GLOBALS['ods_buffer'] .= + '' + . '' + . htmlspecialchars($row[$j]) + . '' + . ''; + } elseif ($fields_meta[$j]->type == "datetime") { + $GLOBALS['ods_buffer'] .= + '' + . '' + . htmlspecialchars($row[$j]) + . '' + . ''; + } elseif (($fields_meta[$j]->numeric + && $fields_meta[$j]->type != 'timestamp' + && ! $fields_meta[$j]->blob) || $fields_meta[$j]->type == 'real' + ) { + $GLOBALS['ods_buffer'] .= + '' + . '' + . htmlspecialchars($row[$j]) + . '' + . ''; + } else { + $GLOBALS['ods_buffer'] .= + '' + . '' + . htmlspecialchars($row[$j]) + . '' + . ''; + } + } // end for + $GLOBALS['ods_buffer'] .= ''; + } // end while + $GLOBALS['dbi']->freeResult($result); + + $GLOBALS['ods_buffer'] .= ''; + + return true; + } +} +?> diff --git a/phpMyAdmin/libraries/plugins/export/ExportOdt.class.php b/phpMyAdmin/libraries/plugins/export/ExportOdt.class.php new file mode 100644 index 0000000..5df6f65 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/export/ExportOdt.class.php @@ -0,0 +1,734 @@ +setProperties(); + } + + /** + * Sets the export ODT properties + * + * @return void + */ + protected function setProperties() + { + global $plugin_param; + $hide_structure = false; + if ($plugin_param['export_type'] == 'table' + && ! $plugin_param['single_table'] + ) { + $hide_structure = true; + } + + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/TextPropertyItem.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + include_once "$props/options/items/HiddenPropertyItem.class.php"; + include_once "$props/options/items/RadioPropertyItem.class.php"; + + $exportPluginProperties = new ExportPluginProperties(); + $exportPluginProperties->setText('OpenDocument Text'); + $exportPluginProperties->setExtension('odt'); + $exportPluginProperties->setMimeType( + 'application/vnd.oasis.opendocument.text' + ); + $exportPluginProperties->setForceFile(true); + $exportPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $exportPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup(); + $exportSpecificOptions->setName("Format Specific Options"); + + // what to dump (structure/data/both) main group + $dumpWhat = new OptionsPropertyMainGroup(); + $dumpWhat->setName("general_opts"); + $dumpWhat->setText(__('Dump table')); + // create primary items and add them to the group + $leaf = new RadioPropertyItem(); + $leaf->setName("structure_or_data"); + $leaf->setValues( + array( + 'structure' => __('structure'), + 'data' => __('data'), + 'structure_and_data' => __('structure and data') + ) + ); + $dumpWhat->addProperty($leaf); + // add the main group to the root group + $exportSpecificOptions->addProperty($dumpWhat); + + + // structure options main group + if (! $hide_structure) { + $structureOptions = new OptionsPropertyMainGroup(); + $structureOptions->setName("structure"); + $structureOptions->setText(__('Object creation options')); + $structureOptions->setForce('data'); + // create primary items and add them to the group + if (! empty($GLOBALS['cfgRelation']['relation'])) { + $leaf = new BoolPropertyItem(); + $leaf->setName("relation"); + $leaf->setText(__('Display foreign key relationships')); + $structureOptions->addProperty($leaf); + } + $leaf = new BoolPropertyItem(); + $leaf->setName("comments"); + $leaf->setText(__('Display comments')); + $structureOptions->addProperty($leaf); + if (! empty($GLOBALS['cfgRelation']['mimework'])) { + $leaf = new BoolPropertyItem(); + $leaf->setName("mime"); + $leaf->setText(__('Display MIME types')); + $structureOptions->addProperty($leaf); + } + // add the main group to the root group + $exportSpecificOptions->addProperty($structureOptions); + } + + // data options main group + $dataOptions = new OptionsPropertyMainGroup(); + $dataOptions->setName("data"); + $dataOptions->setText(__('Data dump options')); + $dataOptions->setForce('structure'); + // create primary items and add them to the group + $leaf = new BoolPropertyItem(); + $leaf->setName("columns"); + $leaf->setText(__('Put columns names in the first row')); + $dataOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName('null'); + $leaf->setText(__('Replace NULL with:')); + $dataOptions->addProperty($leaf); + // add the main group to the root group + $exportSpecificOptions->addProperty($dataOptions); + + // set the options for the export plugin property item + $exportPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $exportPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Outputs export header + * + * @return bool Whether it succeeded + */ + public function exportHeader () + { + $GLOBALS['odt_buffer'] .= '' + . '' + . '' + . ''; + return true; + } + + /** + * Outputs export footer + * + * @return bool Whether it succeeded + */ + public function exportFooter () + { + $GLOBALS['odt_buffer'] .= '' + . '' + . ''; + if (! PMA_exportOutputHandler( + PMA_createOpenDocument( + 'application/vnd.oasis.opendocument.text', + $GLOBALS['odt_buffer'] + ) + )) { + return false; + } + return true; + } + + /** + * Outputs database header + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + $GLOBALS['odt_buffer'] .= + '' + . __('Database') . ' ' . htmlspecialchars($db) + . ''; + return true; + } + + /** + * Outputs database footer + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBFooter ($db) + { + return true; + } + + /** + * Outputs CREATE DATABASE statement + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + return true; + } + /** + * Outputs the content of a table in NHibernate format + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $sql_query SQL query for obtaining data + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + global $what; + + // Gets the data from the database + $result = $GLOBALS['dbi']->query( + $sql_query, null, PMA_DatabaseInterface::QUERY_UNBUFFERED + ); + $fields_cnt = $GLOBALS['dbi']->numFields($result); + $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result); + $field_flags = array(); + for ($j = 0; $j < $fields_cnt; $j++) { + $field_flags[$j] = $GLOBALS['dbi']->fieldFlags($result, $j); + } + + $GLOBALS['odt_buffer'] .= + '' + . __('Dumping data for table') . ' ' . htmlspecialchars($table) + . '' + . '' + . ''; + + // If required, get fields name at the first line + if (isset($GLOBALS[$what . '_columns'])) { + $GLOBALS['odt_buffer'] .= ''; + for ($i = 0; $i < $fields_cnt; $i++) { + $GLOBALS['odt_buffer'] .= + '' + . '' + . htmlspecialchars( + stripslashes($GLOBALS['dbi']->fieldName($result, $i)) + ) + . '' + . ''; + } // end for + $GLOBALS['odt_buffer'] .= ''; + } // end if + + // Format the data + while ($row = $GLOBALS['dbi']->fetchRow($result)) { + $GLOBALS['odt_buffer'] .= ''; + for ($j = 0; $j < $fields_cnt; $j++) { + if (! isset($row[$j]) || is_null($row[$j])) { + $GLOBALS['odt_buffer'] .= + '' + . '' + . htmlspecialchars($GLOBALS[$what . '_null']) + . '' + . ''; + } elseif (stristr($field_flags[$j], 'BINARY') + && $fields_meta[$j]->blob + ) { + // ignore BLOB + $GLOBALS['odt_buffer'] .= + '' + . '' + . ''; + } elseif ($fields_meta[$j]->numeric + && $fields_meta[$j]->type != 'timestamp' + && ! $fields_meta[$j]->blob + ) { + $GLOBALS['odt_buffer'] .= + '' + . '' + . htmlspecialchars($row[$j]) + . '' + . ''; + } else { + $GLOBALS['odt_buffer'] .= + '' + . '' + . htmlspecialchars($row[$j]) + . '' + . ''; + } + } // end for + $GLOBALS['odt_buffer'] .= ''; + } // end while + $GLOBALS['dbi']->freeResult($result); + + $GLOBALS['odt_buffer'] .= ''; + + return true; + } + + /** + * Returns a stand-in CREATE definition to resolve view dependencies + * + * @param string $db the database name + * @param string $view the view name + * @param string $crlf the end of line sequence + * + * @return bool true + */ + public function getTableDefStandIn($db, $view, $crlf) + { + /** + * Gets fields properties + */ + $GLOBALS['dbi']->selectDb($db); + + /** + * Displays the table structure + */ + $GLOBALS['odt_buffer'] .= + ''; + $columns_cnt = 4; + $GLOBALS['odt_buffer'] .= + ''; + /* Header */ + $GLOBALS['odt_buffer'] .= '' + . '' + . '' . __('Column') . '' + . '' + . '' + . '' . __('Type') . '' + . '' + . '' + . '' . __('Null') . '' + . '' + . '' + . '' . __('Default') . '' + . '' + . ''; + + $columns = $GLOBALS['dbi']->getColumns($db, $view); + foreach ($columns as $column) { + $GLOBALS['odt_buffer'] .= $this->formatOneColumnDefinition($column); + $GLOBALS['odt_buffer'] .= ''; + } // end foreach + + $GLOBALS['odt_buffer'] .= ''; + return true; + } + + /** + * Returns $table's CREATE definition + * + * @param string $db the database name + * @param string $table the table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param bool $do_relation whether to include relation comments + * @param bool $do_comments whether to include the pmadb-style column + * comments as comments in the structure; + * this is deprecated but the parameter is + * left here because export.php calls + * PMA_exportStructure() also for other + * @param bool $do_mime whether to include mime comments + * @param bool $show_dates whether to include creation/update/check dates + * @param bool $add_semicolon whether to add semicolon and end-of-line at + * the end + * @param bool $view whether we're handling a view + * + * @return bool true + */ + public function getTableDef( + $db, + $table, + $crlf, + $error_url, + $do_relation, + $do_comments, + $do_mime, + $show_dates = false, + $add_semicolon = true, + $view = false + ) { + global $cfgRelation; + + /** + * Gets fields properties + */ + $GLOBALS['dbi']->selectDb($db); + + // Check if we can use Relations + if ($do_relation && ! empty($cfgRelation['relation'])) { + // Find which tables are related with the current one and write it in + // an array + $res_rel = PMA_getForeigners($db, $table); + + if ($res_rel && count($res_rel) > 0) { + $have_rel = true; + } else { + $have_rel = false; + } + } else { + $have_rel = false; + } // end if + + /** + * Displays the table structure + */ + $GLOBALS['odt_buffer'] .= ''; + $columns_cnt = 4; + if ($do_relation && $have_rel) { + $columns_cnt++; + } + if ($do_comments) { + $columns_cnt++; + } + if ($do_mime && $cfgRelation['mimework']) { + $columns_cnt++; + } + $GLOBALS['odt_buffer'] .= ''; + /* Header */ + $GLOBALS['odt_buffer'] .= '' + . '' + . '' . __('Column') . '' + . '' + . '' + . '' . __('Type') . '' + . '' + . '' + . '' . __('Null') . '' + . '' + . '' + . '' . __('Default') . '' + . ''; + if ($do_relation && $have_rel) { + $GLOBALS['odt_buffer'] .= '' + . '' . __('Links to') . '' + . ''; + } + if ($do_comments) { + $GLOBALS['odt_buffer'] .= '' + . '' . __('Comments') . '' + . ''; + $comments = PMA_getComments($db, $table); + } + if ($do_mime && $cfgRelation['mimework']) { + $GLOBALS['odt_buffer'] .= '' + . '' . __('MIME type') . '' + . ''; + $mime_map = PMA_getMIME($db, $table, true); + } + $GLOBALS['odt_buffer'] .= ''; + + $columns = $GLOBALS['dbi']->getColumns($db, $table); + foreach ($columns as $column) { + $field_name = $column['Field']; + $GLOBALS['odt_buffer'] .= $this->formatOneColumnDefinition($column); + + if ($do_relation && $have_rel) { + if (isset($res_rel[$field_name])) { + $GLOBALS['odt_buffer'] .= + '' + . '' + . htmlspecialchars( + $res_rel[$field_name]['foreign_table'] + . ' (' . $res_rel[$field_name]['foreign_field'] . ')' + ) + . '' + . ''; + } + } + if ($do_comments) { + if (isset($comments[$field_name])) { + $GLOBALS['odt_buffer'] .= + '' + . '' + . htmlspecialchars($comments[$field_name]) + . '' + . ''; + } else { + $GLOBALS['odt_buffer'] .= + '' + . '' + . ''; + } + } + if ($do_mime && $cfgRelation['mimework']) { + if (isset($mime_map[$field_name])) { + $GLOBALS['odt_buffer'] .= + '' + . '' + . htmlspecialchars( + str_replace('_', '/', $mime_map[$field_name]['mimetype']) + ) + . '' + . ''; + } else { + $GLOBALS['odt_buffer'] .= + '' + . '' + . ''; + } + } + $GLOBALS['odt_buffer'] .= ''; + } // end foreach + + $GLOBALS['odt_buffer'] .= ''; + return true; + } // end of the '$this->getTableDef()' function + + /** + * Outputs triggers + * + * @param string $db database name + * @param string $table table name + * + * @return bool true + */ + protected function getTriggers($db, $table) + { + $GLOBALS['odt_buffer'] .= '' + . '' + . '' + . '' + . '' . __('Name') . '' + . '' + . '' + . '' . __('Time') . '' + . '' + . '' + . '' . __('Event') . '' + . '' + . '' + . '' . __('Definition') . '' + . '' + . ''; + + $triggers = $GLOBALS['dbi']->getTriggers($db, $table); + + foreach ($triggers as $trigger) { + $GLOBALS['odt_buffer'] .= ''; + $GLOBALS['odt_buffer'] .= '' + . '' + . htmlspecialchars($trigger['name']) + . '' + . ''; + $GLOBALS['odt_buffer'] .= '' + . '' + . htmlspecialchars($trigger['action_timing']) + . '' + . ''; + $GLOBALS['odt_buffer'] .= '' + . '' + . htmlspecialchars($trigger['event_manipulation']) + . '' + . ''; + $GLOBALS['odt_buffer'] .= '' + . '' + . htmlspecialchars($trigger['definition']) + . '' + . ''; + $GLOBALS['odt_buffer'] .= ''; + } + + $GLOBALS['odt_buffer'] .= ''; + return true; + } + + /** + * Outputs table's structure + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $export_mode 'create_table', 'triggers', 'create_view', + * 'stand_in' + * @param string $export_type 'server', 'database', 'table' + * @param bool $do_relation whether to include relation comments + * @param bool $do_comments whether to include the pmadb-style column + * comments as comments in the structure; + * this is deprecated but the parameter is + * left here because export.php calls + * PMA_exportStructure() also for other + * @param bool $do_mime whether to include mime comments + * @param bool $dates whether to include creation/update/check dates + * + * @return bool Whether it succeeded + */ + public function exportStructure( + $db, + $table, + $crlf, + $error_url, + $export_mode, + $export_type, + $do_relation = false, + $do_comments = false, + $do_mime = false, + $dates = false + ) { + switch($export_mode) { + case 'create_table': + $GLOBALS['odt_buffer'] .= + '' + . __('Table structure for table') . ' ' . + htmlspecialchars($table) + . ''; + $this->getTableDef( + $db, $table, $crlf, $error_url, $do_relation, $do_comments, + $do_mime, $dates + ); + break; + case 'triggers': + $triggers = $GLOBALS['dbi']->getTriggers($db, $table); + if ($triggers) { + $GLOBALS['odt_buffer'] .= + '' + . __('Triggers') . ' ' + . htmlspecialchars($table) + . ''; + $this->getTriggers($db, $table); + } + break; + case 'create_view': + $GLOBALS['odt_buffer'] .= + '' + . __('Structure for view') . ' ' + . htmlspecialchars($table) + . ''; + $this->getTableDef( + $db, $table, $crlf, $error_url, $do_relation, $do_comments, + $do_mime, $dates, true, true + ); + break; + case 'stand_in': + $GLOBALS['odt_buffer'] .= + '' + . __('Stand-in structure for view') . ' ' + . htmlspecialchars($table) + . ''; + // export a stand-in definition to resolve view dependencies + $this->getTableDefStandIn($db, $table, $crlf); + } // end switch + + return true; + } // end of the '$this->exportStructure' function + + /** + * Formats the definition for one column + * + * @param array $column info about this column + * + * @return string Formatted column definition + */ + protected function formatOneColumnDefinition($column) + { + $field_name = $column['Field']; + $definition = ''; + $definition .= '' + . '' . htmlspecialchars($field_name) . '' + . ''; + + $extracted_columnspec + = PMA_Util::extractColumnSpec($column['Type']); + $type = htmlspecialchars($extracted_columnspec['print_type']); + if (empty($type)) { + $type = ' '; + } + + $definition .= '' + . '' . htmlspecialchars($type) . '' + . ''; + if (! isset($column['Default'])) { + if ($column['Null'] != 'NO') { + $column['Default'] = 'NULL'; + } else { + $column['Default'] = ''; + } + } + $definition .= '' + . '' + . (($column['Null'] == '' || $column['Null'] == 'NO') + ? __('No') + : __('Yes')) + . '' + . ''; + $definition .= '' + . '' . htmlspecialchars($column['Default']) . '' + . ''; + return $definition; + } +} +?> diff --git a/phpMyAdmin/libraries/plugins/export/ExportPdf.class.php b/phpMyAdmin/libraries/plugins/export/ExportPdf.class.php new file mode 100644 index 0000000..ffabb96 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/export/ExportPdf.class.php @@ -0,0 +1,268 @@ +initSpecificVariables(); + + $this->setProperties(); + } + + /** + * Initialize the local variables that are used for export PDF + * + * @return void + */ + protected function initSpecificVariables() + { + $this->_setPdfReportTitle(""); + $this->_setPdf(new PMA_ExportPdf('L', 'pt', 'A3')); + } + + /** + * Sets the export PDF properties + * + * @return void + */ + protected function setProperties() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/MessageOnlyPropertyItem.class.php"; + include_once "$props/options/items/TextPropertyItem.class.php"; + include_once "$props/options/items/HiddenPropertyItem.class.php"; + + $exportPluginProperties = new ExportPluginProperties(); + $exportPluginProperties->setText('PDF'); + $exportPluginProperties->setExtension('pdf'); + $exportPluginProperties->setMimeType('application/pdf'); + $exportPluginProperties->setForceFile(true); + $exportPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $exportPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create primary items and add them to the group + $leaf = new MessageOnlyPropertyItem(); + $leaf->setName("explanation"); + $leaf->setText( + __('(Generates a report containing the data of a single table)') + ); + $generalOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("report_title"); + $leaf->setText(__('Report title:')); + $generalOptions->addProperty($leaf); + $leaf = new HiddenPropertyItem(); + $leaf->setName("structure_or_data"); + $generalOptions->addProperty($leaf); + // add the main group to the root group + $exportSpecificOptions->addProperty($generalOptions); + + // set the options for the export plugin property item + $exportPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $exportPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Outputs export header + * + * @return bool Whether it succeeded + */ + public function exportHeader () + { + $pdf_report_title = $this->_getPdfReportTitle(); + $pdf = $this->_getPdf(); + $pdf->Open(); + + $attr = array('titleFontSize' => 18, 'titleText' => $pdf_report_title); + $pdf->setAttributes($attr); + $pdf->setTopMargin(30); + + return true; + } + + /** + * Outputs export footer + * + * @return bool Whether it succeeded + */ + public function exportFooter () + { + $pdf = $this->_getPdf(); + + // instead of $pdf->Output(): + if (! PMA_exportOutputHandler($pdf->getPDFData())) { + return false; + } + + return true; + } + + /** + * Outputs database header + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + return true; + } + + /** + * Outputs database footer + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBFooter ($db) + { + return true; + } + + /** + * Outputs CREATE DATABASE statement + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + return true; + } + /** + * Outputs the content of a table in NHibernate format + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $sql_query SQL query for obtaining data + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + $pdf = $this->_getPdf(); + + $attr = array('currentDb' => $db, 'currentTable' => $table); + $pdf->setAttributes($attr); + $pdf->mysqlReport($sql_query); + + return true; + } // end of the 'PMA_exportData()' function + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the PMA_ExportPdf instance + * + * @return PMA_ExportPdf + */ + private function _getPdf() + { + return $this->_pdf; + } + + /** + * Instantiates the PMA_ExportPdf class + * + * @param string $pdf PMA_ExportPdf instance + * + * @return void + */ + private function _setPdf($pdf) + { + $this->_pdf = $pdf; + } + + /** + * Gets the PDF report title + * + * @return string + */ + private function _getPdfReportTitle() + { + return $this->_pdfReportTitle; + } + + /** + * Sets the PDF report title + * + * @param string $pdfReportTitle PDF report title + * + * @return void + */ + private function _setPdfReportTitle($pdfReportTitle) + { + $this->_pdfReportTitle = $pdfReportTitle; + } +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/export/ExportPhparray.class.php b/phpMyAdmin/libraries/plugins/export/ExportPhparray.class.php new file mode 100644 index 0000000..78d8cbe --- /dev/null +++ b/phpMyAdmin/libraries/plugins/export/ExportPhparray.class.php @@ -0,0 +1,229 @@ +setProperties(); + } + + /** + * Sets the export PHP Array properties + * + * @return void + */ + protected function setProperties() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/HiddenPropertyItem.class.php"; + + $exportPluginProperties = new ExportPluginProperties(); + $exportPluginProperties->setText('PHP array'); + $exportPluginProperties->setExtension('php'); + $exportPluginProperties->setMimeType('text/plain'); + $exportPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $exportPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create primary items and add them to the group + $leaf = new HiddenPropertyItem(); + $leaf->setName("structure_or_data"); + $generalOptions->addProperty($leaf); + // add the main group to the root group + $exportSpecificOptions->addProperty($generalOptions); + + // set the options for the export plugin property item + $exportPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $exportPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Outputs export header + * + * @return bool Whether it succeeded + */ + public function exportHeader () + { + PMA_exportOutputHandler( + 'query( + $sql_query, null, PMA_DatabaseInterface::QUERY_UNBUFFERED + ); + + $columns_cnt = $GLOBALS['dbi']->numFields($result); + for ($i = 0; $i < $columns_cnt; $i++) { + $columns[$i] = stripslashes($GLOBALS['dbi']->fieldName($result, $i)); + } + unset($i); + + // fix variable names (based on + // http://www.php.net/manual/language.variables.basics.php) + if (! preg_match( + '/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', + $table + )) { + // fix invalid characters in variable names by replacing them with + // underscores + $tablefixed = preg_replace('/[^a-zA-Z0-9_\x7f-\xff]/', '_', $table); + + // variable name must not start with a number or dash... + if (preg_match('/^[a-zA-Z_\x7f-\xff]/', $tablefixed) == false) { + $tablefixed = '_' . $tablefixed; + } + } else { + $tablefixed = $table; + } + + $buffer = ''; + $record_cnt = 0; + // Output table name as comment + $buffer .= $crlf . '// ' + . PMA_Util::backquote($db) . '.' + . PMA_Util::backquote($table) . $crlf; + $buffer .= '$' . $tablefixed . ' = array('; + + while ($record = $GLOBALS['dbi']->fetchRow($result)) { + $record_cnt++; + + if ($record_cnt == 1) { + $buffer .= $crlf . ' array('; + } else { + $buffer .= ',' . $crlf . ' array('; + } + + for ($i = 0; $i < $columns_cnt; $i++) { + $buffer .= var_export($columns[$i], true) + . " => " . var_export($record[$i], true) + . (($i + 1 >= $columns_cnt) ? '' : ','); + } + + $buffer .= ')'; + } + + $buffer .= $crlf . ');' . $crlf; + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + + $GLOBALS['dbi']->freeResult($result); + return true; + } +} +?> diff --git a/phpMyAdmin/libraries/plugins/export/ExportSql.class.php b/phpMyAdmin/libraries/plugins/export/ExportSql.class.php new file mode 100644 index 0000000..1151943 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/export/ExportSql.class.php @@ -0,0 +1,2017 @@ +setProperties(); + + // Avoids undefined variables, use NULL so isset() returns false + if (! isset($GLOBALS['sql_backquotes'])) { + $GLOBALS['sql_backquotes'] = null; + } + } + + /** + * Sets the export SQL properties + * + * @return void + */ + protected function setProperties() + { + global $plugin_param; + + $hide_sql = false; + $hide_structure = false; + if ($plugin_param['export_type'] == 'table' + && ! $plugin_param['single_table'] + ) { + $hide_structure = true; + $hide_sql = true; + } + + if (! $hide_sql) { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/groups/OptionsPropertySubgroup.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + include_once "$props/options/items/MessageOnlyPropertyItem.class.php"; + include_once "$props/options/items/RadioPropertyItem.class.php"; + include_once "$props/options/items/SelectPropertyItem.class.php"; + include_once "$props/options/items/TextPropertyItem.class.php"; + include_once "$props/options/items/NumberPropertyItem.class.php"; + + $exportPluginProperties = new ExportPluginProperties(); + $exportPluginProperties->setText('SQL'); + $exportPluginProperties->setExtension('sql'); + $exportPluginProperties->setMimeType('text/x-sql'); + $exportPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $exportPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + + // comments + $subgroup = new OptionsPropertySubgroup(); + $subgroup->setName("include_comments"); + $leaf = new BoolPropertyItem(); + $leaf->setName('include_comments'); + $leaf->setText( + __( + 'Display comments (includes info such as export' + . ' timestamp, PHP version, and server version)' + ) + ); + $subgroup->setSubgroupHeader($leaf); + + $leaf = new TextPropertyItem(); + $leaf->setName('header_comment'); + $leaf->setText( + __('Additional custom header comment (\n splits lines):') + ); + $subgroup->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName('dates'); + $leaf->setText( + __( + 'Include a timestamp of when databases were created, last' + . ' updated, and last checked' + ) + ); + $subgroup->addProperty($leaf); + if (! empty($GLOBALS['cfgRelation']['relation'])) { + $leaf = new BoolPropertyItem(); + $leaf->setName('relation'); + $leaf->setText(__('Display foreign key relationships')); + $subgroup->addProperty($leaf); + } + if (! empty($GLOBALS['cfgRelation']['mimework'])) { + $leaf = new BoolPropertyItem(); + $leaf->setName('mime'); + $leaf->setText(__('Display MIME types')); + $subgroup->addProperty($leaf); + } + $generalOptions->addProperty($subgroup); + + // enclose in a transaction + $leaf = new BoolPropertyItem(); + $leaf->setName("use_transaction"); + $leaf->setText(__('Enclose export in a transaction')); + $leaf->setDoc( + array( + 'programs', + 'mysqldump', + 'option_mysqldump_single-transaction' + ) + ); + $generalOptions->addProperty($leaf); + + // disable foreign key checks + $leaf = new BoolPropertyItem(); + $leaf->setName("disable_fk"); + $leaf->setText(__('Disable foreign key checks')); + $leaf->setDoc( + array( + 'manual_MySQL_Database_Administration', + 'server-system-variables', + 'sysvar_foreign_key_checks' + ) + ); + $generalOptions->addProperty($leaf); + + // export views as tables + $leaf = new BoolPropertyItem(); + $leaf->setName("views_as_tables"); + $leaf->setText(__('Export views as tables')); + $generalOptions->addProperty($leaf); + + // compatibility maximization + $compats = $GLOBALS['dbi']->getCompatibilities(); + if (count($compats) > 0) { + $values = array(); + foreach ($compats as $val) { + $values[$val] = $val; + } + + $leaf = new SelectPropertyItem(); + $leaf->setName("compatibility"); + $leaf->setText( + __( + 'Database system or older MySQL server to maximize output' + . ' compatibility with:' + ) + ); + $leaf->setValues($values); + $leaf->setDoc( + array( + 'manual_MySQL_Database_Administration', + 'Server_SQL_mode' + ) + ); + $generalOptions->addProperty($leaf); + + unset($values); + } + + // server export options + if ($plugin_param['export_type'] == 'server') { + $leaf = new BoolPropertyItem(); + $leaf->setName("drop_database"); + $leaf->setText( + sprintf(__('Add %s statement'), 'DROP DATABASE') + ); + $generalOptions->addProperty($leaf); + } + + // what to dump (structure/data/both) + $subgroup = new OptionsPropertySubgroup(); + $subgroup->setName("dump_table"); + $subgroup->setText("Dump table"); + $leaf = new RadioPropertyItem(); + $leaf->setName('structure_or_data'); + $leaf->setValues( + array( + 'structure' => __('structure'), + 'data' => __('data'), + 'structure_and_data' => __('structure and data') + ) + ); + $subgroup->setSubgroupHeader($leaf); + $generalOptions->addProperty($subgroup); + + // add the main group to the root group + $exportSpecificOptions->addProperty($generalOptions); + + + // structure options main group + if (! $hide_structure) { + $structureOptions = new OptionsPropertyMainGroup(); + $structureOptions->setName("structure"); + $structureOptions->setText(__('Object creation options')); + $structureOptions->setForce('data'); + + // begin SQL Statements + $subgroup = new OptionsPropertySubgroup(); + $leaf = new MessageOnlyPropertyItem(); + $leaf->setName('add_statements'); + $leaf->setText(__('Add statements:')); + $subgroup->setSubgroupHeader($leaf); + + if ($plugin_param['export_type'] != 'table') { + $leaf = new BoolPropertyItem(); + $leaf->setName('create_database'); + $create_clause = 'CREATE DATABASE / USE'; + $leaf->setText(sprintf(__('Add %s statement'), $create_clause)); + $subgroup->addProperty($leaf); + } + + if ($plugin_param['export_type'] == 'table') { + if (PMA_Table::isView($GLOBALS['db'], $GLOBALS['table'])) { + $drop_clause = 'DROP VIEW'; + } else { + $drop_clause = 'DROP TABLE'; + } + } else { + if (PMA_DRIZZLE) { + $drop_clause = 'DROP TABLE'; + } else { + $drop_clause = 'DROP TABLE / VIEW / PROCEDURE' + . ' / FUNCTION'; + if (PMA_MYSQL_INT_VERSION > 50100) { + $drop_clause .= ' / EVENT'; + } + } + } + $leaf = new BoolPropertyItem(); + $leaf->setName('drop_table'); + $leaf->setText(sprintf(__('Add %s statement'), $drop_clause)); + $subgroup->addProperty($leaf); + // Drizzle doesn't support procedures and functions + if (! PMA_DRIZZLE) { + $leaf = new BoolPropertyItem(); + $leaf->setName('procedure_function'); + $leaf->setText( + sprintf( + __('Add %s statement'), + 'CREATE PROCEDURE / FUNCTION' + . (PMA_MYSQL_INT_VERSION > 50100 + ? ' / EVENT' : '') + ) + ); + $subgroup->addProperty($leaf); + } + + // begin CREATE TABLE statements + $subgroup_create_table = new OptionsPropertySubgroup(); + $leaf = new BoolPropertyItem(); + $leaf->setName('create_table_statements'); + $leaf->setText(__('CREATE TABLE options:')); + $subgroup_create_table->setSubgroupHeader($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName('if_not_exists'); + $leaf->setText('IF NOT EXISTS'); + $subgroup_create_table->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName('auto_increment'); + $leaf->setText('AUTO_INCREMENT'); + $subgroup_create_table->addProperty($leaf); + $subgroup->addProperty($subgroup_create_table); + $structureOptions->addProperty($subgroup); + + $leaf = new BoolPropertyItem(); + $leaf->setName("backquotes"); + $leaf->setText( + __( + 'Enclose table and column names with backquotes ' + . '(Protects column and table names formed with' + . ' special characters or keywords)' + ) + ); + + $structureOptions->addProperty($leaf); + + // add the main group to the root group + $exportSpecificOptions->addProperty($structureOptions); + } + + + // begin Data options + $dataOptions = new OptionsPropertyMainGroup(); + $dataOptions->setName("data"); + $dataOptions->setText(__('Data creation options')); + $dataOptions->setForce('structure'); + $leaf = new BoolPropertyItem(); + $leaf->setName("truncate"); + $leaf->setText(__('Truncate table before insert')); + $dataOptions->addProperty($leaf); + + // begin SQL Statements + $subgroup = new OptionsPropertySubgroup(); + $leaf = new MessageOnlyPropertyItem(); + $leaf->setText(__('Instead of INSERT statements, use:')); + $subgroup->setSubgroupHeader($leaf); + // Not supported in Drizzle + if (! PMA_DRIZZLE) { + $leaf = new BoolPropertyItem(); + $leaf->setName("delayed"); + $leaf->setText(__('INSERT DELAYED statements')); + $leaf->setDoc( + array( + 'manual_MySQL_Database_Administration', + 'insert_delayed' + ) + ); + $subgroup->addProperty($leaf); + } + $leaf = new BoolPropertyItem(); + $leaf->setName("ignore"); + $leaf->setText(__('INSERT IGNORE statements')); + $leaf->setDoc( + array( + 'manual_MySQL_Database_Administration', + 'insert' + ) + ); + $subgroup->addProperty($leaf); + $dataOptions->addProperty($subgroup); + + // Function to use when dumping dat + $leaf = new SelectPropertyItem(); + $leaf->setName("type"); + $leaf->setText(__('Function to use when dumping data:')); + $leaf->setValues( + array( + 'INSERT' => 'INSERT', + 'UPDATE' => 'UPDATE', + 'REPLACE' => 'REPLACE' + ) + ); + $dataOptions->addProperty($leaf); + + /* Syntax to use when inserting data */ + $subgroup = new OptionsPropertySubgroup(); + $leaf = new MessageOnlyPropertyItem(); + $leaf->setText(__('Syntax to use when inserting data:')); + $subgroup->setSubgroupHeader($leaf); + $leaf = new RadioPropertyItem(); + $leaf->setName("insert_syntax"); + $leaf->setText(__('INSERT IGNORE statements')); + $leaf->setValues( + array( + 'complete' => __( + 'include column names in every INSERT statement' + . '
          Example: INSERT INTO' + . ' tbl_name (col_A,col_B,col_C) VALUES (1,2,3)' + ), + 'extended' => __( + 'insert multiple rows in every INSERT statement' + . '
          Example: INSERT INTO' + . ' tbl_name VALUES (1,2,3), (4,5,6), (7,8,9)' + ), + 'both' => __( + 'both of the above
          Example:' + . ' INSERT INTO tbl_name (col_A,col_B) VALUES (1,2,3),' + . ' (4,5,6), (7,8,9)' + ), + 'none' => __( + 'neither of the above
          Example:' + . ' INSERT INTO tbl_name VALUES (1,2,3)' + ) + ) + ); + $subgroup->addProperty($leaf); + $dataOptions->addProperty($subgroup); + + // Max length of query + $leaf = new NumberPropertyItem(); + $leaf->setName("max_query_size"); + $leaf->setText(__('Maximal length of created query')); + $dataOptions->addProperty($leaf); + + // Dump binary columns in hexadecimal + $leaf = new BoolPropertyItem(); + $leaf->setName("hex_for_blob"); + $leaf->setText( + __( + 'Dump binary columns in hexadecimal notation' + . ' (for example, "abc" becomes 0x616263)' + ) + ); + $dataOptions->addProperty($leaf); + + // Drizzle works only with UTC timezone + if (! PMA_DRIZZLE) { + // Dump time in UTC + $leaf = new BoolPropertyItem(); + $leaf->setName("utc_time"); + $leaf->setText( + __( + 'Dump TIMESTAMP columns in UTC (enables TIMESTAMP columns' + . ' to be dumped and reloaded between servers in different' + . ' time zones)' + ) + ); + $dataOptions->addProperty($leaf); + } + + // add the main group to the root group + $exportSpecificOptions->addProperty($dataOptions); + + // set the options for the export plugin property item + $exportPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $exportPluginProperties; + } + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Exports routines (procedures and functions) + * + * @param string $db Database + * + * @return bool Whether it succeeded + */ + public function exportRoutines($db) + { + global $crlf; + + $text = ''; + $delimiter = '$$'; + + $procedure_names = $GLOBALS['dbi'] + ->getProceduresOrFunctions($db, 'PROCEDURE'); + $function_names = $GLOBALS['dbi']->getProceduresOrFunctions($db, 'FUNCTION'); + + if ($procedure_names || $function_names) { + $text .= $crlf + . 'DELIMITER ' . $delimiter . $crlf; + } + + if ($procedure_names) { + $text .= + $this->_exportComment() + . $this->_exportComment(__('Procedures')) + . $this->_exportComment(); + + foreach ($procedure_names as $procedure_name) { + if (! empty($GLOBALS['sql_drop_table'])) { + $text .= 'DROP PROCEDURE IF EXISTS ' + . PMA_Util::backquote($procedure_name) + . $delimiter . $crlf; + } + $text .= $GLOBALS['dbi'] + ->getDefinition($db, 'PROCEDURE', $procedure_name) + . $delimiter . $crlf . $crlf; + } + } + + if ($function_names) { + $text .= + $this->_exportComment() + . $this->_exportComment(__('Functions')) + . $this->_exportComment(); + + foreach ($function_names as $function_name) { + if (! empty($GLOBALS['sql_drop_table'])) { + $text .= 'DROP FUNCTION IF EXISTS ' + . PMA_Util::backquote($function_name) + . $delimiter . $crlf; + } + $text .= $GLOBALS['dbi'] + ->getDefinition($db, 'FUNCTION', $function_name) + . $delimiter . $crlf . $crlf; + } + } + + if ($procedure_names || $function_names) { + $text .= 'DELIMITER ;' . $crlf; + } + + if (! empty($text)) { + return PMA_exportOutputHandler($text); + } else { + return false; + } + } + + /** + * Possibly outputs comment + * + * @param string $text Text of comment + * + * @return string The formatted comment + */ + private function _exportComment($text = '') + { + if (isset($GLOBALS['sql_include_comments']) + && $GLOBALS['sql_include_comments'] + ) { + // see http://dev.mysql.com/doc/refman/5.0/en/ansi-diff-comments.html + return '--' . (empty($text) ? '' : ' ') . $text . $GLOBALS['crlf']; + } else { + return ''; + } + } + + /** + * Possibly outputs CRLF + * + * @return string $crlf or nothing + */ + private function _possibleCRLF() + { + if (isset($GLOBALS['sql_include_comments']) + && $GLOBALS['sql_include_comments'] + ) { + return $GLOBALS['crlf']; + } else { + return ''; + } + } + + /** + * Outputs export footer + * + * @return bool Whether it succeeded + */ + public function exportFooter() + { + global $crlf, $mysql_charset_map; + + $foot = ''; + + if (isset($GLOBALS['sql_disable_fk'])) { + $foot .= 'SET FOREIGN_KEY_CHECKS=1;' . $crlf; + } + + if (isset($GLOBALS['sql_use_transaction'])) { + $foot .= 'COMMIT;' . $crlf; + } + + // restore connection settings + $charset_of_file = isset($GLOBALS['charset_of_file']) + ? $GLOBALS['charset_of_file'] : ''; + if (! empty($GLOBALS['asfile']) + && isset($mysql_charset_map[$charset_of_file]) + && ! PMA_DRIZZLE + ) { + $foot .= $crlf + . '/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;' + . $crlf + . '/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;' + . $crlf + . '/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;' + . $crlf; + } + + /* Restore timezone */ + if (isset($GLOBALS['sql_utc_time']) && $GLOBALS['sql_utc_time']) { + $GLOBALS['dbi']->query('SET time_zone = "' . $GLOBALS['old_tz'] . '"'); + } + + return PMA_exportOutputHandler($foot); + } + + /** + * Outputs export header. It is the first method to be called, so all + * the required variables are initialized here. + * + * @return bool Whether it succeeded + */ + public function exportHeader() + { + global $crlf, $cfg; + global $mysql_charset_map; + + if (isset($GLOBALS['sql_compatibility'])) { + $tmp_compat = $GLOBALS['sql_compatibility']; + if ($tmp_compat == 'NONE') { + $tmp_compat = ''; + } + $GLOBALS['dbi']->tryQuery('SET SQL_MODE="' . $tmp_compat . '"'); + unset($tmp_compat); + } + $head = $this->_exportComment('phpMyAdmin SQL Dump') + . $this->_exportComment('version ' . PMA_VERSION) + . $this->_exportComment('http://www.phpmyadmin.net') + . $this->_exportComment(); + $host_string = __('Host:') . ' ' . $cfg['Server']['host']; + if (! empty($cfg['Server']['port'])) { + $host_string .= ':' . $cfg['Server']['port']; + } + $head .= $this->_exportComment($host_string); + $head .= + $this->_exportComment( + __('Generation Time:') . ' ' + . PMA_Util::localisedDate() + ) + . $this->_exportComment( + __('Server version:') . ' ' . PMA_MYSQL_STR_VERSION + ) + . $this->_exportComment(__('PHP Version:') . ' ' . phpversion()) + . $this->_possibleCRLF(); + + if (isset($GLOBALS['sql_header_comment']) + && ! empty($GLOBALS['sql_header_comment']) + ) { + // '\n' is not a newline (like "\n" would be), it's the characters + // backslash and n, as explained on the export interface + $lines = explode('\n', $GLOBALS['sql_header_comment']); + $head .= $this->_exportComment(); + foreach ($lines as $one_line) { + $head .= $this->_exportComment($one_line); + } + $head .= $this->_exportComment(); + } + + if (isset($GLOBALS['sql_disable_fk'])) { + $head .= 'SET FOREIGN_KEY_CHECKS=0;' . $crlf; + } + + // We want exported AUTO_INCREMENT columns to have still same value, + // do this only for recent MySQL exports + if ((! isset($GLOBALS['sql_compatibility']) + || $GLOBALS['sql_compatibility'] == 'NONE') + && ! PMA_DRIZZLE + ) { + $head .= 'SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";' . $crlf; + } + + if (isset($GLOBALS['sql_use_transaction'])) { + $head .= 'SET AUTOCOMMIT = 0;' . $crlf + . 'START TRANSACTION;' . $crlf; + } + + /* Change timezone if we should export timestamps in UTC */ + if (isset($GLOBALS['sql_utc_time']) && $GLOBALS['sql_utc_time']) { + $head .= 'SET time_zone = "+00:00";' . $crlf; + $GLOBALS['old_tz'] = $GLOBALS['dbi'] + ->fetchValue('SELECT @@session.time_zone'); + $GLOBALS['dbi']->query('SET time_zone = "+00:00"'); + } + + $head .= $this->_possibleCRLF(); + + if (! empty($GLOBALS['asfile']) && ! PMA_DRIZZLE) { + // we are saving as file, therefore we provide charset information + // so that a utility like the mysql client can interpret + // the file correctly + if (isset($GLOBALS['charset_of_file']) + && isset($mysql_charset_map[$GLOBALS['charset_of_file']]) + ) { + // we got a charset from the export dialog + $set_names = $mysql_charset_map[$GLOBALS['charset_of_file']]; + } else { + // by default we use the connection charset + $set_names = $mysql_charset_map['utf-8']; + } + $head .= $crlf + . '/*!40101 SET @OLD_CHARACTER_SET_CLIENT=' + . '@@CHARACTER_SET_CLIENT */;' . $crlf + . '/*!40101 SET @OLD_CHARACTER_SET_RESULTS=' + . '@@CHARACTER_SET_RESULTS */;' . $crlf + . '/*!40101 SET @OLD_COLLATION_CONNECTION=' + . '@@COLLATION_CONNECTION */;'. $crlf + . '/*!40101 SET NAMES ' . $set_names . ' */;' . $crlf . $crlf; + } + + return PMA_exportOutputHandler($head); + } + + /** + * Outputs CREATE DATABASE statement + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + global $crlf; + + if (isset($GLOBALS['sql_compatibility'])) { + $compat = $GLOBALS['sql_compatibility']; + } else { + $compat = 'NONE'; + } + if (isset($GLOBALS['sql_drop_database'])) { + if (! PMA_exportOutputHandler( + 'DROP DATABASE ' + . (isset($GLOBALS['sql_backquotes']) + ? PMA_Util::backquoteCompat($db, $compat) : $db) + . ';' . $crlf + )) { + return false; + } + } + if (isset($GLOBALS['sql_create_database'])) { + $create_query = 'CREATE DATABASE IF NOT EXISTS ' + . (isset($GLOBALS['sql_backquotes']) + ? PMA_Util::backquoteCompat($db, $compat) : $db); + $collation = PMA_getDbCollation($db); + if (PMA_DRIZZLE) { + $create_query .= ' COLLATE ' . $collation; + } else { + if (strpos($collation, '_')) { + $create_query .= ' DEFAULT CHARACTER SET ' + . substr($collation, 0, strpos($collation, '_')) + . ' COLLATE ' . $collation; + } else { + $create_query .= ' DEFAULT CHARACTER SET ' . $collation; + } + } + $create_query .= ';' . $crlf; + if (! PMA_exportOutputHandler($create_query)) { + return false; + } + if (isset($GLOBALS['sql_backquotes']) + && ((isset($GLOBALS['sql_compatibility']) + && $GLOBALS['sql_compatibility'] == 'NONE') + || PMA_DRIZZLE) + ) { + $result = PMA_exportOutputHandler( + 'USE ' . PMA_Util::backquoteCompat($db, $compat) + . ';' . $crlf + ); + } else { + $result = PMA_exportOutputHandler('USE ' . $db . ';' . $crlf); + } + return $result; + } else { + return true; + } + } + + /** + * Outputs database header + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBHeader($db) + { + if (isset($GLOBALS['sql_compatibility'])) { + $compat = $GLOBALS['sql_compatibility']; + } else { + $compat = 'NONE'; + } + $head = $this->_exportComment() + . $this->_exportComment( + __('Database:') . ' ' + . (isset($GLOBALS['sql_backquotes']) + ? PMA_Util::backquoteCompat($db, $compat) + : '\'' . $db . '\'') + ) + . $this->_exportComment(); + return PMA_exportOutputHandler($head); + } + + /** + * Outputs database footer + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBFooter($db) + { + global $crlf; + + $result = true; + if (isset($GLOBALS['sql_constraints'])) { + $result = PMA_exportOutputHandler($GLOBALS['sql_constraints']); + unset($GLOBALS['sql_constraints']); + } + + if (($GLOBALS['sql_structure_or_data'] == 'structure' + || $GLOBALS['sql_structure_or_data'] == 'structure_and_data') + && isset($GLOBALS['sql_procedure_function']) + ) { + $text = ''; + $delimiter = '$$'; + + if (PMA_MYSQL_INT_VERSION > 50100) { + $event_names = $GLOBALS['dbi']->fetchResult( + 'SELECT EVENT_NAME FROM information_schema.EVENTS WHERE' + . ' EVENT_SCHEMA= \'' + . PMA_Util::sqlAddSlashes($db, true) + . '\';' + ); + } else { + $event_names = array(); + } + + if ($event_names) { + $text .= $crlf + . 'DELIMITER ' . $delimiter . $crlf; + + $text .= + $this->_exportComment() + . $this->_exportComment(__('Events')) + . $this->_exportComment(); + + foreach ($event_names as $event_name) { + if (! empty($GLOBALS['sql_drop_table'])) { + $text .= 'DROP EVENT ' + . PMA_Util::backquote($event_name) + . $delimiter . $crlf; + } + $text .= $GLOBALS['dbi'] + ->getDefinition($db, 'EVENT', $event_name) + . $delimiter . $crlf . $crlf; + } + + $text .= 'DELIMITER ;' . $crlf; + } + + if (! empty($text)) { + $result = PMA_exportOutputHandler($text); + } + } + return $result; + } + + /** + * Returns a stand-in CREATE definition to resolve view dependencies + * + * @param string $db the database name + * @param string $view the view name + * @param string $crlf the end of line sequence + * + * @return string resulting definition + */ + public function getTableDefStandIn($db, $view, $crlf) + { + $create_query = ''; + if (! empty($GLOBALS['sql_drop_table'])) { + $create_query .= 'DROP VIEW IF EXISTS ' + . PMA_Util::backquote($view) + . ';' . $crlf; + } + + $create_query .= 'CREATE TABLE '; + + if (isset($GLOBALS['sql_if_not_exists']) + && $GLOBALS['sql_if_not_exists'] + ) { + $create_query .= 'IF NOT EXISTS '; + } + $create_query .= PMA_Util::backquote($view) . ' (' . $crlf; + $tmp = array(); + $columns = $GLOBALS['dbi']->getColumnsFull($db, $view); + foreach ($columns as $column_name => $definition) { + $tmp[] = PMA_Util::backquote($column_name) . ' ' . + $definition['Type'] . $crlf; + } + $create_query .= implode(',', $tmp) . ');'; + return($create_query); + } + + /** + * Returns CREATE definition that matches $view's structure + * + * @param string $db the database name + * @param string $view the view name + * @param string $crlf the end of line sequence + * @param bool $add_semicolon whether to add semicolon and end-of-line at + * the end + * + * @return string resulting schema + */ + private function _getTableDefForView( + $db, + $view, + $crlf, + $add_semicolon = true + ) { + $create_query = "CREATE TABLE"; + if (isset($GLOBALS['sql_if_not_exists'])) { + $create_query .= " IF NOT EXISTS "; + } + $create_query .= PMA_Util::backquote($view) . "(" . $crlf; + + $columns = $GLOBALS['dbi']->getColumns($db, $view, null, true); + + $firstCol = true; + foreach ($columns as $column) { + $extracted_columnspec = PMA_Util::extractColumnSpec($column['Type']); + + if (! $firstCol) { + $create_query .= "," . $crlf; + } + $create_query .= " " . PMA_Util::backquote($column['Field']); + $create_query .= " " . $column['Type']; + if ($extracted_columnspec['can_contain_collation'] + && ! empty($column['Collation']) + ) { + $create_query .= " COLLATE " . $column['Collation']; + } + if ($column['Null'] == 'NO') { + $create_query .= " NOT NULL"; + } + if (isset($column['Default'])) { + $create_query .= " DEFAULT '" + . PMA_Util::sqlAddSlashes($column['Default']) . "'"; + } else if ($column['Null'] == 'YES') { + $create_query .= " DEFAULT NULL"; + } + if (! empty($column['Comment'])) { + $create_query .= " COMMENT '" + . PMA_Util::sqlAddSlashes($column['Comment']) . "'"; + } + $firstCol = false; + } + $create_query .= $crlf . ")" . ($add_semicolon ? ';' : '') . $crlf; + + if (isset($GLOBALS['sql_compatibility'])) { + $compat = $GLOBALS['sql_compatibility']; + } else { + $compat = 'NONE'; + } + if ($compat == 'MSSQL') { + $create_query = $this->_makeCreateTableMSSQLCompatible( + $create_query + ); + } + return $create_query; + } + + /** + * Returns $table's CREATE definition + * + * @param string $db the database name + * @param string $table the table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param bool $show_dates whether to include creation/update/check + * dates + * @param bool $add_semicolon whether to add semicolon and end-of-line at + * the end + * @param bool $view whether we're handling a view + * + * @return string resulting schema + */ + public function getTableDef( + $db, + $table, + $crlf, + $error_url, + $show_dates = false, + $add_semicolon = true, + $view = false + ) { + global $sql_drop_table, $sql_backquotes, $sql_constraints, + $sql_constraints_query, $sql_drop_foreign_keys; + + $schema_create = ''; + $auto_increment = ''; + $new_crlf = $crlf; + + if (isset($GLOBALS['sql_compatibility'])) { + $compat = $GLOBALS['sql_compatibility']; + } else { + $compat = 'NONE'; + } + + // need to use PMA_DatabaseInterface::QUERY_STORE + // with $GLOBALS['dbi']->numRows() in mysqli + $result = $GLOBALS['dbi']->query( + 'SHOW TABLE STATUS FROM ' . PMA_Util::backquote($db) + . ' LIKE \'' . PMA_Util::sqlAddSlashes($table, true) . '\'', + null, + PMA_DatabaseInterface::QUERY_STORE + ); + if ($result != false) { + if ($GLOBALS['dbi']->numRows($result) > 0) { + $tmpres = $GLOBALS['dbi']->fetchAssoc($result); + if (PMA_DRIZZLE && $show_dates) { + // Drizzle doesn't give Create_time and Update_time in + // SHOW TABLE STATUS, add it + $sql ="SELECT + TABLE_CREATION_TIME AS Create_time, + TABLE_UPDATE_TIME AS Update_time + FROM data_dictionary.TABLES + WHERE TABLE_SCHEMA = '" + . PMA_Util::sqlAddSlashes($db) . "' + AND TABLE_NAME = '" + . PMA_Util::sqlAddSlashes($table) . "'"; + $tmpres = array_merge( + $GLOBALS['dbi']->fetchSingleRow($sql), $tmpres + ); + } + // Here we optionally add the AUTO_INCREMENT next value, + // but starting with MySQL 5.0.24, the clause is already included + // in SHOW CREATE TABLE so we'll remove it below + // It's required for Drizzle because SHOW CREATE TABLE uses + // the value from table's creation time + if (isset($GLOBALS['sql_auto_increment']) + && ! empty($tmpres['Auto_increment']) + ) { + $auto_increment .= ' AUTO_INCREMENT=' + . $tmpres['Auto_increment'] . ' '; + } + + if ($show_dates + && isset($tmpres['Create_time']) + && ! empty($tmpres['Create_time']) + ) { + $schema_create .= $this->_exportComment( + __('Creation:') . ' ' + . PMA_Util::localisedDate( + strtotime($tmpres['Create_time']) + ) + ); + $new_crlf = $this->_exportComment() . $crlf; + } + + if ($show_dates + && isset($tmpres['Update_time']) + && ! empty($tmpres['Update_time']) + ) { + $schema_create .= $this->_exportComment( + __('Last update:') . ' ' + . PMA_Util::localisedDate( + strtotime($tmpres['Update_time']) + ) + ); + $new_crlf = $this->_exportComment() . $crlf; + } + + if ($show_dates + && isset($tmpres['Check_time']) + && ! empty($tmpres['Check_time']) + ) { + $schema_create .= $this->_exportComment( + __('Last check:') . ' ' + . PMA_Util::localisedDate( + strtotime($tmpres['Check_time']) + ) + ); + $new_crlf = $this->_exportComment() . $crlf; + } + } + $GLOBALS['dbi']->freeResult($result); + } + + $schema_create .= $new_crlf; + + // no need to generate a DROP VIEW here, it was done earlier + if (! empty($sql_drop_table) && ! PMA_Table::isView($db, $table)) { + $schema_create .= 'DROP TABLE IF EXISTS ' + . PMA_Util::backquote($table, $sql_backquotes) . ';' + . $crlf; + } + + // Complete table dump, + // Whether to quote table and column names or not + // Drizzle always quotes names + if (! PMA_DRIZZLE) { + if ($sql_backquotes) { + $GLOBALS['dbi']->query('SET SQL_QUOTE_SHOW_CREATE = 1'); + } else { + $GLOBALS['dbi']->query('SET SQL_QUOTE_SHOW_CREATE = 0'); + } + } + + // I don't see the reason why this unbuffered query could cause problems, + // because SHOW CREATE TABLE returns only one row, and we free the + // results below. Nonetheless, we got 2 user reports about this + // (see bug 1562533) so I removed the unbuffered mode. + // $result = $GLOBALS['dbi']->query('SHOW CREATE TABLE ' . backquote($db) + // . '.' . backquote($table), null, PMA_DatabaseInterface::QUERY_UNBUFFERED); + // + // Note: SHOW CREATE TABLE, at least in MySQL 5.1.23, does not + // produce a displayable result for the default value of a BIT + // column, nor does the mysqldump command. See MySQL bug 35796 + $result = $GLOBALS['dbi']->tryQuery( + 'SHOW CREATE TABLE ' . PMA_Util::backquote($db) . '.' + . PMA_Util::backquote($table) + ); + // an error can happen, for example the table is crashed + $tmp_error = $GLOBALS['dbi']->getError(); + if ($tmp_error) { + return $this->_exportComment(__('in use') . '(' . $tmp_error . ')'); + } + + if ($result != false && ($row = $GLOBALS['dbi']->fetchRow($result))) { + $create_query = $row[1]; + unset($row); + + // Convert end of line chars to one that we want (note that MySQL + // doesn't return query it will accept in all cases) + if (strpos($create_query, "(\r\n ")) { + $create_query = str_replace("\r\n", $crlf, $create_query); + } elseif (strpos($create_query, "(\n ")) { + $create_query = str_replace("\n", $crlf, $create_query); + } elseif (strpos($create_query, "(\r ")) { + $create_query = str_replace("\r", $crlf, $create_query); + } + + /* + * Drop database name from VIEW creation. + * + * This is a bit tricky, but we need to issue SHOW CREATE TABLE with + * database name, but we don't want name to show up in CREATE VIEW + * statement. + */ + if ($view) { + $create_query = preg_replace( + '/' . PMA_Util::backquote($db) . '\./', + '', + $create_query + ); + } + + // Should we use IF NOT EXISTS? + if (isset($GLOBALS['sql_if_not_exists'])) { + $create_query = preg_replace( + '/^CREATE TABLE/', + 'CREATE TABLE IF NOT EXISTS', + $create_query + ); + } + + if ($compat == 'MSSQL') { + $create_query = $this->_makeCreateTableMSSQLCompatible( + $create_query + ); + } + + // Drizzle (checked on 2011.03.13) returns ROW_FORMAT surrounded + // with quotes, which is not accepted by parser + if (PMA_DRIZZLE) { + $create_query = preg_replace( + '/ROW_FORMAT=\'(\S+)\'/', + 'ROW_FORMAT=$1', + $create_query + ); + } + + // are there any constraints to cut out? + if (preg_match('@CONSTRAINT|FOREIGN[\s]+KEY@', $create_query)) { + + // Split the query into lines, so we can easily handle it. + // We know lines are separated by $crlf (done few lines above). + $sql_lines = explode($crlf, $create_query); + $sql_count = count($sql_lines); + + // lets find first line with constraints + for ($i = 0; $i < $sql_count; $i++) { + if (preg_match( + '@^[\s]*(CONSTRAINT|FOREIGN[\s]+KEY)@', + $sql_lines[$i] + )) { + break; + } + } + + // If we really found a constraint + if ($i != $sql_count) { + + // remove, from the end of create statement + $sql_lines[$i - 1] = preg_replace( + '@,$@', + '', + $sql_lines[$i - 1] + ); + + // prepare variable for constraints + if (! isset($sql_constraints)) { + if (isset($GLOBALS['no_constraints_comments'])) { + $sql_constraints = ''; + } else { + $sql_constraints = $crlf + . $this->_exportComment() + . $this->_exportComment( + __('Constraints for dumped tables') + ) + . $this->_exportComment(); + } + } + + // comments for current table + if (! isset($GLOBALS['no_constraints_comments'])) { + $sql_constraints .= $crlf + . $this->_exportComment() + . $this->_exportComment( + __('Constraints for table') + . ' ' + . PMA_Util::backquoteCompat($table, $compat) + ) + . $this->_exportComment(); + } + + // let's do the work + $sql_constraints_query .= 'ALTER TABLE ' + . PMA_Util::backquoteCompat($table, $compat) + . $crlf; + $sql_constraints .= 'ALTER TABLE ' + . PMA_Util::backquoteCompat($table, $compat) + . $crlf; + $sql_drop_foreign_keys .= 'ALTER TABLE ' + . PMA_Util::backquoteCompat($db, $compat) . '.' + . PMA_Util::backquoteCompat($table, $compat) + . $crlf; + + $first = true; + for ($j = $i; $j < $sql_count; $j++) { + if (preg_match( + '@CONSTRAINT|FOREIGN[\s]+KEY@', + $sql_lines[$j] + )) { + if (! $first) { + $sql_constraints .= $crlf; + } + if (strpos($sql_lines[$j], 'CONSTRAINT') === false) { + $tmp_str = preg_replace( + '/(FOREIGN[\s]+KEY)/', + 'ADD \1', + $sql_lines[$j] + ); + $sql_constraints_query .= $tmp_str; + $sql_constraints .= $tmp_str; + } else { + $tmp_str = preg_replace( + '/(CONSTRAINT)/', + 'ADD \1', + $sql_lines[$j] + ); + $sql_constraints_query .= $tmp_str; + $sql_constraints .= $tmp_str; + preg_match( + '/(CONSTRAINT)([\s])([\S]*)([\s])/', + $sql_lines[$j], + $matches + ); + if (! $first) { + $sql_drop_foreign_keys .= ', '; + } + $sql_drop_foreign_keys .= 'DROP FOREIGN KEY ' + . $matches[3]; + } + $first = false; + } else { + break; + } + } + $sql_constraints .= ';' . $crlf; + $sql_constraints_query .= ';'; + + $create_query = implode( + $crlf, + array_slice($sql_lines, 0, $i) + ) + . $crlf + . implode( + $crlf, + array_slice($sql_lines, $j, $sql_count - 1) + ); + unset($sql_lines); + } + } + $schema_create .= $create_query; + } + + // remove a possible "AUTO_INCREMENT = value" clause + // that could be there starting with MySQL 5.0.24 + // in Drizzle it's useless as it contains the value given at table + // creation time + $schema_create = preg_replace( + '/AUTO_INCREMENT\s*=\s*([0-9])+/', + '', + $schema_create + ); + + $schema_create .= ($compat != 'MSSQL') ? $auto_increment : ''; + + $GLOBALS['dbi']->freeResult($result); + return $schema_create . ($add_semicolon ? ';' . $crlf : ''); + } // end of the 'getTableDef()' function + + /** + * Returns $table's comments, relations etc. + * + * @param string $db database name + * @param string $table table name + * @param string $crlf end of line sequence + * @param bool $do_relation whether to include relation comments + * @param bool $do_mime whether to include mime comments + * + * @return string resulting comments + */ + private function _getTableComments( + $db, + $table, + $crlf, + $do_relation = false, + $do_mime = false + ) { + global $cfgRelation, $sql_backquotes; + + $schema_create = ''; + + // Check if we can use Relations + if ($do_relation && ! empty($cfgRelation['relation'])) { + // Find which tables are related with the current one and write it in + // an array + $res_rel = PMA_getForeigners($db, $table); + + if ($res_rel && count($res_rel) > 0) { + $have_rel = true; + } else { + $have_rel = false; + } + } else { + $have_rel = false; + } // end if + + if ($do_mime && $cfgRelation['mimework']) { + if (! ($mime_map = PMA_getMIME($db, $table, true))) { + unset($mime_map); + } + } + + if (isset($mime_map) && count($mime_map) > 0) { + $schema_create .= $this->_possibleCRLF() + . $this->_exportComment() + . $this->_exportComment( + __('MIME TYPES FOR TABLE'). ' ' + . PMA_Util::backquote($table, $sql_backquotes) . ':' + ); + @reset($mime_map); + foreach ($mime_map as $mime_field => $mime) { + $schema_create .= + $this->_exportComment( + ' ' + . PMA_Util::backquote($mime_field, $sql_backquotes) + ) + . $this->_exportComment( + ' ' + . PMA_Util::backquote( + $mime['mimetype'], + $sql_backquotes + ) + ); + } + $schema_create .= $this->_exportComment(); + } + + if ($have_rel) { + $schema_create .= $this->_possibleCRLF() + . $this->_exportComment() + . $this->_exportComment( + __('RELATIONS FOR TABLE') . ' ' + . PMA_Util::backquote($table, $sql_backquotes) + . ':' + ); + foreach ($res_rel as $rel_field => $rel) { + $schema_create .= + $this->_exportComment( + ' ' + . PMA_Util::backquote($rel_field, $sql_backquotes) + ) + . $this->_exportComment( + ' ' + . PMA_Util::backquote( + $rel['foreign_table'], + $sql_backquotes + ) + . ' -> ' + . PMA_Util::backquote( + $rel['foreign_field'], + $sql_backquotes + ) + ); + } + $schema_create .= $this->_exportComment(); + } + + return $schema_create; + + } // end of the '_getTableComments()' function + + /** + * Outputs table's structure + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $export_mode 'create_table','triggers','create_view', + * 'stand_in' + * @param string $export_type 'server', 'database', 'table' + * @param bool $relation whether to include relation comments + * @param bool $comments whether to include the pmadb-style column + * comments as comments in the structure; this is + * deprecated but the parameter is left here + * because export.php calls exportStructure() + * also for other export types which use this + * parameter + * @param bool $mime whether to include mime comments + * @param bool $dates whether to include creation/update/check dates + * + * @return bool Whether it succeeded + */ + public function exportStructure( + $db, + $table, + $crlf, + $error_url, + $export_mode, + $export_type, + $relation = false, + $comments = false, + $mime = false, + $dates = false + ) { + if (isset($GLOBALS['sql_compatibility'])) { + $compat = $GLOBALS['sql_compatibility']; + } else { + $compat = 'NONE'; + } + + $formatted_table_name = (isset($GLOBALS['sql_backquotes'])) + ? PMA_Util::backquoteCompat($table, $compat) + : '\'' . $table . '\''; + $dump = $this->_possibleCRLF() + . $this->_exportComment(str_repeat('-', 56)) + . $this->_possibleCRLF() + . $this->_exportComment(); + + switch($export_mode) { + case 'create_table': + $dump .= $this->_exportComment( + __('Table structure for table') . ' '. $formatted_table_name + ); + $dump .= $this->_exportComment(); + $dump .= $this->getTableDef($db, $table, $crlf, $error_url, $dates); + $dump .= $this->_getTableComments($db, $table, $crlf, $relation, $mime); + break; + case 'triggers': + $dump = ''; + $triggers = $GLOBALS['dbi']->getTriggers($db, $table); + if ($triggers) { + $dump .= $this->_possibleCRLF() + . $this->_exportComment() + . $this->_exportComment( + __('Triggers') . ' ' . $formatted_table_name + ) + . $this->_exportComment(); + $delimiter = '//'; + foreach ($triggers as $trigger) { + $dump .= $trigger['drop'] . ';' . $crlf; + $dump .= 'DELIMITER ' . $delimiter . $crlf; + $dump .= $trigger['create']; + $dump .= 'DELIMITER ;' . $crlf; + } + } + break; + case 'create_view': + if (empty($GLOBALS['sql_views_as_tables'])) { + $dump .= + $this->_exportComment( + __('Structure for view') + . ' ' + . $formatted_table_name + ) + . $this->_exportComment(); + // delete the stand-in table previously created (if any) + if ($export_type != 'table') { + $dump .= 'DROP TABLE IF EXISTS ' + . PMA_Util::backquote($table) . ';' . $crlf; + } + $dump .= $this->getTableDef( + $db, $table, $crlf, $error_url, $dates, true, true + ); + } else { + $dump .= + $this->_exportComment( + sprintf( + __('Structure for view %s exported as a table'), + $formatted_table_name + ) + ) + . $this->_exportComment(); + // delete the stand-in table previously created (if any) + if ($export_type != 'table') { + $dump .= 'DROP TABLE IF EXISTS ' + . PMA_Util::backquote($table) . ';' . $crlf; + } + $dump .= $this->_getTableDefForView( + $db, $table, $crlf, true + ); + } + break; + case 'stand_in': + $dump .= + $this->_exportComment( + __('Stand-in structure for view') . ' ' . $formatted_table_name + ) + . $this->_exportComment(); + // export a stand-in definition to resolve view dependencies + $dump .= $this->getTableDefStandIn($db, $table, $crlf); + } // end switch + + // this one is built by getTableDef() to use in table copy/move + // but not in the case of export + unset($GLOBALS['sql_constraints_query']); + + return PMA_exportOutputHandler($dump); + } + + /** + * Outputs the content of a table in SQL format + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $sql_query SQL query for obtaining data + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + global $current_row, $sql_backquotes; + + if (isset($GLOBALS['sql_compatibility'])) { + $compat = $GLOBALS['sql_compatibility']; + } else { + $compat = 'NONE'; + } + + $formatted_table_name = (isset($GLOBALS['sql_backquotes'])) + ? PMA_Util::backquoteCompat($table, $compat) + : '\'' . $table . '\''; + + // Do not export data for a VIEW, unless asked to export the view as a table + // (For a VIEW, this is called only when exporting a single VIEW) + if (PMA_Table::isView($db, $table) + && empty($GLOBALS['sql_views_as_tables']) + ) { + $head = $this->_possibleCRLF() + . $this->_exportComment() + . $this->_exportComment('VIEW ' . ' ' . $formatted_table_name) + . $this->_exportComment(__('Data:') . ' ' . __('None')) + . $this->_exportComment() + . $this->_possibleCRLF(); + + if (! PMA_exportOutputHandler($head)) { + return false; + } + return true; + } + + // analyze the query to get the true column names, not the aliases + // (this fixes an undefined index, also if Complete inserts + // are used, we did not get the true column name in case of aliases) + $analyzed_sql = PMA_SQP_analyze(PMA_SQP_parse($sql_query)); + + $result = $GLOBALS['dbi']->tryQuery( + $sql_query, null, PMA_DatabaseInterface::QUERY_UNBUFFERED + ); + // a possible error: the table has crashed + $tmp_error = $GLOBALS['dbi']->getError(); + if ($tmp_error) { + return PMA_exportOutputHandler( + $this->_exportComment( + __('Error reading data:') . ' (' . $tmp_error . ')' + ) + ); + } + + if ($result != false) { + $fields_cnt = $GLOBALS['dbi']->numFields($result); + + // Get field information + $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result); + $field_flags = array(); + for ($j = 0; $j < $fields_cnt; $j++) { + $field_flags[$j] = $GLOBALS['dbi']->fieldFlags($result, $j); + } + + for ($j = 0; $j < $fields_cnt; $j++) { + if (isset($analyzed_sql[0]['select_expr'][$j]['column'])) { + $field_set[$j] = PMA_Util::backquoteCompat( + $analyzed_sql[0]['select_expr'][$j]['column'], + $compat, + $sql_backquotes + ); + } else { + $field_set[$j] = PMA_Util::backquoteCompat( + $fields_meta[$j]->name, + $compat, + $sql_backquotes + ); + } + } + + if (isset($GLOBALS['sql_type']) + && $GLOBALS['sql_type'] == 'UPDATE' + ) { + // update + $schema_insert = 'UPDATE '; + if (isset($GLOBALS['sql_ignore'])) { + $schema_insert .= 'IGNORE '; + } + // avoid EOL blank + $schema_insert .= PMA_Util::backquoteCompat( + $table, + $compat, + $sql_backquotes + ) . ' SET'; + } else { + // insert or replace + if (isset($GLOBALS['sql_type']) + && $GLOBALS['sql_type'] == 'REPLACE' + ) { + $sql_command = 'REPLACE'; + } else { + $sql_command = 'INSERT'; + } + + // delayed inserts? + if (isset($GLOBALS['sql_delayed'])) { + $insert_delayed = ' DELAYED'; + } else { + $insert_delayed = ''; + } + + // insert ignore? + if (isset($GLOBALS['sql_type']) + && $GLOBALS['sql_type'] == 'INSERT' + && isset($GLOBALS['sql_ignore']) + ) { + $insert_delayed .= ' IGNORE'; + } + //truncate table before insert + if (isset($GLOBALS['sql_truncate']) + && $GLOBALS['sql_truncate'] + && $sql_command == 'INSERT' + ) { + $truncate = 'TRUNCATE TABLE ' + . PMA_Util::backquoteCompat( + $table, + $compat, + $sql_backquotes + ) . ";"; + $truncatehead = $this->_possibleCRLF() + . $this->_exportComment() + . $this->_exportComment( + __('Truncate table before insert') . ' ' + . $formatted_table_name + ) + . $this->_exportComment() + . $crlf; + PMA_exportOutputHandler($truncatehead); + PMA_exportOutputHandler($truncate); + } else { + $truncate = ''; + } + + // scheme for inserting fields + if ($GLOBALS['sql_insert_syntax'] == 'complete' + || $GLOBALS['sql_insert_syntax'] == 'both' + ) { + $fields = implode(', ', $field_set); + $schema_insert = $sql_command . $insert_delayed .' INTO ' + . PMA_Util::backquoteCompat( + $table, + $compat, + $sql_backquotes + ) + // avoid EOL blank + . ' (' . $fields . ') VALUES'; + } else { + $schema_insert = $sql_command . $insert_delayed .' INTO ' + . PMA_Util::backquoteCompat( + $table, + $compat, + $sql_backquotes + ) + . ' VALUES'; + } + } + + //\x08\\x09, not required + $search = array("\x00", "\x0a", "\x0d", "\x1a"); + $replace = array('\0', '\n', '\r', '\Z'); + $current_row = 0; + $query_size = 0; + if (($GLOBALS['sql_insert_syntax'] == 'extended' + || $GLOBALS['sql_insert_syntax'] == 'both') + && (! isset($GLOBALS['sql_type']) + || $GLOBALS['sql_type'] != 'UPDATE') + ) { + $separator = ','; + $schema_insert .= $crlf; + } else { + $separator = ';'; + } + + while ($row = $GLOBALS['dbi']->fetchRow($result)) { + if ($current_row == 0) { + $head = $this->_possibleCRLF() + . $this->_exportComment() + . $this->_exportComment( + __('Dumping data for table') . ' ' + . $formatted_table_name + ) + . $this->_exportComment() + . $crlf; + if (! PMA_exportOutputHandler($head)) { + return false; + } + } + // We need to SET IDENTITY_INSERT ON for MSSQL + if (isset($GLOBALS['sql_compatibility']) + && $GLOBALS['sql_compatibility'] == 'MSSQL' + && $current_row == 0 + ) { + if (! PMA_exportOutputHandler( + 'SET IDENTITY_INSERT ' + . PMA_Util::backquoteCompat( + $table, + $compat + ) + . ' ON ;'.$crlf + )) { + return false; + } + } + $current_row++; + for ($j = 0; $j < $fields_cnt; $j++) { + // NULL + if (! isset($row[$j]) || is_null($row[$j])) { + $values[] = 'NULL'; + } elseif ($fields_meta[$j]->numeric + && $fields_meta[$j]->type != 'timestamp' + && ! $fields_meta[$j]->blob + ) { + // a number + // timestamp is numeric on some MySQL 4.1, BLOBs are + // sometimes numeric + $values[] = $row[$j]; + } elseif (stristr($field_flags[$j], 'BINARY') + && $fields_meta[$j]->blob + && isset($GLOBALS['sql_hex_for_blob']) + ) { + // a true BLOB + // - mysqldump only generates hex data when the --hex-blob + // option is used, for fields having the binary attribute + // no hex is generated + // - a TEXT field returns type blob but a real blob + // returns also the 'binary' flag + + // empty blobs need to be different, but '0' is also empty + // :-( + if (empty($row[$j]) && $row[$j] != '0') { + $values[] = '\'\''; + } else { + $values[] = '0x' . bin2hex($row[$j]); + } + } elseif ($fields_meta[$j]->type == 'bit') { + // detection of 'bit' works only on mysqli extension + $values[] = "b'" . PMA_Util::sqlAddSlashes( + PMA_Util::printableBitValue( + $row[$j], $fields_meta[$j]->length + ) + ) + . "'"; + } else { + // something else -> treat as a string + $values[] = '\'' + . str_replace( + $search, $replace, + PMA_Util::sqlAddSlashes($row[$j]) + ) + . '\''; + } // end if + } // end for + + // should we make update? + if (isset($GLOBALS['sql_type']) + && $GLOBALS['sql_type'] == 'UPDATE' + ) { + + $insert_line = $schema_insert; + for ($i = 0; $i < $fields_cnt; $i++) { + if (0 == $i) { + $insert_line .= ' '; + } + if ($i > 0) { + // avoid EOL blank + $insert_line .= ','; + } + $insert_line .= $field_set[$i] . ' = ' . $values[$i]; + } + + list($tmp_unique_condition, $tmp_clause_is_unique) + = PMA_Util::getUniqueCondition( + $result, + $fields_cnt, + $fields_meta, + $row + ); + $insert_line .= ' WHERE ' . $tmp_unique_condition; + unset($tmp_unique_condition, $tmp_clause_is_unique); + + } else { + + // Extended inserts case + if ($GLOBALS['sql_insert_syntax'] == 'extended' + || $GLOBALS['sql_insert_syntax'] == 'both' + ) { + if ($current_row == 1) { + $insert_line = $schema_insert . '(' + . implode(', ', $values) . ')'; + } else { + $insert_line = '(' . implode(', ', $values) . ')'; + $sql_max_size = $GLOBALS['sql_max_query_size']; + if (isset($sql_max_size) + && $sql_max_size > 0 + && $query_size + strlen($insert_line) > $sql_max_size + ) { + if (! PMA_exportOutputHandler(';' . $crlf)) { + return false; + } + $query_size = 0; + $current_row = 1; + $insert_line = $schema_insert . $insert_line; + } + } + $query_size += strlen($insert_line); + // Other inserts case + } else { + $insert_line = $schema_insert + . '(' + . implode(', ', $values) + . ')'; + } + } + unset($values); + + if (! PMA_exportOutputHandler( + ($current_row == 1 ? '' : $separator . $crlf) + . $insert_line + )) { + return false; + } + + } // end while + + if ($current_row > 0) { + if (! PMA_exportOutputHandler(';' . $crlf)) { + return false; + } + } + + // We need to SET IDENTITY_INSERT OFF for MSSQL + if (isset($GLOBALS['sql_compatibility']) + && $GLOBALS['sql_compatibility'] == 'MSSQL' + && $current_row > 0 + ) { + $outputSucceeded = PMA_exportOutputHandler( + $crlf . 'SET IDENTITY_INSERT ' + . PMA_Util::backquoteCompat($table, $compat) + . ' OFF;' . $crlf + ); + if (! $outputSucceeded) { + return false; + } + } + } // end if ($result != false) + $GLOBALS['dbi']->freeResult($result); + + return true; + } // end of the 'exportData()' function + + /** + * Make a create table statement compatible with MSSQL + * + * @param string $create_query MySQL create table statement + * + * @return string MSSQL compatible create table statement + */ + private function _makeCreateTableMSSQLCompatible($create_query) + { + // In MSSQL + // 1. No 'IF NOT EXISTS' in CREATE TABLE + // 2. DATE field doesn't exists, we will use DATETIME instead + // 3. UNSIGNED attribute doesn't exist + // 4. No length on INT, TINYINT, SMALLINT, BIGINT and no precision on + // FLOAT fields + // 5. No KEY and INDEX inside CREATE TABLE + // 6. DOUBLE field doesn't exists, we will use FLOAT instead + + $create_query = preg_replace( + "/^CREATE TABLE IF NOT EXISTS/", + 'CREATE TABLE', + $create_query + ); + // first we need to replace all lines ended with '" DATE ...,\n' + // last preg_replace preserve us from situation with date text + // inside DEFAULT field value + $create_query = preg_replace( + "/\" date DEFAULT NULL(,)?\n/", + '" datetime DEFAULT NULL$1' . "\n", + $create_query + ); + $create_query = preg_replace( + "/\" date NOT NULL(,)?\n/", + '" datetime NOT NULL$1' . "\n", + $create_query + ); + $create_query = preg_replace( + '/" date NOT NULL DEFAULT \'([^\'])/', + '" datetime NOT NULL DEFAULT \'$1', + $create_query + ); + + // next we need to replace all lines ended with ') UNSIGNED ...,' + // last preg_replace preserve us from situation with unsigned text + // inside DEFAULT field value + $create_query = preg_replace( + "/\) unsigned NOT NULL(,)?\n/", + ') NOT NULL$1' . "\n", + $create_query + ); + $create_query = preg_replace( + "/\) unsigned DEFAULT NULL(,)?\n/", + ') DEFAULT NULL$1' . "\n", + $create_query + ); + $create_query = preg_replace( + '/\) unsigned NOT NULL DEFAULT \'([^\'])/', + ') NOT NULL DEFAULT \'$1', + $create_query + ); + + // we need to replace all lines ended with + // '" INT|TINYINT([0-9]{1,}) ...,' last preg_replace preserve us + // from situation with int([0-9]{1,}) text inside DEFAULT field + // value + $create_query = preg_replace( + '/" (int|tinyint|smallint|bigint)\([0-9]+\) DEFAULT NULL(,)?\n/', + '" $1 DEFAULT NULL$2' . "\n", + $create_query + ); + $create_query = preg_replace( + '/" (int|tinyint|smallint|bigint)\([0-9]+\) NOT NULL(,)?\n/', + '" $1 NOT NULL$2' . "\n", + $create_query + ); + $create_query = preg_replace( + '/" (int|tinyint|smallint|bigint)\([0-9]+\) NOT NULL DEFAULT \'([^\'])/', + '" $1 NOT NULL DEFAULT \'$2', + $create_query + ); + + // we need to replace all lines ended with + // '" FLOAT|DOUBLE([0-9,]{1,}) ...,' + // last preg_replace preserve us from situation with + // float([0-9,]{1,}) text inside DEFAULT field value + $create_query = preg_replace( + '/" (float|double)(\([0-9]+,[0-9,]+\))? DEFAULT NULL(,)?\n/', + '" float DEFAULT NULL$3' . "\n", + $create_query + ); + $create_query = preg_replace( + '/" (float|double)(\([0-9,]+,[0-9,]+\))? NOT NULL(,)?\n/', + '" float NOT NULL$3' . "\n", + $create_query + ); + $create_query = preg_replace( + '/" (float|double)(\([0-9,]+,[0-9,]+\))? NOT NULL DEFAULT \'([^\'])/', + '" float NOT NULL DEFAULT \'$3', + $create_query + ); + + // @todo remove indexes from CREATE TABLE + + return $create_query; + } +} diff --git a/phpMyAdmin/libraries/plugins/export/ExportTexytext.class.php b/phpMyAdmin/libraries/plugins/export/ExportTexytext.class.php new file mode 100644 index 0000000..1e6efa0 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/export/ExportTexytext.class.php @@ -0,0 +1,576 @@ +setProperties(); + } + + /** + * Sets the export Texy! text properties + * + * @return void + */ + protected function setProperties() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/RadioPropertyItem.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + include_once "$props/options/items/TextPropertyItem.class.php"; + + $exportPluginProperties = new ExportPluginProperties(); + $exportPluginProperties->setText('Texy! text'); + $exportPluginProperties->setExtension('txt'); + $exportPluginProperties->setMimeType('text/plain'); + $exportPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $exportPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup(); + $exportSpecificOptions->setName("Format Specific Options"); + + // what to dump (structure/data/both) main group + $dumpWhat = new OptionsPropertyMainGroup(); + $dumpWhat->setName("general_opts"); + $dumpWhat->setText(__('Dump table')); + // create primary items and add them to the group + $leaf = new RadioPropertyItem(); + $leaf->setName("structure_or_data"); + $leaf->setValues( + array( + 'structure' => __('structure'), + 'data' => __('data'), + 'structure_and_data' => __('structure and data') + ) + ); + $dumpWhat->addProperty($leaf); + // add the main group to the root group + $exportSpecificOptions->addProperty($dumpWhat); + + // data options main group + $dataOptions = new OptionsPropertyMainGroup(); + $dataOptions->setName("data"); + $dataOptions->setText(__('Data dump options')); + $dataOptions->setForce('structure'); + // create primary items and add them to the group + $leaf = new BoolPropertyItem(); + $leaf->setName("columns"); + $leaf->setText(__('Put columns names in the first row')); + $dataOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName('null'); + $leaf->setText(__('Replace NULL with:')); + $dataOptions->addProperty($leaf); + // add the main group to the root group + $exportSpecificOptions->addProperty($dataOptions); + + // set the options for the export plugin property item + $exportPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $exportPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Outputs export header + * + * @return bool Whether it succeeded + */ + public function exportHeader () + { + return true; + } + + /** + * Outputs export footer + * + * @return bool Whether it succeeded + */ + public function exportFooter () + { + return true; + } + + /** + * Outputs database header + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + return PMA_exportOutputHandler( + '===' . __('Database') . ' ' . $db . "\n\n" + ); + } + + /** + * Outputs database footer + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBFooter ($db) + { + return true; + } + + /** + * Outputs CREATE DATABASE statement + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + return true; + } + /** + * Outputs the content of a table in NHibernate format + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $sql_query SQL query for obtaining data + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + global $what; + + if (! PMA_exportOutputHandler( + '== ' . __('Dumping data for table') . ' ' . $table . "\n\n" + )) { + return false; + } + + // Gets the data from the database + $result = $GLOBALS['dbi']->query( + $sql_query, null, PMA_DatabaseInterface::QUERY_UNBUFFERED + ); + $fields_cnt = $GLOBALS['dbi']->numFields($result); + + // If required, get fields name at the first line + if (isset($GLOBALS[$what . '_columns'])) { + $text_output = "|------\n"; + for ($i = 0; $i < $fields_cnt; $i++) { + $text_output .= '|' + . htmlspecialchars( + stripslashes($GLOBALS['dbi']->fieldName($result, $i)) + ); + } // end for + $text_output .= "\n|------\n"; + if (! PMA_exportOutputHandler($text_output)) { + return false; + } + } // end if + + // Format the data + while ($row = $GLOBALS['dbi']->fetchRow($result)) { + $text_output = ''; + for ($j = 0; $j < $fields_cnt; $j++) { + if (! isset($row[$j]) || is_null($row[$j])) { + $value = $GLOBALS[$what . '_null']; + } elseif ($row[$j] == '0' || $row[$j] != '') { + $value = $row[$j]; + } else { + $value = ' '; + } + $text_output .= '|' + . str_replace( + '|', '|', htmlspecialchars($value) + ); + } // end for + $text_output .= "\n"; + if (! PMA_exportOutputHandler($text_output)) { + return false; + } + } // end while + $GLOBALS['dbi']->freeResult($result); + + return true; + } + + /** + * Returns a stand-in CREATE definition to resolve view dependencies + * + * @param string $db the database name + * @param string $view the view name + * @param string $crlf the end of line sequence + * + * @return string resulting definition + */ + function getTableDefStandIn($db, $view, $crlf) + { + $text_output = ''; + + /** + * Get the unique keys in the table + */ + $unique_keys = array(); + $keys = $GLOBALS['dbi']->getTableIndexes($db, $view); + foreach ($keys as $key) { + if ($key['Non_unique'] == 0) { + $unique_keys[] = $key['Column_name']; + } + } + + /** + * Gets fields properties + */ + $GLOBALS['dbi']->selectDb($db); + + /** + * Displays the table structure + */ + + $text_output .= "|------\n" + . '|' . __('Column') + . '|' . __('Type') + . '|' . __('Null') + . '|' . __('Default') + . "\n|------\n"; + + $columns = $GLOBALS['dbi']->getColumns($db, $view); + foreach ($columns as $column) { + $text_output .= $this->formatOneColumnDefinition($column, $unique_keys); + $text_output .= "\n"; + } // end foreach + + return $text_output; + } + + /** + * Returns $table's CREATE definition + * + * @param string $db the database name + * @param string $table the table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param bool $do_relation whether to include relation comments + * @param bool $do_comments whether to include the pmadb-style column + * comments as comments in the structure; + * this is deprecated but the parameter is + * left here because export.php calls + * $this->exportStructure() also for other + * export types which use this parameter + * @param bool $do_mime whether to include mime comments + * @param bool $show_dates whether to include creation/update/check dates + * @param bool $add_semicolon whether to add semicolon and end-of-line + * at the end + * @param bool $view whether we're handling a view + * + * @return string resulting schema + */ + function getTableDef( + $db, + $table, + $crlf, + $error_url, + $do_relation, + $do_comments, + $do_mime, + $show_dates = false, + $add_semicolon = true, + $view = false + ) { + global $cfgRelation; + + $text_output = ''; + + /** + * Get the unique keys in the table + */ + $unique_keys = array(); + $keys = $GLOBALS['dbi']->getTableIndexes($db, $table); + foreach ($keys as $key) { + if ($key['Non_unique'] == 0) { + $unique_keys[] = $key['Column_name']; + } + } + + /** + * Gets fields properties + */ + $GLOBALS['dbi']->selectDb($db); + + // Check if we can use Relations + if ($do_relation && ! empty($cfgRelation['relation'])) { + // Find which tables are related with the current one and write it in + // an array + $res_rel = PMA_getForeigners($db, $table); + + if ($res_rel && count($res_rel) > 0) { + $have_rel = true; + } else { + $have_rel = false; + } + } else { + $have_rel = false; + } // end if + + /** + * Displays the table structure + */ + + $columns_cnt = 4; + if ($do_relation && $have_rel) { + $columns_cnt++; + } + if ($do_comments && $cfgRelation['commwork']) { + $columns_cnt++; + } + if ($do_mime && $cfgRelation['mimework']) { + $columns_cnt++; + } + + $text_output .= "|------\n"; + $text_output .= '|' . __('Column'); + $text_output .= '|' . __('Type'); + $text_output .= '|' . __('Null'); + $text_output .= '|' . __('Default'); + if ($do_relation && $have_rel) { + $text_output .= '|' . __('Links to'); + } + if ($do_comments) { + $text_output .= '|' . __('Comments'); + $comments = PMA_getComments($db, $table); + } + if ($do_mime && $cfgRelation['mimework']) { + $text_output .= '|' . htmlspecialchars('MIME'); + $mime_map = PMA_getMIME($db, $table, true); + } + $text_output .= "\n|------\n"; + + $columns = $GLOBALS['dbi']->getColumns($db, $table); + foreach ($columns as $column) { + $text_output .= $this->formatOneColumnDefinition($column, $unique_keys); + $field_name = $column['Field']; + + if ($do_relation && $have_rel) { + $text_output .= '|' + . (isset($res_rel[$field_name]) + ? htmlspecialchars( + $res_rel[$field_name]['foreign_table'] + . ' (' . $res_rel[$field_name]['foreign_field'] . ')' + ) + : ''); + } + if ($do_comments && $cfgRelation['commwork']) { + $text_output .= '|' + . (isset($comments[$field_name]) + ? htmlspecialchars($comments[$field_name]) + : ''); + } + if ($do_mime && $cfgRelation['mimework']) { + $text_output .= '|' + . (isset($mime_map[$field_name]) + ? htmlspecialchars( + str_replace('_', '/', $mime_map[$field_name]['mimetype']) + ) + : ''); + } + + $text_output .= "\n"; + } // end foreach + + return $text_output; + } // end of the '$this->getTableDef()' function + + /** + * Outputs triggers + * + * @param string $db database name + * @param string $table table name + * + * @return string Formatted triggers list + */ + function getTriggers($db, $table) + { + $text_output = "|------\n"; + $text_output .= '|' . __('Column'); + $dump = "|------\n"; + $dump .= '|' . __('Name'); + $dump .= '|' . __('Time'); + $dump .= '|' . __('Event'); + $dump .= '|' . __('Definition'); + $dump .= "\n|------\n"; + + $triggers = $GLOBALS['dbi']->getTriggers($db, $table); + + foreach ($triggers as $trigger) { + $dump .= '|' . $trigger['name']; + $dump .= '|' . $trigger['action_timing']; + $dump .= '|' . $trigger['event_manipulation']; + $dump .= '|' . + str_replace( + '|', + '|', + htmlspecialchars($trigger['definition']) + ); + $dump .= "\n"; + } + + return $dump; + } + + /** + * Outputs table's structure + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $export_mode 'create_table', 'triggers', 'create_view', + * 'stand_in' + * @param string $export_type 'server', 'database', 'table' + * @param bool $do_relation whether to include relation comments + * @param bool $do_comments whether to include the pmadb-style column + * comments as comments in the structure; + * this is deprecated but the parameter is + * left here because export.php calls + * $this->exportStructure() also for other + * export types which use this parameter + * @param bool $do_mime whether to include mime comments + * @param bool $dates whether to include creation/update/check dates + * + * @return bool Whether it succeeded + */ + function exportStructure( + $db, + $table, + $crlf, + $error_url, + $export_mode, + $export_type, + $do_relation = false, + $do_comments = false, + $do_mime = false, + $dates = false + ) { + $dump = ''; + + switch($export_mode) { + case 'create_table': + $dump .= '== ' . __('Table structure for table') . ' ' .$table . "\n\n"; + $dump .= $this->getTableDef( + $db, $table, $crlf, $error_url, $do_relation, $do_comments, + $do_mime, $dates + ); + break; + case 'triggers': + $dump = ''; + $triggers = $GLOBALS['dbi']->getTriggers($db, $table); + if ($triggers) { + $dump .= '== ' . __('Triggers') . ' ' .$table . "\n\n"; + $dump .= $this->getTriggers($db, $table); + } + break; + case 'create_view': + $dump .= '== ' . __('Structure for view') . ' ' .$table . "\n\n"; + $dump .= $this->getTableDef( + $db, $table, $crlf, $error_url, $do_relation, $do_comments, + $do_mime, $dates, true, true + ); + break; + case 'stand_in': + $dump .= '== ' . __('Stand-in structure for view') + . ' ' .$table . "\n\n"; + // export a stand-in definition to resolve view dependencies + $dump .= $this->getTableDefStandIn($db, $table, $crlf); + } // end switch + + return PMA_exportOutputHandler($dump); + } + + /** + * Formats the definition for one column + * + * @param array $column info about this column + * @param array $unique_keys unique keys for this table + * + * @return string Formatted column definition + */ + function formatOneColumnDefinition( + $column, $unique_keys + ) { + $extracted_columnspec + = PMA_Util::extractColumnSpec($column['Type']); + $type = $extracted_columnspec['print_type']; + if (empty($type)) { + $type = ' '; + } + + if (! isset($column['Default'])) { + if ($column['Null'] != 'NO') { + $column['Default'] = 'NULL'; + } + } + + $fmt_pre = ''; + $fmt_post = ''; + if (in_array($column['Field'], $unique_keys)) { + $fmt_pre = '**' . $fmt_pre; + $fmt_post = $fmt_post . '**'; + } + if ($column['Key']=='PRI') { + $fmt_pre = '//' . $fmt_pre; + $fmt_post = $fmt_post . '//'; + } + $definition = '|' + . $fmt_pre . htmlspecialchars($column['Field']) . $fmt_post; + $definition .= '|' . htmlspecialchars($type); + $definition .= '|' + . (($column['Null'] == '' || $column['Null'] == 'NO') + ? __('No') : __('Yes')); + $definition .= '|' + . htmlspecialchars( + isset($column['Default']) ? $column['Default'] : '' + ); + return $definition; + } +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/export/ExportXml.class.php b/phpMyAdmin/libraries/plugins/export/ExportXml.class.php new file mode 100644 index 0000000..e36b110 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/export/ExportXml.class.php @@ -0,0 +1,546 @@ +setProperties(); + } + + /** + * Initialize the local variables that are used for export PDF + * + * @return void + */ + protected function initSpecificVariables() + { + global $table, $tables; + $this->_setTable($table); + $this->_setTables($tables); + } + + /** + * Sets the export XML properties + * + * @return void + */ + protected function setProperties() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/HiddenPropertyItem.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + + // create the export plugin property item + $exportPluginProperties = new ExportPluginProperties(); + $exportPluginProperties->setText('XML'); + $exportPluginProperties->setExtension('xml'); + $exportPluginProperties->setMimeType('text/xml'); + $exportPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $exportPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create primary items and add them to the group + $leaf = new HiddenPropertyItem(); + $leaf->setName("structure_or_data"); + $generalOptions->addProperty($leaf); + // add the main group to the root group + $exportSpecificOptions->addProperty($generalOptions); + + // export structure main group + $structure = new OptionsPropertyMainGroup(); + $structure->setName("structure"); + $structure->setText(__('Object creation options (all are recommended)')); + // create primary items and add them to the group + if (! PMA_DRIZZLE) { + $leaf = new BoolPropertyItem(); + $leaf->setName("export_functions"); + $leaf->setText(__('Functions')); + $structure->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName("export_procedures"); + $leaf->setText(__('Procedures')); + $structure->addProperty($leaf); + } + $leaf = new BoolPropertyItem(); + $leaf->setName("export_tables"); + $leaf->setText(__('Tables')); + $structure->addProperty($leaf); + if (! PMA_DRIZZLE) { + $leaf = new BoolPropertyItem(); + $leaf->setName("export_triggers"); + $leaf->setText(__('Triggers')); + $structure->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName("export_views"); + $leaf->setText(__('Views')); + $structure->addProperty($leaf); + } + $exportSpecificOptions->addProperty($structure); + + // data main group + $data = new OptionsPropertyMainGroup(); + $data->setName("data"); + $data->setText(__('Data dump options')); + // create primary items and add them to the group + $leaf = new BoolPropertyItem(); + $leaf->setName("export_contents"); + $leaf->setText(__('Export contents')); + $data->addProperty($leaf); + $exportSpecificOptions->addProperty($data); + + // set the options for the export plugin property item + $exportPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $exportPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Outputs export header. It is the first method to be called, so all + * the required variables are initialized here. + * + * @return bool Whether it succeeded + */ + public function exportHeader () + { + $this->initSpecificVariables(); + global $crlf, $cfg, $db; + $table = $this->_getTable(); + $tables = $this->_getTables(); + + $export_struct = isset($GLOBALS['xml_export_functions']) + || isset($GLOBALS['xml_export_procedures']) + || isset($GLOBALS['xml_export_tables']) + || isset($GLOBALS['xml_export_triggers']) + || isset($GLOBALS['xml_export_views']); + $export_data = isset($GLOBALS['xml_export_contents']) ? true : false; + + if ($GLOBALS['output_charset_conversion']) { + $charset = $GLOBALS['charset_of_file']; + } else { + $charset = 'utf-8'; + } + + $head = '' . $crlf + . '' . $crlf . $crlf; + + $head .= '' . $crlf; + + if ($export_struct) { + if (PMA_DRIZZLE) { + $result = $GLOBALS['dbi']->fetchResult( + "SELECT + 'utf8' AS DEFAULT_CHARACTER_SET_NAME, + DEFAULT_COLLATION_NAME + FROM data_dictionary.SCHEMAS + WHERE SCHEMA_NAME = '" + . PMA_Util::sqlAddSlashes($db) . "'" + ); + } else { + $result = $GLOBALS['dbi']->fetchResult( + 'SELECT `DEFAULT_CHARACTER_SET_NAME`, `DEFAULT_COLLATION_NAME`' + . ' FROM `information_schema`.`SCHEMATA` WHERE `SCHEMA_NAME`' + . ' = \''.PMA_Util::sqlAddSlashes($db).'\' LIMIT 1' + ); + } + $db_collation = $result[0]['DEFAULT_COLLATION_NAME']; + $db_charset = $result[0]['DEFAULT_CHARACTER_SET_NAME']; + + $head .= ' ' . $crlf; + $head .= ' ' . $crlf; + $head .= ' ' . $crlf; + + if (count($tables) == 0) { + $tables[] = $table; + } + + foreach ($tables as $table) { + // Export tables and views + $result = $GLOBALS['dbi']->fetchResult( + 'SHOW CREATE TABLE ' . PMA_Util::backquote($db) . '.' + . PMA_Util::backquote($table), + 0 + ); + $tbl = $result[$table][1]; + + $is_view = PMA_Table::isView($db, $table); + + if ($is_view) { + $type = 'view'; + } else { + $type = 'table'; + } + + if ($is_view && ! isset($GLOBALS['xml_export_views'])) { + continue; + } + + if (! $is_view && ! isset($GLOBALS['xml_export_tables'])) { + continue; + } + + $head .= ' ' + . $crlf; + + $tbl = " " . htmlspecialchars($tbl); + $tbl = str_replace("\n", "\n ", $tbl); + + $head .= $tbl . ';' . $crlf; + $head .= ' ' . $crlf; + + if (isset($GLOBALS['xml_export_triggers']) + && $GLOBALS['xml_export_triggers'] + ) { + // Export triggers + $triggers = $GLOBALS['dbi']->getTriggers($db, $table); + if ($triggers) { + foreach ($triggers as $trigger) { + $code = $trigger['create']; + $head .= ' ' . $crlf; + + // Do some formatting + $code = substr(rtrim($code), 0, -3); + $code = " " . htmlspecialchars($code); + $code = str_replace("\n", "\n ", $code); + + $head .= $code . $crlf; + $head .= ' ' . $crlf; + } + + unset($trigger); + unset($triggers); + } + } + } + + if (isset($GLOBALS['xml_export_functions']) + && $GLOBALS['xml_export_functions'] + ) { + // Export functions + $functions = $GLOBALS['dbi']->getProceduresOrFunctions( + $db, 'FUNCTION' + ); + if ($functions) { + foreach ($functions as $function) { + $head .= ' ' . $crlf; + + // Do some formatting + $sql = $GLOBALS['dbi']->getDefinition( + $db, 'FUNCTION', $function + ); + $sql = rtrim($sql); + $sql = " " . htmlspecialchars($sql); + $sql = str_replace("\n", "\n ", $sql); + + $head .= $sql . $crlf; + $head .= ' ' . $crlf; + } + + unset($function); + unset($functions); + } + } + + if (isset($GLOBALS['xml_export_procedures']) + && $GLOBALS['xml_export_procedures'] + ) { + // Export procedures + $procedures = $GLOBALS['dbi']->getProceduresOrFunctions( + $db, 'PROCEDURE' + ); + if ($procedures) { + foreach ($procedures as $procedure) { + $head .= ' ' . $crlf; + + // Do some formatting + $sql = $GLOBALS['dbi']->getDefinition( + $db, 'PROCEDURE', $procedure + ); + $sql = rtrim($sql); + $sql = " " . htmlspecialchars($sql); + $sql = str_replace("\n", "\n ", $sql); + + $head .= $sql . $crlf; + $head .= ' ' . $crlf; + } + + unset($procedure); + unset($procedures); + } + } + + unset($result); + + $head .= ' ' . $crlf; + $head .= ' ' . $crlf; + + if ($export_data) { + $head .= $crlf; + } + } + + return PMA_exportOutputHandler($head); + } + + /** + * Outputs export footer + * + * @return bool Whether it succeeded + */ + public function exportFooter () + { + $foot = ''; + + return PMA_exportOutputHandler($foot); + } + + /** + * Outputs database header + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + global $crlf; + + if (isset($GLOBALS['xml_export_contents']) + && $GLOBALS['xml_export_contents'] + ) { + $head = ' ' . $crlf + . ' ' . $crlf; + + return PMA_exportOutputHandler($head); + } else { + return true; + } + } + + /** + * Outputs database footer + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBFooter ($db) + { + global $crlf; + + if (isset($GLOBALS['xml_export_contents']) + && $GLOBALS['xml_export_contents'] + ) { + return PMA_exportOutputHandler(' ' . $crlf); + } else { + return true; + } + } + + /** + * Outputs CREATE DATABASE statement + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + return true; + } + + /** + * Outputs the content of a table in XML format + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $sql_query SQL query for obtaining data + * + * @return bool Whether it succeeded + */ + public function exportData ($db, $table, $crlf, $error_url, $sql_query) + { + if (isset($GLOBALS['xml_export_contents']) + && $GLOBALS['xml_export_contents'] + ) { + $result = $GLOBALS['dbi']->query( + $sql_query, null, PMA_DatabaseInterface::QUERY_UNBUFFERED + ); + + $columns_cnt = $GLOBALS['dbi']->numFields($result); + $columns = array(); + for ($i = 0; $i < $columns_cnt; $i++) { + $columns[$i] = stripslashes($GLOBALS['dbi']->fieldName($result, $i)); + } + unset($i); + + $buffer = ' ' . $crlf; + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + + while ($record = $GLOBALS['dbi']->fetchRow($result)) { + $buffer = ' ' . $crlf; + for ($i = 0; $i < $columns_cnt; $i++) { + // If a cell is NULL, still export it to preserve + // the XML structure + if (! isset($record[$i]) || is_null($record[$i])) { + $record[$i] = 'NULL'; + } + $buffer .= ' ' + . htmlspecialchars((string)$record[$i]) + . '' . $crlf; + } + $buffer .= '
    ' . $crlf; + + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + } + $GLOBALS['dbi']->freeResult($result); + } + + return true; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the table name + * + * @return string + */ + private function _getTable() + { + return $this->_table; + } + + /** + * Sets the table name + * + * @param string $table table name + * + * @return void + */ + private function _setTable($table) + { + $this->_table = $table; + } + + /** + * Gets the table names + * + * @return array + */ + private function _getTables() + { + return $this->_tables; + } + + /** + * Sets the table names + * + * @param array $tables table names + * + * @return void + */ + private function _setTables($tables) + { + $this->_tables = $tables; + } +} +?> diff --git a/phpMyAdmin/libraries/plugins/export/ExportYaml.class.php b/phpMyAdmin/libraries/plugins/export/ExportYaml.class.php new file mode 100644 index 0000000..a59fb35 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/export/ExportYaml.class.php @@ -0,0 +1,216 @@ +setProperties(); + } + + /** + * Sets the export YAML properties + * + * @return void + */ + protected function setProperties() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ExportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/HiddenPropertyItem.class.php"; + + $exportPluginProperties = new ExportPluginProperties(); + $exportPluginProperties->setText('YAML'); + $exportPluginProperties->setExtension('yml'); + $exportPluginProperties->setMimeType('text/yaml'); + $exportPluginProperties->setForceFile(true); + $exportPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $exportPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create primary items and add them to the group + $leaf = new HiddenPropertyItem(); + $leaf->setName("structure_or_data"); + $generalOptions->addProperty($leaf); + // add the main group to the root group + $exportSpecificOptions->addProperty($generalOptions); + + // set the options for the export plugin property item + $exportPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $exportPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Outputs export header + * + * @return bool Whether it succeeded + */ + public function exportHeader () + { + PMA_exportOutputHandler( + '%YAML 1.1' . $GLOBALS['crlf'] . '---' . $GLOBALS['crlf'] + ); + return true; + } + + /** + * Outputs export footer + * + * @return bool Whether it succeeded + */ + public function exportFooter () + { + PMA_exportOutputHandler('...' . $GLOBALS['crlf']); + return true; + } + + /** + * Outputs database header + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + return true; + } + + /** + * Outputs database footer + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBFooter ($db) + { + return true; + } + + /** + * Outputs CREATE DATABASE statement + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + return true; + } + + /** + * Outputs the content of a table in JSON format + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $sql_query SQL query for obtaining data + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + $result = $GLOBALS['dbi']->query( + $sql_query, null, PMA_DatabaseInterface::QUERY_UNBUFFERED + ); + + $columns_cnt = $GLOBALS['dbi']->numFields($result); + for ($i = 0; $i < $columns_cnt; $i++) { + $columns[$i] = stripslashes($GLOBALS['dbi']->fieldName($result, $i)); + } + unset($i); + + $buffer = ''; + $record_cnt = 0; + while ($record = $GLOBALS['dbi']->fetchRow($result)) { + $record_cnt++; + + // Output table name as comment if this is the first record of the table + if ($record_cnt == 1) { + $buffer = '# ' . $db . '.' . $table . $crlf; + $buffer .= '-' . $crlf; + } else { + $buffer = '-' . $crlf; + } + + for ($i = 0; $i < $columns_cnt; $i++) { + if (! isset($record[$i])) { + continue; + } + + $column = $columns[$i]; + + if (is_null($record[$i])) { + $buffer .= ' ' . $column . ': null' . $crlf; + continue; + } + + if (is_numeric($record[$i])) { + $buffer .= ' ' . $column . ': ' . $record[$i] . $crlf; + continue; + } + + $record[$i] = str_replace( + array('\\', '"', "\n", "\r"), + array('\\\\', '\"', '\n', '\r'), + $record[$i] + ); + $buffer .= ' ' . $column . ': "' . $record[$i] . '"' . $crlf; + } + + if (! PMA_exportOutputHandler($buffer)) { + return false; + } + } + $GLOBALS['dbi']->freeResult($result); + + return true; + } // end getTableYAML +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/export/PMA_ExportPdf.class.php b/phpMyAdmin/libraries/plugins/export/PMA_ExportPdf.class.php new file mode 100644 index 0000000..29c823d --- /dev/null +++ b/phpMyAdmin/libraries/plugins/export/PMA_ExportPdf.class.php @@ -0,0 +1,426 @@ +y; + } + $current_page = $this->page; + if ((($y + $h) > $this->PageBreakTrigger) + AND (! $this->InFooter) + AND ($this->AcceptPageBreak()) + ) { + if ($addpage) { + //Automatic page break + $x = $this->x; + $this->AddPage($this->CurOrientation); + $this->y = $this->dataY; + $oldpage = $this->page - 1; + + $this_page_orm = $this->pagedim[$this->page]['orm']; + $old_page_orm = $this->pagedim[$oldpage]['orm']; + $this_page_olm = $this->pagedim[$this->page]['olm']; + $old_page_olm = $this->pagedim[$oldpage]['olm']; + if ($this->rtl) { + if ($this_page_orm!= $old_page_orm) { + $this->x = $x - ($this_page_orm - $old_page_orm); + } else { + $this->x = $x; + } + } else { + if ($this_page_olm != $old_page_olm) { + $this->x = $x + ($this_page_olm - $old_page_olm); + } else { + $this->x = $x; + } + } + } + return true; + } + if ($current_page != $this->page) { + // account for columns mode + return true; + } + return false; + } + + /** + * This method is used to render the page header. + * + * @return void + */ + function Header() + { + global $maxY; + // We don't want automatic page breaks while generating header + // as this can lead to infinite recursion as auto generated page + // will want header as well causing another page break + // FIXME: Better approach might be to try to compact the content + $this->SetAutoPageBreak(false); + // Check if header for this page already exists + if (! isset($this->headerset[$this->page])) { + $fullwidth = 0; + foreach ($this->tablewidths as $width) { + $fullwidth += $width; + } + $this->SetY(($this->tMargin) - ($this->FontSizePt / $this->k) * 5); + $this->cellFontSize = $this->FontSizePt ; + $this->SetFont( + PMA_PDF_FONT, + '', + ($this->titleFontSize + ? $this->titleFontSize + : $this->FontSizePt) + ); + $this->Cell(0, $this->FontSizePt, $this->titleText, 0, 1, 'C'); + $this->SetFont(PMA_PDF_FONT, '', $this->cellFontSize); + $this->SetY(($this->tMargin) - ($this->FontSizePt / $this->k) * 2.5); + $this->Cell( + 0, + $this->FontSizePt, + __('Database:') . ' ' . $this->currentDb . ', ' + . __('Table:') . ' ' . $this->currentTable, + 0, 1, 'L' + ); + $l = ($this->lMargin); + foreach ($this->colTitles as $col => $txt) { + $this->SetXY($l, ($this->tMargin)); + $this->MultiCell( + $this->tablewidths[$col], + $this->FontSizePt, + $txt + ); + $l += $this->tablewidths[$col] ; + $maxY = ($maxY < $this->getY()) ? $this->getY() : $maxY ; + } + $this->SetXY($this->lMargin, $this->tMargin); + $this->setFillColor(200, 200, 200); + $l = ($this->lMargin); + foreach ($this->colTitles as $col => $txt) { + $this->SetXY($l, $this->tMargin); + $this->cell( + $this->tablewidths[$col], + $maxY-($this->tMargin), + '', + 1, + 0, + 'L', + 1 + ); + $this->SetXY($l, $this->tMargin); + $this->MultiCell( + $this->tablewidths[$col], + $this->FontSizePt, + $txt, + 0, + 'C' + ); + $l += $this->tablewidths[$col]; + } + $this->setFillColor(255, 255, 255); + // set headerset + $this->headerset[$this->page] = 1; + } + + $this->dataY = $maxY; + $this->SetAutoPageBreak(true); + } + + /** + * Generate table + * + * @param int $lineheight Height of line + * + * @return void + */ + function morepagestable($lineheight = 8) + { + // some things to set and 'remember' + $l = $this->lMargin; + $startheight = $h = $this->dataY; + $startpage = $currpage = $this->page; + + // calculate the whole width + $fullwidth = 0; + foreach ($this->tablewidths as $width) { + $fullwidth += $width; + } + + // Now let's start to write the table + $row = 0; + $tmpheight = array(); + $maxpage = $this->page; + + while ($data = $GLOBALS['dbi']->fetchRow($this->results)) { + $this->page = $currpage; + // write the horizontal borders + $this->Line($l, $h, $fullwidth+$l, $h); + // write the content and remember the height of the highest col + foreach ($data as $col => $txt) { + $this->page = $currpage; + $this->SetXY($l, $h); + if ($this->tablewidths[$col] > 0) { + $this->MultiCell( + $this->tablewidths[$col], + $lineheight, + $txt, + 0, + $this->colAlign[$col] + ); + $l += $this->tablewidths[$col]; + } + + if (! isset($tmpheight[$row.'-'.$this->page])) { + $tmpheight[$row.'-'.$this->page] = 0; + } + if ($tmpheight[$row.'-'.$this->page] < $this->GetY()) { + $tmpheight[$row.'-'.$this->page] = $this->GetY(); + } + if ($this->page > $maxpage) { + $maxpage = $this->page; + } + unset($data[$col]); + } + + // get the height we were in the last used page + $h = $tmpheight[$row.'-'.$maxpage]; + // set the "pointer" to the left margin + $l = $this->lMargin; + // set the $currpage to the last page + $currpage = $maxpage; + unset($data[$row]); + $row++; + } + // draw the borders + // we start adding a horizontal line on the last page + $this->page = $maxpage; + $this->Line($l, $h, $fullwidth+$l, $h); + // now we start at the top of the document and walk down + for ($i = $startpage; $i <= $maxpage; $i++) { + $this->page = $i; + $l = $this->lMargin; + $t = ($i == $startpage) ? $startheight : $this->tMargin; + $lh = ($i == $maxpage) ? $h : $this->h-$this->bMargin; + $this->Line($l, $t, $l, $lh); + foreach ($this->tablewidths as $width) { + $l += $width; + $this->Line($l, $t, $l, $lh); + } + } + // set it to the last page, if not it'll cause some problems + $this->page = $maxpage; + } + + /** + * Sets a set of attributes. + * + * @param array $attr array containing the attributes + * + * @return void + */ + function setAttributes($attr = array()) + { + foreach ($attr as $key => $val) { + $this->$key = $val ; + } + } + + /** + * Defines the top margin. + * The method can be called before creating the first page. + * + * @param float $topMargin the margin + * + * @return void + */ + function setTopMargin($topMargin) + { + $this->tMargin = $topMargin; + } + + /** + * MySQL report + * + * @param string $query Query to execute + * + * @return void + */ + function mysqlReport($query) + { + unset($this->tablewidths); + unset($this->colTitles); + unset($this->titleWidth); + unset($this->colFits); + unset($this->display_column); + unset($this->colAlign); + + /** + * Pass 1 for column widths + */ + $this->results = $GLOBALS['dbi']->query( + $query, null, PMA_DatabaseInterface::QUERY_UNBUFFERED + ); + $this->numFields = $GLOBALS['dbi']->numFields($this->results); + $this->fields = $GLOBALS['dbi']->getFieldsMeta($this->results); + + // sColWidth = starting col width (an average size width) + $availableWidth = $this->w - $this->lMargin - $this->rMargin; + $this->sColWidth = $availableWidth / $this->numFields; + $totalTitleWidth = 0; + + // loop through results header and set initial + // col widths/ titles/ alignment + // if a col title is less than the starting col width, + // reduce that column size + $colFits = array(); + for ($i = 0; $i < $this->numFields; $i++) { + $stringWidth = $this->getstringwidth($this->fields[$i]->name) + 6 ; + // save the real title's width + $titleWidth[$i] = $stringWidth; + $totalTitleWidth += $stringWidth; + + // set any column titles less than the start width to + // the column title width + if ($stringWidth < $this->sColWidth) { + $colFits[$i] = $stringWidth ; + } + $this->colTitles[$i] = $this->fields[$i]->name; + $this->display_column[$i] = true; + + switch ($this->fields[$i]->type) { + case 'int': + $this->colAlign[$i] = 'R'; + break; + case 'blob': + case 'tinyblob': + case 'mediumblob': + case 'longblob': + /** + * @todo do not deactivate completely the display + * but show the field's name and [BLOB] + */ + if (stristr($this->fields[$i]->flags, 'BINARY')) { + $this->display_column[$i] = false; + unset($this->colTitles[$i]); + } + $this->colAlign[$i] = 'L'; + break; + default: + $this->colAlign[$i] = 'L'; + } + } + + // title width verification + if ($totalTitleWidth > $availableWidth) { + $adjustingMode = true; + } else { + $adjustingMode = false; + // we have enough space for all the titles at their + // original width so use the true title's width + foreach ($titleWidth as $key => $val) { + $colFits[$key] = $val; + } + } + + // loop through the data; any column whose contents + // is greater than the column size is resized + /** + * @todo force here a LIMIT to avoid reading all rows + */ + while ($row = $GLOBALS['dbi']->fetchRow($this->results)) { + foreach ($colFits as $key => $val) { + $stringWidth = $this->getstringwidth($row[$key]) + 6 ; + if ($adjustingMode && ($stringWidth > $this->sColWidth)) { + // any column whose data's width is bigger than + // the start width is now discarded + unset($colFits[$key]); + } else { + // if data's width is bigger than the current column width, + // enlarge the column (but avoid enlarging it if the + // data's width is very big) + if ($stringWidth > $val + && $stringWidth < ($this->sColWidth * 3) + ) { + $colFits[$key] = $stringWidth ; + } + } + } + } + + $totAlreadyFitted = 0; + foreach ($colFits as $key => $val) { + // set fitted columns to smallest size + $this->tablewidths[$key] = $val; + // to work out how much (if any) space has been freed up + $totAlreadyFitted += $val; + } + + if ($adjustingMode) { + $surplus = (sizeof($colFits) * $this->sColWidth) - $totAlreadyFitted; + $surplusToAdd = $surplus / ($this->numFields - sizeof($colFits)); + } else { + $surplusToAdd = 0; + } + + for ($i = 0; $i < $this->numFields; $i++) { + if (! in_array($i, array_keys($colFits))) { + $this->tablewidths[$i] = $this->sColWidth + $surplusToAdd; + } + if ($this->display_column[$i] == false) { + $this->tablewidths[$i] = 0; + } + } + + ksort($this->tablewidths); + + $GLOBALS['dbi']->freeResult($this->results); + + // Pass 2 + + $this->results = $GLOBALS['dbi']->query( + $query, null, PMA_DatabaseInterface::QUERY_UNBUFFERED + ); + $this->setY($this->tMargin); + $this->AddPage(); + $this->SetFont(PMA_PDF_FONT, '', 9); + $this->morepagestable($this->FontSizePt); + $GLOBALS['dbi']->freeResult($this->results); + + } // end of mysqlReport function + +} // end of PMA_Export_PDF class +?> diff --git a/phpMyAdmin/libraries/plugins/export/README b/phpMyAdmin/libraries/plugins/export/README new file mode 100644 index 0000000..68d5a26 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/export/README @@ -0,0 +1,276 @@ +This directory holds export plugins for phpMyAdmin. Any new plugin should +basically follow the structure presented here. Official plugins need to +have str* messages with their definition in language files, but if you build +some plugins for your use, you can directly use texts in plugin. + +setProperties(); + } + + // optional - declare global variables and use getters later + /** + * Initialize the local variables that are used specific for export SQL + * + * @global type $global_variable_name + * [..] + * + * @return void + */ + protected function initSpecificVariables() + { + global $global_variable_name; + $this->_setGlobalVariableName($global_variable_name); + } + + /** + * Sets the export plugin properties. + * Called in the constructor. + * + * @return void + */ + protected function setProperties() + { + // set properties + $props = 'libraries/properties/'; + // include the main class for properties for the export plug-ins + include_once "$props/plugins/ExportPluginProperties.class.php"; + // include the group properties classes + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + // include the needed single property items + include_once "$props/options/items/RadioPropertyItem.class.php"; + + $exportPluginProperties = new ExportPluginProperties(); + $exportPluginProperties->setText('[name]'); // the name of your plug-in + $exportPluginProperties->setExtension('[ext]'); // extension this plug-in can handle + $exportPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $exportPluginProperties + // this will be shown as "Format specific options" + $exportSpecificOptions = new OptionsPropertyRootGroup(); + $exportSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + + // optional : + // create primary items and add them to the group + // type - one of the classes listed in libraries/properties/options/items/ + // name - form element name + // text - description in GUI + // size - size of text element + // len - maximal size of input + // values - possible values of the item + $leaf = new RadioPropertyItem(); + $leaf->setName("structure_or_data"); + $leaf->setValues( + array( + 'structure' => __('structure'), + 'data' => __('data'), + 'structure_and_data' => __('structure and data') + ) + ); + $generalOptions->addProperty($leaf); + + // add the main group to the root group + $exportSpecificOptions->addProperty($generalOptions); + + // set the options for the export plugin property item + $exportPluginProperties->setOptions($exportSpecificOptions); + $this->properties = $exportPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Outputs export header + * + * @return bool Whether it succeeded + */ + public function exportHeader () + { + // implementation + return true; + } + + /** + * Outputs export footer + * + * @return bool Whether it succeeded + */ + public function exportFooter () + { + // implementation + return true; + } + + /** + * Outputs database header + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBHeader ($db) + { + // implementation + return true; + } + + /** + * Outputs database footer + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBFooter ($db) + { + // implementation + return true; + } + + /** + * Outputs CREATE DATABASE statement + * + * @param string $db Database name + * + * @return bool Whether it succeeded + */ + public function exportDBCreate($db) + { + // implementation + return true; + } + + /** + * Outputs the content of a table in [Name] format + * + * @param string $db database name + * @param string $table table name + * @param string $crlf the end of line sequence + * @param string $error_url the url to go back in case of error + * @param string $sql_query SQL query for obtaining data + * + * @return bool Whether it succeeded + */ + public function exportData($db, $table, $crlf, $error_url, $sql_query) + { + // implementation; + return true; + } + + // optional - implement other methods defined in ExportPlugin.class.php: + // - exportRoutines() + // - exportStructure() + // - getTableDefStandIn() + // - getTriggers() + + // optional - implement other private methods in order to avoid + // having huge methods or avoid duplicate code. Make use of them + // as well as of the getters and setters declared both here + // and in the ExportPlugin class + + + // optional: + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Getter description + * + * @return type + */ + private function _getMyOptionalVariable() + { + return $this->_myOptionalVariable; + } + + /** + * Setter description + * + * @param type $my_optional_variable description + * + * @return void + */ + private function _setMyOptionalVariable($my_optional_variable) + { + $this->_myOptionalVariable = $my_optional_variable; + } + + /** + * Getter description + * + * @return type + */ + private function _getGlobalVariableName() + { + return $this->_globalVariableName; + } + + /** + * Setter description + * + * @param type $global_variable_name description + * + * @return void + */ + private function _setGlobalVariableName($global_variable_name) + { + $this->_globalVariableName = $global_variable_name; + } +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/export/TableProperty.class.php b/phpMyAdmin/libraries/plugins/export/TableProperty.class.php new file mode 100644 index 0000000..cf7c6fc --- /dev/null +++ b/phpMyAdmin/libraries/plugins/export/TableProperty.class.php @@ -0,0 +1,286 @@ +name = trim($row[0]); + $this->type = trim($row[1]); + $this->nullable = trim($row[2]); + $this->key = trim($row[3]); + $this->defaultValue = trim($row[4]); + $this->ext = trim($row[5]); + } + + /** + * Gets the pure type + * + * @return string type + */ + function getPureType() + { + $pos = strpos($this->type, "("); + if ($pos > 0) { + return substr($this->type, 0, $pos); + } + return $this->type; + } + + /** + * Tells whether the key is null or not + * + * @return bool true if the key is not null, false otherwise + */ + function isNotNull() + { + return $this->nullable == "NO" ? "true" : "false"; + } + + /** + * Tells whether the key is unique or not + * + * @return bool true if the key is unique, false otherwise + */ + function isUnique() + { + return $this->key == "PRI" || $this->key == "UNI" ? "true" : "false"; + } + + /** + * Gets the .NET primitive type + * + * @return string type + */ + function getDotNetPrimitiveType() + { + if (strpos($this->type, "int") === 0) { + return "int"; + } + if (strpos($this->type, "long") === 0) { + return "long"; + } + if (strpos($this->type, "char") === 0) { + return "string"; + } + if (strpos($this->type, "varchar") === 0) { + return "string"; + } + if (strpos($this->type, "text") === 0) { + return "string"; + } + if (strpos($this->type, "longtext") === 0) { + return "string"; + } + if (strpos($this->type, "tinyint") === 0) { + return "bool"; + } + if (strpos($this->type, "datetime") === 0) { + return "DateTime"; + } + return "unknown"; + } + + /** + * Gets the .NET object type + * + * @return string type + */ + function getDotNetObjectType() + { + if (strpos($this->type, "int") === 0) { + return "Int32"; + } + if (strpos($this->type, "long") === 0) { + return "Long"; + } + if (strpos($this->type, "char") === 0) { + return "String"; + } + if (strpos($this->type, "varchar") === 0) { + return "String"; + } + if (strpos($this->type, "text") === 0) { + return "String"; + } + if (strpos($this->type, "longtext") === 0) { + return "String"; + } + if (strpos($this->type, "tinyint") === 0) { + return "Boolean"; + } + if (strpos($this->type, "datetime") === 0) { + return "DateTime"; + } + return "Unknown"; + } + + /** + * Gets the index name + * + * @return string containing the name of the index + */ + function getIndexName() + { + if (strlen($this->key) > 0) { + return "index=\"" + . htmlspecialchars($this->name, ENT_COMPAT, 'UTF-8') + . "\""; + } + return ""; + } + + /** + * Tells whether the key is primary or not + * + * @return bool true if the key is primary, false otherwise + */ + function isPK() + { + return $this->key=="PRI"; + } + + /** + * Formats a string for C# + * + * @param string $text string to be formatted + * + * @return string formatted text + */ + function formatCs($text) + { + $text = str_replace( + "#name#", + ExportCodegen::cgMakeIdentifier($this->name, false), + $text + ); + return $this->format($text); + } + + /** + * Formats a string for XML + * + * @param string $text string to be formatted + * + * @return string formatted text + */ + function formatXml($text) + { + $text = str_replace( + "#name#", + htmlspecialchars($this->name, ENT_COMPAT, 'UTF-8'), + $text + ); + $text = str_replace( + "#indexName#", + $this->getIndexName(), + $text + ); + return $this->format($text); + } + + /** + * Formats a string + * + * @param string $text string to be formatted + * + * @return string formatted text + */ + function format($text) + { + $text = str_replace( + "#ucfirstName#", + ExportCodegen::cgMakeIdentifier($this->name), + $text + ); + $text = str_replace( + "#dotNetPrimitiveType#", + $this->getDotNetPrimitiveType(), + $text + ); + $text = str_replace( + "#dotNetObjectType#", + $this->getDotNetObjectType(), + $text + ); + $text = str_replace( + "#type#", + $this->getPureType(), + $text + ); + $text = str_replace( + "#notNull#", + $this->isNotNull(), + $text + ); + $text = str_replace( + "#unique#", + $this->isUnique(), + $text + ); + return $text; + } +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/import/AbstractImportCsv.class.php b/phpMyAdmin/libraries/plugins/import/AbstractImportCsv.class.php new file mode 100644 index 0000000..4c72cba --- /dev/null +++ b/phpMyAdmin/libraries/plugins/import/AbstractImportCsv.class.php @@ -0,0 +1,91 @@ +setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $importPluginProperties + // this will be shown as "Format specific options" + $importSpecificOptions = new OptionsPropertyRootGroup(); + $importSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + + // create common items and add them to the group + $leaf = new BoolPropertyItem(); + $leaf->setName("replace"); + $leaf->setText(__('Replace table data with file')); + $generalOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("terminated"); + $leaf->setText(__('Columns separated with:')); + $leaf->setSize(2); + $leaf->setLen(2); + $generalOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("enclosed"); + $leaf->setText(__('Columns enclosed with:')); + $leaf->setSize(2); + $leaf->setLen(2); + $generalOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("escaped"); + $leaf->setText(__('Columns escaped with:')); + $leaf->setSize(2); + $leaf->setLen(2); + $generalOptions->addProperty($leaf); + $leaf = new TextPropertyItem(); + $leaf->setName("new_line"); + $leaf->setText(__('Lines terminated with:')); + $leaf->setSize(2); + $generalOptions->addProperty($leaf); + + // add the main group to the root group + $importSpecificOptions->addProperty($generalOptions); + + // set the options for the import plugin property item + $importPluginProperties->setOptions($importSpecificOptions); + $this->properties = $importPluginProperties; + + return $generalOptions; + } +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/import/ImportCsv.class.php b/phpMyAdmin/libraries/plugins/import/ImportCsv.class.php new file mode 100644 index 0000000..8e067d9 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/import/ImportCsv.class.php @@ -0,0 +1,608 @@ +setProperties(); + } + + /** + * Sets the import plugin properties. + * Called in the constructor. + * + * @return void + */ + protected function setProperties() + { + $this->_setAnalyze(false); + + if ($GLOBALS['plugin_param'] !== 'table') { + $this->_setAnalyze(true); + } + + $generalOptions = parent::setProperties(); + $this->properties->setText('CSV'); + $this->properties->setExtension('csv'); + + if ($GLOBALS['plugin_param'] !== 'table') { + $leaf = new BoolPropertyItem(); + $leaf->setName("col_names"); + $leaf->setText( + __( + 'The first line of the file contains the table column names' + . ' (if this is unchecked, the first line will become part' + . ' of the data)' + ) + ); + $generalOptions->addProperty($leaf); + } else { + $hint = new PMA_Message( + __( + 'If the data in each row of the file is not' + . ' in the same order as in the database, list the corresponding' + . ' column names here. Column names must be separated by commas' + . ' and not enclosed in quotations.' + ) + ); + $leaf = new TextPropertyItem(); + $leaf->setName("columns"); + $leaf->setText( + __('Column names: ') + . PMA_Util::showHint($hint) + ); + $generalOptions->addProperty($leaf); + } + + $leaf = new BoolPropertyItem(); + $leaf->setName("ignore"); + $leaf->setText(__('Do not abort on INSERT error')); + $generalOptions->addProperty($leaf); + + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Handles the whole import logic + * + * @return void + */ + public function doImport() + { + global $db, $table, $csv_terminated, $csv_enclosed, $csv_escaped, + $csv_new_line, $csv_columns, $err_url; + // $csv_replace and $csv_ignore should have been here, + // but we use directly from $_POST + global $error, $timeout_passed, $finished, $message; + + $replacements = array( + '\\n' => "\n", + '\\t' => "\t", + '\\r' => "\r", + ); + $csv_terminated = strtr($csv_terminated, $replacements); + $csv_enclosed = strtr($csv_enclosed, $replacements); + $csv_escaped = strtr($csv_escaped, $replacements); + $csv_new_line = strtr($csv_new_line, $replacements); + + $param_error = false; + if (strlen($csv_terminated) != 1) { + $message = PMA_Message::error( + __('Invalid parameter for CSV import: %s') + ); + $message->addParam(__('Columns terminated with'), false); + $error = true; + $param_error = true; + // The default dialog of MS Excel when generating a CSV produces a + // semi-colon-separated file with no chance of specifying the + // enclosing character. Thus, users who want to import this file + // tend to remove the enclosing character on the Import dialog. + // I could not find a test case where having no enclosing characters + // confuses this script. + // But the parser won't work correctly with strings so we allow just + // one character. + } elseif (strlen($csv_enclosed) > 1) { + $message = PMA_Message::error( + __('Invalid parameter for CSV import: %s') + ); + $message->addParam(__('Columns enclosed with'), false); + $error = true; + $param_error = true; + } elseif (strlen($csv_escaped) != 1) { + $message = PMA_Message::error( + __('Invalid parameter for CSV import: %s') + ); + $message->addParam(__('Columns escaped with'), false); + $error = true; + $param_error = true; + } elseif (strlen($csv_new_line) != 1 && $csv_new_line != 'auto') { + $message = PMA_Message::error( + __('Invalid parameter for CSV import: %s') + ); + $message->addParam(__('Lines terminated with'), false); + $error = true; + $param_error = true; + } + + // If there is an error in the parameters entered, + // indicate that immediately. + if ($param_error) { + PMA_Util::mysqlDie($message->getMessage(), '', '', $err_url); + } + + $buffer = ''; + $required_fields = 0; + + if (! $this->_getAnalyze()) { + if (isset($_POST['csv_replace'])) { + $sql_template = 'REPLACE'; + } else { + $sql_template = 'INSERT'; + if (isset($_POST['csv_ignore'])) { + $sql_template .= ' IGNORE'; + } + } + $sql_template .= ' INTO ' . PMA_Util::backquote($table); + + $tmp_fields = $GLOBALS['dbi']->getColumns($db, $table); + + if (empty($csv_columns)) { + $fields = $tmp_fields; + } else { + $sql_template .= ' ('; + $fields = array(); + $tmp = preg_split('/,( ?)/', $csv_columns); + foreach ($tmp as $key => $val) { + if (count($fields) > 0) { + $sql_template .= ', '; + } + /* Trim also `, if user already included backquoted fields */ + $val = trim($val, " \t\r\n\0\x0B`"); + $found = false; + foreach ($tmp_fields as $field) { + if ($field['Field'] == $val) { + $found = true; + break; + } + } + if (! $found) { + $message = PMA_Message::error( + __( + 'Invalid column (%s) specified! Ensure that columns' + . ' names are spelled correctly, separated by commas' + . ', and not enclosed in quotes.' + ) + ); + $message->addParam($val); + $error = true; + break; + } + $fields[] = $field; + $sql_template .= PMA_Util::backquote($val); + } + $sql_template .= ') '; + } + + $required_fields = count($fields); + + $sql_template .= ' VALUES ('; + } + + // Defaults for parser + $i = 0; + $len = 0; + $lastlen = null; + $line = 1; + $lasti = -1; + $values = array(); + $csv_finish = false; + + $tempRow = array(); + $rows = array(); + $col_names = array(); + $tables = array(); + + $col_count = 0; + $max_cols = 0; + + while (! ($finished && $i >= $len) && ! $error && ! $timeout_passed) { + $data = PMA_importGetNextChunk(); + if ($data === false) { + // subtract data we didn't handle yet and stop processing + $GLOBALS['offset'] -= strlen($buffer); + break; + } elseif ($data === true) { + // Handle rest of buffer + } else { + // Append new data to buffer + $buffer .= $data; + unset($data); + + // Force a trailing new line at EOF to prevent parsing problems + if ($finished && $buffer) { + $finalch = substr($buffer, -1); + if ($csv_new_line == 'auto' + && $finalch != "\r" + && $finalch != "\n" + ) { + $buffer .= "\n"; + } elseif ($csv_new_line != 'auto' + && $finalch != $csv_new_line + ) { + $buffer .= $csv_new_line; + } + } + + // Do not parse string when we're not at the end + // and don't have new line inside + if (($csv_new_line == 'auto' + && strpos($buffer, "\r") === false + && strpos($buffer, "\n") === false) + || ($csv_new_line != 'auto' + && strpos($buffer, $csv_new_line) === false) + ) { + continue; + } + } + + // Current length of our buffer + $len = strlen($buffer); + // Currently parsed char + $ch = $buffer[$i]; + while ($i < $len) { + // Deadlock protection + if ($lasti == $i && $lastlen == $len) { + $message = PMA_Message::error( + __('Invalid format of CSV input on line %d.') + ); + $message->addParam($line); + $error = true; + break; + } + $lasti = $i; + $lastlen = $len; + + // This can happen with auto EOL and \r at the end of buffer + if (! $csv_finish) { + // Grab empty field + if ($ch == $csv_terminated) { + if ($i == $len - 1) { + break; + } + $values[] = ''; + $i++; + $ch = $buffer[$i]; + continue; + } + + // Grab one field + $fallbacki = $i; + if ($ch == $csv_enclosed) { + if ($i == $len - 1) { + break; + } + $need_end = true; + $i++; + $ch = $buffer[$i]; + } else { + $need_end = false; + } + $fail = false; + $value = ''; + while (($need_end + && ( $ch != $csv_enclosed || $csv_enclosed == $csv_escaped )) + || ( ! $need_end + && ! ( $ch == $csv_terminated + || $ch == $csv_new_line + || ( $csv_new_line == 'auto' + && ( $ch == "\r" || $ch == "\n" ) ) ) ) + ) { + if ($ch == $csv_escaped) { + if ($i == $len - 1) { + $fail = true; + break; + } + $i++; + $ch = $buffer[$i]; + if ($csv_enclosed == $csv_escaped + && ($ch == $csv_terminated + || $ch == $csv_new_line + || ($csv_new_line == 'auto' + && ($ch == "\r" || $ch == "\n"))) + ) { + break; + } + } + $value .= $ch; + if ($i == $len - 1) { + if (! $finished) { + $fail = true; + } + break; + } + $i++; + $ch = $buffer[$i]; + } + + // unquoted NULL string + if (false === $need_end && $value === 'NULL') { + $value = null; + } + + if ($fail) { + $i = $fallbacki; + $ch = $buffer[$i]; + break; + } + // Need to strip trailing enclosing char? + if ($need_end && $ch == $csv_enclosed) { + if ($finished && $i == $len - 1) { + $ch = null; + } elseif ($i == $len - 1) { + $i = $fallbacki; + $ch = $buffer[$i]; + break; + } else { + $i++; + $ch = $buffer[$i]; + } + } + // Are we at the end? + if ($ch == $csv_new_line + || ($csv_new_line == 'auto' && ($ch == "\r" || $ch == "\n")) + || ($finished && $i == $len - 1) + ) { + $csv_finish = true; + } + // Go to next char + if ($ch == $csv_terminated) { + if ($i == $len - 1) { + $i = $fallbacki; + $ch = $buffer[$i]; + break; + } + $i++; + $ch = $buffer[$i]; + } + // If everything went okay, store value + $values[] = $value; + } + + // End of line + if ($csv_finish + || $ch == $csv_new_line + || ($csv_new_line == 'auto' && ($ch == "\r" || $ch == "\n")) + ) { + if ($csv_new_line == 'auto' && $ch == "\r") { // Handle "\r\n" + if ($i >= ($len - 2) && ! $finished) { + break; // We need more data to decide new line + } + if ($buffer[$i + 1] == "\n") { + $i++; + } + } + // We didn't parse value till the end of line, so there was + // empty one + if (! $csv_finish) { + $values[] = ''; + } + + if ($this->_getAnalyze()) { + foreach ($values as $val) { + $tempRow[] = $val; + ++$col_count; + } + + if ($col_count > $max_cols) { + $max_cols = $col_count; + } + $col_count = 0; + + $rows[] = $tempRow; + $tempRow = array(); + } else { + // Do we have correct count of values? + if (count($values) != $required_fields) { + + // Hack for excel + if ($values[count($values) - 1] == ';') { + unset($values[count($values) - 1]); + } else { + $message = PMA_Message::error( + __( + 'Invalid column count in CSV input' + . ' on line %d.' + ) + ); + $message->addParam($line); + $error = true; + break; + } + } + + $first = true; + $sql = $sql_template; + foreach ($values as $key => $val) { + if (! $first) { + $sql .= ', '; + } + if ($val === null) { + $sql .= 'NULL'; + } else { + $sql .= '\'' + . PMA_Util::sqlAddSlashes($val) + . '\''; + } + + $first = false; + } + $sql .= ')'; + + /** + * @todo maybe we could add original line to verbose + * SQL in comment + */ + PMA_importRunQuery($sql, $sql); + } + + $line++; + $csv_finish = false; + $values = array(); + $buffer = substr($buffer, $i + 1); + $len = strlen($buffer); + $i = 0; + $lasti = -1; + $ch = $buffer[0]; + } + } // End of parser loop + } // End of import loop + + if ($this->_getAnalyze()) { + /* Fill out all rows */ + $num_rows = count($rows); + for ($i = 0; $i < $num_rows; ++$i) { + for ($j = count($rows[$i]); $j < $max_cols; ++$j) { + $rows[$i][] = 'NULL'; + } + } + + if (isset($_REQUEST['csv_col_names'])) { + $col_names = array_splice($rows, 0, 1); + $col_names = $col_names[0]; + } + + if ((isset($col_names) && count($col_names) != $max_cols) + || ! isset($col_names) + ) { + // Fill out column names + for ($i = 0; $i < $max_cols; ++$i) { + $col_names[] = 'COL '.($i+1); + } + } + + if (strlen($db)) { + $result = $GLOBALS['dbi']->fetchResult('SHOW TABLES'); + $tbl_name = 'TABLE '.(count($result) + 1); + } else { + $tbl_name = 'TBL_NAME'; + } + + $tables[] = array($tbl_name, $col_names, $rows); + + /* Obtain the best-fit MySQL types for each column */ + $analyses = array(); + $analyses[] = PMA_analyzeTable($tables[0]); + + /** + * string $db_name (no backquotes) + * + * array $table = array(table_name, array() column_names, array()() rows) + * array $tables = array of "$table"s + * + * array $analysis = array(array() column_types, array() column_sizes) + * array $analyses = array of "$analysis"s + * + * array $create = array of SQL strings + * + * array $options = an associative array of options + */ + + /* Set database name to the currently selected one, if applicable */ + if (strlen($db)) { + $db_name = $db; + $options = array('create_db' => false); + } else { + $db_name = 'CSV_DB'; + $options = null; + } + + /* Non-applicable parameters */ + $create = null; + + /* Created and execute necessary SQL statements from data */ + PMA_buildSQL($db_name, $tables, $analyses, $create, $options); + + unset($tables); + unset($analyses); + } + + // Commit any possible data in buffers + PMA_importRunQuery(); + + if (count($values) != 0 && ! $error) { + $message = PMA_Message::error( + __('Invalid format of CSV input on line %d.') + ); + $message->addParam($line); + $error = true; + } + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Returns true if the table should be analyzed, false otherwise + * + * @return bool + */ + private function _getAnalyze() + { + return $this->_analyze; + } + + /** + * Sets to true if the table should be analyzed, false otherwise + * + * @param bool $analyze status + * + * @return void + */ + private function _setAnalyze($analyze) + { + $this->_analyze = $analyze; + } +} diff --git a/phpMyAdmin/libraries/plugins/import/ImportLdi.class.php b/phpMyAdmin/libraries/plugins/import/ImportLdi.class.php new file mode 100644 index 0000000..1277938 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/import/ImportLdi.class.php @@ -0,0 +1,174 @@ +setProperties(); + } + + /** + * Sets the import plugin properties. + * Called in the constructor. + * + * @return void + */ + protected function setProperties() + { + if ($GLOBALS['cfg']['Import']['ldi_local_option'] == 'auto') { + $GLOBALS['cfg']['Import']['ldi_local_option'] = false; + + $result = $GLOBALS['dbi']->tryQuery( + 'SHOW VARIABLES LIKE \'local\\_infile\';' + ); + if ($result != false && $GLOBALS['dbi']->numRows($result) > 0) { + $tmp = $GLOBALS['dbi']->fetchRow($result); + if ($tmp[1] == 'ON') { + $GLOBALS['cfg']['Import']['ldi_local_option'] = true; + } + } + $GLOBALS['dbi']->freeResult($result); + unset($result); + } + + $generalOptions = parent::setProperties(); + $this->properties->setText('CSV using LOAD DATA'); + $this->properties->setExtension('ldi'); + + $leaf = new TextPropertyItem(); + $leaf->setName("columns"); + $leaf->setText(__('Column names: ')); + $generalOptions->addProperty($leaf); + + $leaf = new BoolPropertyItem(); + $leaf->setName("ignore"); + $leaf->setText(__('Do not abort on INSERT error')); + $generalOptions->addProperty($leaf); + + $leaf = new BoolPropertyItem(); + $leaf->setName("local_option"); + $leaf->setText(__('Use LOCAL keyword')); + $generalOptions->addProperty($leaf); + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Handles the whole import logic + * + * @return void + */ + public function doImport() + { + global $finished, $import_file, $compression, $charset_conversion, $table; + global $ldi_local_option, $ldi_replace, $ldi_ignore, $ldi_terminated, + $ldi_enclosed, $ldi_escaped, $ldi_new_line, $skip_queries, $ldi_columns; + + if ($import_file == 'none' + || $compression != 'none' + || $charset_conversion + ) { + // We handle only some kind of data! + $GLOBALS['message'] = PMA_Message::error( + __('This plugin does not support compressed imports!') + ); + $GLOBALS['error'] = true; + return; + } + + $sql = 'LOAD DATA'; + if (isset($ldi_local_option)) { + $sql .= ' LOCAL'; + } + $sql .= ' INFILE \'' . PMA_Util::sqlAddSlashes($import_file) . '\''; + if (isset($ldi_replace)) { + $sql .= ' REPLACE'; + } elseif (isset($ldi_ignore)) { + $sql .= ' IGNORE'; + } + $sql .= ' INTO TABLE ' . PMA_Util::backquote($table); + + if (strlen($ldi_terminated) > 0) { + $sql .= ' FIELDS TERMINATED BY \'' . $ldi_terminated . '\''; + } + if (strlen($ldi_enclosed) > 0) { + $sql .= ' ENCLOSED BY \'' + . PMA_Util::sqlAddSlashes($ldi_enclosed) . '\''; + } + if (strlen($ldi_escaped) > 0) { + $sql .= ' ESCAPED BY \'' + . PMA_Util::sqlAddSlashes($ldi_escaped) . '\''; + } + if (strlen($ldi_new_line) > 0) { + if ($ldi_new_line == 'auto') { + $ldi_new_line + = (PMA_Util::whichCrlf() == "\n") + ? '\n' + : '\r\n'; + } + $sql .= ' LINES TERMINATED BY \'' . $ldi_new_line . '\''; + } + if ($skip_queries > 0) { + $sql .= ' IGNORE ' . $skip_queries . ' LINES'; + $skip_queries = 0; + } + if (strlen($ldi_columns) > 0) { + $sql .= ' ('; + $tmp = preg_split('/,( ?)/', $ldi_columns); + $cnt_tmp = count($tmp); + for ($i = 0; $i < $cnt_tmp; $i++) { + if ($i > 0) { + $sql .= ', '; + } + /* Trim also `, if user already included backquoted fields */ + $sql .= PMA_Util::backquote( + trim($tmp[$i], " \t\r\n\0\x0B`") + ); + } // end for + $sql .= ')'; + } + + PMA_importRunQuery($sql, $sql); + PMA_importRunQuery(); + $finished = true; + } +} diff --git a/phpMyAdmin/libraries/plugins/import/ImportMediawiki.class.php b/phpMyAdmin/libraries/plugins/import/ImportMediawiki.class.php new file mode 100644 index 0000000..b7cd3be --- /dev/null +++ b/phpMyAdmin/libraries/plugins/import/ImportMediawiki.class.php @@ -0,0 +1,573 @@ +setProperties(); + } + + /** + * Sets the import plugin properties. + * Called in the constructor. + * + * @return void + */ + protected function setProperties() + { + $this->_setAnalyze(false); + if ($GLOBALS['plugin_param'] !== 'table') { + $this->_setAnalyze(true); + } + + $props = 'libraries/properties/'; + include_once "$props/plugins/ImportPluginProperties.class.php"; + + $importPluginProperties = new ImportPluginProperties(); + $importPluginProperties->setText(__('MediaWiki Table')); + $importPluginProperties->setExtension('txt'); + $importPluginProperties->setMimeType('text/plain'); + $importPluginProperties->setOptions(array()); + $importPluginProperties->setOptionsText(__('Options')); + + $this->properties = $importPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Handles the whole import logic + * + * @return void + */ + public function doImport() + { + global $error, $timeout_passed, $finished; + + // Defaults for parser + + // The buffer that will be used to store chunks read from the imported file + $buffer = ''; + + // Used as storage for the last part of the current chunk data + // Will be appended to the first line of the next chunk, if there is one + $last_chunk_line = ''; + + // Remembers whether the current buffer line is part of a comment + $inside_comment = false; + // Remembers whether the current buffer line is part of a data comment + $inside_data_comment = false; + // Remembers whether the current buffer line is part of a structure comment + $inside_structure_comment = false; + + // MediaWiki only accepts "\n" as row terminator + $mediawiki_new_line = "\n"; + + // Initialize the name of the current table + $cur_table_name = ""; + + while (! $finished && ! $error && ! $timeout_passed ) { + $data = PMA_importGetNextChunk(); + + if ($data === false) { + // Subtract data we didn't handle yet and stop processing + $GLOBALS['offset'] -= strlen($buffer); + break; + } elseif ($data === true) { + // Handle rest of buffer + } else { + // Append new data to buffer + $buffer = $data; + unset($data); + // Don't parse string if we're not at the end + // and don't have a new line inside + if ( strpos($buffer, $mediawiki_new_line) === false ) { + continue; + } + } + + // Because of reading chunk by chunk, the first line from the buffer + // contains only a portion of an actual line from the imported file. + // Therefore, we have to append it to the last line from the previous + // chunk. If we are at the first chunk, $last_chunk_line should be empty. + $buffer = $last_chunk_line . $buffer; + + // Process the buffer line by line + $buffer_lines = explode($mediawiki_new_line, $buffer); + + $full_buffer_lines_count = count($buffer_lines); + // If the reading is not finalised, the final line of the current chunk + // will not be complete + if (! $finished) { + $full_buffer_lines_count -= 1; + $last_chunk_line = $buffer_lines[$full_buffer_lines_count]; + } + + for ($line_nr = 0; $line_nr < $full_buffer_lines_count; ++ $line_nr) { + $cur_buffer_line = trim($buffer_lines[$line_nr]); + + // If the line is empty, go to the next one + if ( $cur_buffer_line === '' ) { + continue; + } + + $first_character = $cur_buffer_line[0]; + $matches = array(); + + // Check beginnning of comment + if (! strcmp(substr($cur_buffer_line, 0, 4), "")) { + // Only data comments are closed. The structure comments + // will be closed when a data comment begins (in order to + // skip structure tables) + if ($inside_data_comment) { + $inside_data_comment = false; + } + + // End comments that are not related to table structure + if (! $inside_structure_comment) { + $inside_comment = false; + } + } else { + // Check table name + $match_table_name = array(); + if (preg_match( + "/^Table data for `(.*)`$/", + $cur_buffer_line, + $match_table_name + ) + ) { + $cur_table_name = $match_table_name[1]; + $inside_data_comment = true; + + // End ignoring structure rows + if ($inside_structure_comment) { + $inside_structure_comment = false; + } + } elseif (preg_match( + "/^Table structure for `(.*)`$/", + $cur_buffer_line, + $match_table_name + ) + ) { + // The structure comments will be ignored + $inside_structure_comment = true; + } + } + continue; + } elseif (preg_match('/^\{\|(.*)$/', $cur_buffer_line, $matches)) { + // Check start of table + + // This will store all the column info on all rows from + // the current table read from the buffer + $cur_temp_table = array(); + + // Will be used as storage for the current row in the buffer + // Once all its columns are read, it will be added to + // $cur_temp_table and then it will be emptied + $cur_temp_line = array(); + + // Helps us differentiate the header columns + // from the normal columns + $in_table_header = false; + // End processing because the current line does not + // contain any column information + } elseif (substr($cur_buffer_line, 0, 2) === '|-' + || substr($cur_buffer_line, 0, 2) === '|+' + || substr($cur_buffer_line, 0, 2) === '|}' + ) { + // Check begin row or end table + + // Add current line to the values storage + if (! empty($cur_temp_line)) { + // If the current line contains header cells + // ( marked with '!' ), + // it will be marked as table header + if ( $in_table_header ) { + // Set the header columns + $cur_temp_table_headers = $cur_temp_line; + } else { + // Normal line, add it to the table + $cur_temp_table [] = $cur_temp_line; + } + } + + // Empty the temporary buffer + $cur_temp_line = array(); + + // No more processing required at the end of the table + if (substr($cur_buffer_line, 0, 2) === '|}') { + $current_table = array( + $cur_table_name, + $cur_temp_table_headers, + $cur_temp_table + ); + + // Import the current table data into the database + $this->_importDataOneTable($current_table); + + // Reset table name + $cur_table_name = ""; + } + // What's after the row tag is now only attributes + + } elseif (($first_character === '|') || ($first_character === '!')) { + // Check cell elements + + // Header cells + if ($first_character === '!') { + // Mark as table header, but treat as normal row + $cur_buffer_line = str_replace('!!', '||', $cur_buffer_line); + // Will be used to set $cur_temp_line as table header + $in_table_header = true; + } else { + $in_table_header = false; + } + + // Loop through each table cell + $cells = $this->_explodeMarkup($cur_buffer_line); + foreach ($cells as $cell) { + // A cell could contain both parameters and data + $cell_data = explode('|', $cell, 2); + + // A '|' inside an invalid link should not + // be mistaken as delimiting cell parameters + if (strpos($cell_data[0], '[[') === true ) { + if (count($cell_data) == 1) { + $cell = $cell_data[0]; + } else { + $cell = $cell_data[1]; + } + } + + // Delete the beginning of the column, if there is one + $cell = trim($cell); + $col_start_chars = array( "|", "!"); + foreach ($col_start_chars as $col_start_char) { + if (strpos($cell, $col_start_char) === 0) { + $cell = trim(substr($cell, 1)); + } + } + + // Add the cell to the row + $cur_temp_line [] = $cell; + } // foreach $cells + } else { + // If it's none of the above, then the current line has a bad + // format + $message = PMA_Message::error( + __('Invalid format of mediawiki input on line:
    %s.') + ); + $message->addParam($cur_buffer_line); + $error = true; + } + } // End treating full buffer lines + } // while - finished parsing buffer + } + + /** + * Imports data from a single table + * + * @param array $table containing all table info: + * + * $table[0] - string containing table name + * $table[1] - array[] of table headers + * $table[2] - array[][] of table content rows + * + * + * @global bool $analyze whether to scan for column types + * + * @return void + */ + private function _importDataOneTable ($table) + { + $analyze = $this->_getAnalyze(); + if ($analyze) { + // Set the table name + $this->_setTableName($table[0]); + + // Set generic names for table headers if they don't exist + $this->_setTableHeaders($table[1], $table[2][0]); + + // Create the tables array to be used in PMA_buildSQL() + $tables = array(); + $tables [] = array($table[0], $table[1], $table[2]); + + // Obtain the best-fit MySQL types for each column + $analyses = array(); + $analyses [] = PMA_analyzeTable($tables[0]); + + $this->_executeImportTables($tables, $analyses); + } + + // Commit any possible data in buffers + PMA_importRunQuery(); + } + + /** + * Sets the table name + * + * @param string &$table_name reference to the name of the table + * + * @return void + */ + private function _setTableName(&$table_name) + { + if (empty($table_name)) { + $result = $GLOBALS['dbi']->fetchResult('SHOW TABLES'); + // todo check if the name below already exists + $table_name = 'TABLE '.(count($result) + 1); + } + } + + /** + * Set generic names for table headers, if they don't exist + * + * @param array &$table_headers reference to the array containing the headers + * of a table + * @param array $table_row array containing the first content row + * + * @return void + */ + private function _setTableHeaders(&$table_headers, $table_row) + { + if (empty($table_headers)) { + // The first table row should contain the number of columns + // If they are not set, generic names will be given (COL 1, COL 2, etc) + $num_cols = count($table_row); + for ($i = 0; $i < $num_cols; ++ $i) { + $table_headers [$i] = 'COL '. ($i + 1); + } + } + } + + /** + * Sets the database name and additional options and calls PMA_buildSQL() + * Used in PMA_importDataAllTables() and $this->_importDataOneTable() + * + * @param array &$tables structure: + * array( + * array(table_name, array() column_names, array()() rows) + * ) + * @param array &$analyses structure: + * $analyses = array( + * array(array() column_types, array() column_sizes) + * ) + * + * @global string $db name of the database to import in + * + * @return void + */ + private function _executeImportTables(&$tables, &$analyses) + { + global $db; + + // $db_name : The currently selected database name, if applicable + // No backquotes + // $options : An associative array of options + if (strlen($db)) { + $db_name = $db; + $options = array('create_db' => false); + } else { + $db_name = 'mediawiki_DB'; + $options = null; + } + + // Array of SQL strings + // Non-applicable parameters + $create = null; + + // Create and execute necessary SQL statements from data + PMA_buildSQL($db_name, $tables, $analyses, $create, $options); + + unset($tables); + unset($analyses); + } + + + /** + * Replaces all instances of the '||' separator between delimiters + * in a given string + * + * @param string $start_delim start delimiter + * @param string $end_delim end delimiter + * @param string $replace the string to be replaced with + * @param string $subject the text to be replaced + * + * @return string with replacements + */ + private function _delimiterReplace($start_delim, $end_delim, $replace, $subject) + { + // String that will be returned + $cleaned = ""; + // Possible states of current character + $inside_tag = false; + $inside_attribute = false; + // Attributes can be declared with either " or ' + $start_attribute_character = false; + + // The full separator is "||"; + // This rembembers if the previous character was '|' + $partial_separator = false; + + // Parse text char by char + for ($i = 0; $i < strlen($subject); $i ++) { + $cur_char = $subject[$i]; + // Check for separators + if ($cur_char == '|') { + // If we're not inside a tag, then this is part of a real separator, + // so we append it to the current segment + if (! $inside_attribute) { + $cleaned .= $cur_char; + if ($partial_separator) { + $inside_tag = false; + $inside_attribute = false; + } + } elseif ($partial_separator) { + // If we are inside a tag, we replace the current char with + // the placeholder and append that to the current segment + $cleaned .= $replace; + } + + // If the previous character was also '|', then this ends a + // full separator. If not, this may be the beginning of one + $partial_separator = ! $partial_separator; + } else { + // If we're inside a tag attribute and the current character is + // not '|', but the previous one was, it means that the single '|' + // was not appended, so we append it now + if ($partial_separator && $inside_attribute) { + $cleaned .= "|"; + } + // If the char is different from "|", no separator can be formed + $partial_separator = false; + + // any other character should be appended to the current segment + $cleaned .= $cur_char; + + if ($cur_char == '<' && ! $inside_attribute) { + // start of a tag + $inside_tag = true; + } elseif ($cur_char == '>' && ! $inside_attribute) { + // end of a tag + $inside_tag = false; + } elseif (($cur_char == '"' || $cur_char == "'") && $inside_tag) { + // start or end of an attribute + if (! $inside_attribute) { + $inside_attribute = true; + // remember the attribute`s declaration character (" or ') + $start_attribute_character = $cur_char; + } else { + if ($cur_char == $start_attribute_character) { + $inside_attribute = false; + // unset attribute declaration character + $start_attribute_character = false; + } + } + } + } + } // end for each character in $subject + + return $cleaned; + } + + /** + * Separates a string into items, similarly to explode + * Uses the '||' separator (which is standard in the mediawiki format) + * and ignores any instances of it inside markup tags + * Used in parsing buffer lines containing data cells + * + * @param string $text text to be split + * + * @return array + */ + private function _explodeMarkup($text) + { + $separator = "||"; + $placeholder = "\x00"; + + // Remove placeholder instances + $text = str_replace($placeholder, '', $text); + + // Replace instances of the separator inside HTML-like + // tags with the placeholder + $cleaned = $this->_delimiterReplace("<", ">", $placeholder, $text); + // Explode, then put the replaced separators back in + $items = explode($separator, $cleaned); + foreach ($items as $i => $str) { + $items[$i] = str_replace($placeholder, $separator, $str); + } + + return $items; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Returns true if the table should be analyzed, false otherwise + * + * @return bool + */ + private function _getAnalyze() + { + return $this->_analyze; + } + + /** + * Sets to true if the table should be analyzed, false otherwise + * + * @param bool $analyze status + * + * @return void + */ + private function _setAnalyze($analyze) + { + $this->_analyze = $analyze; + } +} diff --git a/phpMyAdmin/libraries/plugins/import/ImportOds.class.php b/phpMyAdmin/libraries/plugins/import/ImportOds.class.php new file mode 100644 index 0000000..2b07e88 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/import/ImportOds.class.php @@ -0,0 +1,415 @@ +setProperties(); + } + + /** + * Sets the import plugin properties. + * Called in the constructor. + * + * @return void + */ + protected function setProperties() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ImportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + + $importPluginProperties = new ImportPluginProperties(); + $importPluginProperties->setText('OpenDocument Spreadsheet'); + $importPluginProperties->setExtension('ods'); + $importPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $importPluginProperties + // this will be shown as "Format specific options" + $importSpecificOptions = new OptionsPropertyRootGroup(); + $importSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create primary items and add them to the group + $leaf = new BoolPropertyItem(); + $leaf->setName("col_names"); + $leaf->setText( + __( + 'The first line of the file contains the table column names' + . ' (if this is unchecked, the first line will become part' + . ' of the data)' + ) + ); + $generalOptions->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName("empty_rows"); + $leaf->setText(__('Do not import empty rows')); + $generalOptions->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName("recognize_percentages"); + $leaf->setText( + __( + 'Import percentages as proper decimals (ex. 12.00% to .12)' + ) + ); + $generalOptions->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName("recognize_currency"); + $leaf->setText(__('Import currencies (ex. $5.00 to 5.00)')); + $generalOptions->addProperty($leaf); + + // add the main group to the root group + $importSpecificOptions->addProperty($generalOptions); + + // set the options for the import plugin property item + $importPluginProperties->setOptions($importSpecificOptions); + $this->properties = $importPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Handles the whole import logic + * + * @return void + */ + public function doImport() + { + global $db, $error, $timeout_passed, $finished; + + $i = 0; + $len = 0; + $buffer = ""; + + /** + * Read in the file via PMA_importGetNextChunk so that + * it can process compressed files + */ + while (! ($finished && $i >= $len) && ! $error && ! $timeout_passed) { + $data = PMA_importGetNextChunk(); + if ($data === false) { + /* subtract data we didn't handle yet and stop processing */ + $GLOBALS['offset'] -= strlen($buffer); + break; + } elseif ($data === true) { + /* Handle rest of buffer */ + } else { + /* Append new data to buffer */ + $buffer .= $data; + unset($data); + } + } + + unset($data); + + /** + * Disable loading of external XML entities. + */ + libxml_disable_entity_loader(); + + /** + * Load the XML string + * + * The option LIBXML_COMPACT is specified because it can + * result in increased performance without the need to + * alter the code in any way. It's basically a freebee. + */ + $xml = simplexml_load_string($buffer, "SimpleXMLElement", LIBXML_COMPACT); + + unset($buffer); + + if ($xml === false) { + $sheets = array(); + $GLOBALS['message'] = PMA_Message::error( + __( + 'The XML file specified was either malformed or incomplete.' + . ' Please correct the issue and try again.' + ) + ); + $GLOBALS['error'] = true; + } else { + $root = $xml->children('office', true)->{'body'}->{'spreadsheet'}; + if (empty($root)) { + $sheets = array(); + $GLOBALS['message'] = PMA_Message::error( + __('Could not parse OpenDocument Spreadsheet!') + ); + $GLOBALS['error'] = true; + } else { + $sheets = $root->children('table', true); + } + } + + $tables = array(); + + $max_cols = 0; + + $col_count = 0; + $col_names = array(); + + $tempRow = array(); + $tempRows = array(); + $rows = array(); + + /* Iterate over tables */ + foreach ($sheets as $sheet) { + $col_names_in_first_row = isset($_REQUEST['ods_col_names']); + + /* Iterate over rows */ + foreach ($sheet as $row) { + $type = $row->getName(); + if (! strcmp('table-row', $type)) { + /* Iterate over columns */ + foreach ($row as $cell) { + $text = $cell->children('text', true); + $cell_attrs = $cell->attributes('office', true); + + if (count($text) != 0) { + $attr = $cell->attributes('table', true); + $num_repeat = (int) $attr['number-columns-repeated']; + $num_iterations = $num_repeat ? $num_repeat : 1; + + for ($k = 0; $k < $num_iterations; $k++) { + if ($_REQUEST['ods_recognize_percentages'] + && ! strcmp( + 'percentage', + $cell_attrs['value-type'] + ) + ) { + $value = (double)$cell_attrs['value']; + } elseif ($_REQUEST['ods_recognize_currency'] + && !strcmp('currency', $cell_attrs['value-type']) + ) { + $value = (double)$cell_attrs['value']; + } else { + /* We need to concatenate all paragraphs */ + $values = array(); + foreach ($text as $paragraph) { + $values[] = (string)$paragraph; + } + $value = implode("\n", $values); + } + if (! $col_names_in_first_row) { + $tempRow[] = $value; + } else { + $col_names[] = $value; + } + + ++$col_count; + } + } else { + /* Number of blank columns repeated */ + if ($col_count < count($row->children('table', true)) - 1 + ) { + $attr = $cell->attributes('table', true); + $num_null = (int)$attr['number-columns-repeated']; + + if ($num_null) { + if (! $col_names_in_first_row) { + for ($i = 0; $i < $num_null; ++$i) { + $tempRow[] = 'NULL'; + ++$col_count; + } + } else { + for ($i = 0; $i < $num_null; ++$i) { + $col_names[] = PMA_getColumnAlphaName( + $col_count + 1 + ); + ++$col_count; + } + } + } else { + if (! $col_names_in_first_row) { + $tempRow[] = 'NULL'; + } else { + $col_names[] = PMA_getColumnAlphaName( + $col_count + 1 + ); + } + + ++$col_count; + } + } + } + } + + /* Find the widest row */ + if ($col_count > $max_cols) { + $max_cols = $col_count; + } + + /* Don't include a row that is full of NULL values */ + if (! $col_names_in_first_row) { + if ($_REQUEST['ods_empty_rows']) { + foreach ($tempRow as $cell) { + if (strcmp('NULL', $cell)) { + $tempRows[] = $tempRow; + break; + } + } + } else { + $tempRows[] = $tempRow; + } + } + + $col_count = 0; + $col_names_in_first_row = false; + $tempRow = array(); + } + } + + /* Skip over empty sheets */ + if (count($tempRows) == 0 || count($tempRows[0]) == 0) { + $col_names = array(); + $tempRow = array(); + $tempRows = array(); + continue; + } + + /** + * Fill out each row as necessary to make + * every one exactly as wide as the widest + * row. This included column names. + */ + + /* Fill out column names */ + for ($i = count($col_names); $i < $max_cols; ++$i) { + $col_names[] = PMA_getColumnAlphaName($i + 1); + } + + /* Fill out all rows */ + $num_rows = count($tempRows); + for ($i = 0; $i < $num_rows; ++$i) { + for ($j = count($tempRows[$i]); $j < $max_cols; ++$j) { + $tempRows[$i][] = 'NULL'; + } + } + + /* Store the table name so we know where to place the row set */ + $tbl_attr = $sheet->attributes('table', true); + $tables[] = array((string)$tbl_attr['name']); + + /* Store the current sheet in the accumulator */ + $rows[] = array((string)$tbl_attr['name'], $col_names, $tempRows); + $tempRows = array(); + $col_names = array(); + $max_cols = 0; + } + + unset($tempRow); + unset($tempRows); + unset($col_names); + unset($sheets); + unset($xml); + + /** + * Bring accumulated rows into the corresponding table + */ + $num_tbls = count($tables); + for ($i = 0; $i < $num_tbls; ++$i) { + for ($j = 0; $j < count($rows); ++$j) { + if (! strcmp($tables[$i][TBL_NAME], $rows[$j][TBL_NAME])) { + if (! isset($tables[$i][COL_NAMES])) { + $tables[$i][] = $rows[$j][COL_NAMES]; + } + + $tables[$i][ROWS] = $rows[$j][ROWS]; + } + } + } + + /* No longer needed */ + unset($rows); + + /* Obtain the best-fit MySQL types for each column */ + $analyses = array(); + + $len = count($tables); + for ($i = 0; $i < $len; ++$i) { + $analyses[] = PMA_analyzeTable($tables[$i]); + } + + /** + * string $db_name (no backquotes) + * + * array $table = array(table_name, array() column_names, array()() rows) + * array $tables = array of "$table"s + * + * array $analysis = array(array() column_types, array() column_sizes) + * array $analyses = array of "$analysis"s + * + * array $create = array of SQL strings + * + * array $options = an associative array of options + */ + + /* Set database name to the currently selected one, if applicable */ + if (strlen($db)) { + $db_name = $db; + $options = array('create_db' => false); + } else { + $db_name = 'ODS_DB'; + $options = null; + } + + /* Non-applicable parameters */ + $create = null; + + /* Created and execute necessary SQL statements from data */ + PMA_buildSQL($db_name, $tables, $analyses, $create, $options); + + unset($tables); + unset($analyses); + + /* Commit any possible data in buffers */ + PMA_importRunQuery(); + } +} diff --git a/phpMyAdmin/libraries/plugins/import/ImportShp.class.php b/phpMyAdmin/libraries/plugins/import/ImportShp.class.php new file mode 100644 index 0000000..7a4c0c8 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/import/ImportShp.class.php @@ -0,0 +1,335 @@ +setProperties(); + } + + /** + * Sets the import plugin properties. + * Called in the constructor. + * + * @return void + */ + protected function setProperties() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ImportPluginProperties.class.php"; + + $importPluginProperties = new ImportPluginProperties(); + $importPluginProperties->setText(__('ESRI Shape File')); + $importPluginProperties->setExtension('shp'); + $importPluginProperties->setOptions(array()); + $importPluginProperties->setOptionsText(__('Options')); + + $this->properties = $importPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Handles the whole import logic + * + * @return void + */ + public function doImport() + { + global $db, $error, $finished, $compression, + $import_file, $local_import_file, $message; + + $GLOBALS['finished'] = false; + + $shp = new PMA_ShapeFile(1); + // If the zip archive has more than one file, + // get the correct content to the buffer from .shp file. + if ($compression == 'application/zip' + && PMA_getNoOfFilesInZip($import_file) > 1 + ) { + $zip_content = PMA_getZipContents($import_file, '/^.*\.shp$/i'); + $GLOBALS['import_text'] = $zip_content['data']; + } + + $temp_dbf_file = false; + // We need dbase extension to handle .dbf file + if (extension_loaded('dbase')) { + // If we can extract the zip archive to 'TempDir' + // and use the files in it for import + if ($compression == 'application/zip' + && ! empty($GLOBALS['cfg']['TempDir']) + && is_writable($GLOBALS['cfg']['TempDir']) + ) { + $dbf_file_name = PMA_findFileFromZipArchive( + '/^.*\.dbf$/i', $import_file + ); + // If the corresponding .dbf file is in the zip archive + if ($dbf_file_name) { + // Extract the .dbf file and point to it. + $extracted = PMA_zipExtract( + $import_file, + realpath($GLOBALS['cfg']['TempDir']), + array($dbf_file_name) + ); + if ($extracted) { + $dbf_file_path = realpath($GLOBALS['cfg']['TempDir']) + . (PMA_IS_WINDOWS ? '\\' : '/') . $dbf_file_name; + $temp_dbf_file = true; + // Replace the .dbf with .*, as required + // by the bsShapeFiles library. + $file_name = substr( + $dbf_file_path, 0, strlen($dbf_file_path) - 4 + ) . '.*'; + $shp->FileName = $file_name; + } + } + } elseif (! empty($local_import_file) + && ! empty($GLOBALS['cfg']['UploadDir']) + && $compression == 'none' + ) { + // If file is in UploadDir, use .dbf file in the same UploadDir + // to load extra data. + // Replace the .shp with .*, + // so the bsShapeFiles library correctly locates .dbf file. + $file_name = substr($import_file, 0, strlen($import_file) - 4) + . '.*'; + $shp->FileName = $file_name; + } + } + + // Load data + $shp->loadFromFile(''); + if ($shp->lastError != "") { + $error = true; + $message = PMA_Message::error( + __('There was an error importing the ESRI shape file: "%s".') + ); + $message->addParam($shp->lastError); + return; + } + + // Delete the .dbf file extracted to 'TempDir' + if ($temp_dbf_file + && isset($dbf_file_path) + && file_exists($dbf_file_path) + ) { + unlink($dbf_file_path); + } + + $esri_types = array( + 0 => 'Null Shape', + 1 => 'Point', + 3 => 'PolyLine', + 5 => 'Polygon', + 8 => 'MultiPoint', + 11 => 'PointZ', + 13 => 'PolyLineZ', + 15 => 'PolygonZ', + 18 => 'MultiPointZ', + 21 => 'PointM', + 23 => 'PolyLineM', + 25 => 'PolygonM', + 28 => 'MultiPointM', + 31 => 'MultiPatch', + ); + + switch ($shp->shapeType) { + // ESRI Null Shape + case 0: + break; + // ESRI Point + case 1: + $gis_type = 'point'; + break; + // ESRI PolyLine + case 3: + $gis_type = 'multilinestring'; + break; + // ESRI Polygon + case 5: + $gis_type = 'multipolygon'; + break; + // ESRI MultiPoint + case 8: + $gis_type = 'multipoint'; + break; + default: + $error = true; + if (! isset($esri_types[$shp->shapeType])) { + $message = PMA_Message::error( + __( + 'You tried to import an invalid file or the imported file' + . ' contains invalid data' + ) + ); + } else { + $message = PMA_Message::error( + __('MySQL Spatial Extension does not support ESRI type "%s".') + ); + $message->addParam($esri_types[$shp->shapeType]); + } + return; + } + + if (isset($gis_type)) { + include_once './libraries/gis/pma_gis_factory.php'; + $gis_obj = PMA_GIS_Factory::factory($gis_type); + } else { + $gis_obj = null; + } + + $num_rows = count($shp->records); + // If .dbf file is loaded, the number of extra data columns + $num_data_cols = isset($shp->DBFHeader) ? count($shp->DBFHeader) : 0; + + $rows = array(); + $col_names = array(); + if ($num_rows != 0) { + foreach ($shp->records as $record) { + $tempRow = array(); + if ($gis_obj == null) { + $tempRow[] = null; + } else { + $tempRow[] = "GeomFromText('" + . $gis_obj->getShape($record->SHPData) . "')"; + } + + if (isset($shp->DBFHeader)) { + foreach ($shp->DBFHeader as $c) { + $cell = trim($record->DBFData[$c[0]]); + + if (! strcmp($cell, '')) { + $cell = 'NULL'; + } + + $tempRow[] = $cell; + } + } + $rows[] = $tempRow; + } + } + + if (count($rows) == 0) { + $error = true; + $message = PMA_Message::error( + __('The imported file does not contain any data') + ); + return; + } + + // Column names for spatial column and the rest of the columns, + // if they are available + $col_names[] = 'SPATIAL'; + for ($n = 0; $n < $num_data_cols; $n++) { + $col_names[] = $shp->DBFHeader[$n][0]; + } + + // Set table name based on the number of tables + if (strlen($db)) { + $result = $GLOBALS['dbi']->fetchResult('SHOW TABLES'); + $table_name = 'TABLE '.(count($result) + 1); + } else { + $table_name = 'TBL_NAME'; + } + $tables = array(array($table_name, $col_names, $rows)); + + // Use data from shape file to chose best-fit MySQL types for each column + $analyses = array(); + $analyses[] = PMA_analyzeTable($tables[0]); + + $table_no = 0; $spatial_col = 0; + $analyses[$table_no][TYPES][$spatial_col] = GEOMETRY; + $analyses[$table_no][FORMATTEDSQL][$spatial_col] = true; + + // Set database name to the currently selected one, if applicable + if (strlen($db)) { + $db_name = $db; + $options = array('create_db' => false); + } else { + $db_name = 'SHP_DB'; + $options = null; + } + + // Created and execute necessary SQL statements from data + $null_param = null; + PMA_buildSQL($db_name, $tables, $analyses, $null_param, $options); + + unset($tables); + unset($analyses); + + $finished = true; + $error = false; + + // Commit any possible data in buffers + PMA_importRunQuery(); + } + + /** + * Returns specified number of bytes from the buffer. + * Buffer automatically fetches next chunk of data when the buffer + * falls short. + * Sets $eof when $GLOBALS['finished'] is set and the buffer falls short. + * + * @param int $length number of bytes + * + * @return string + */ + public static function readFromBuffer($length) + { + global $buffer, $eof; + + if (strlen($buffer) < $length) { + if ($GLOBALS['finished']) { + $eof = true; + } else { + $buffer .= PMA_importGetNextChunk(); + } + } + $result = substr($buffer, 0, $length); + $buffer = substr($buffer, $length); + return $result; + } +} diff --git a/phpMyAdmin/libraries/plugins/import/ImportSql.class.php b/phpMyAdmin/libraries/plugins/import/ImportSql.class.php new file mode 100644 index 0000000..4ae9024 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/import/ImportSql.class.php @@ -0,0 +1,447 @@ +setProperties(); + } + + /** + * Sets the import plugin properties. + * Called in the constructor. + * + * @return void + */ + protected function setProperties() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ImportPluginProperties.class.php"; + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + include_once "$props/options/items/SelectPropertyItem.class.php"; + include_once "$props/options/items/BoolPropertyItem.class.php"; + + $importPluginProperties = new ImportPluginProperties(); + $importPluginProperties->setText('SQL'); + $importPluginProperties->setExtension('sql'); + $importPluginProperties->setOptionsText(__('Options')); + + $compats = $GLOBALS['dbi']->getCompatibilities(); + if (count($compats) > 0) { + $values = array(); + foreach ($compats as $val) { + $values[$val] = $val; + } + + // create the root group that will be the options field for + // $importPluginProperties + // this will be shown as "Format specific options" + $importSpecificOptions = new OptionsPropertyRootGroup(); + $importSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + // create primary items and add them to the group + $leaf = new SelectPropertyItem(); + $leaf->setName("compatibility"); + $leaf->setText(__('SQL compatibility mode:')); + $leaf->setValues($values); + $leaf->setDoc( + array( + 'manual_MySQL_Database_Administration', + 'Server_SQL_mode', + ) + ); + $generalOptions->addProperty($leaf); + $leaf = new BoolPropertyItem(); + $leaf->setName("no_auto_value_on_zero"); + $leaf->setText( + __('Do not use AUTO_INCREMENT for zero values') + ); + $leaf->setDoc( + array( + 'manual_MySQL_Database_Administration', + 'Server_SQL_mode', + 'sqlmode_no_auto_value_on_zero' + ) + ); + $generalOptions->addProperty($leaf); + + // add the main group to the root group + $importSpecificOptions->addProperty($generalOptions); + // set the options for the import plugin property item + $importPluginProperties->setOptions($importSpecificOptions); + } + + $this->properties = $importPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Handles the whole import logic + * + * @param array &$sql_data 2-element array with sql data + * + * @return void + */ + public function doImport(&$sql_data = array()) + { + global $error, $timeout_passed; + + $buffer = ''; + // Defaults for parser + $sql = ''; + $start_pos = 0; + $i = 0; + $len= 0; + $big_value = 2147483647; + // include the space because it's mandatory + $delimiter_keyword = 'DELIMITER '; + $length_of_delimiter_keyword = strlen($delimiter_keyword); + + if (isset($_POST['sql_delimiter'])) { + $sql_delimiter = $_POST['sql_delimiter']; + } else { + $sql_delimiter = ';'; + } + + // Handle compatibility options + $sql_modes = array(); + if (isset($_REQUEST['sql_compatibility']) + && 'NONE' != $_REQUEST['sql_compatibility'] + ) { + $sql_modes[] = $_REQUEST['sql_compatibility']; + } + if (isset($_REQUEST['sql_no_auto_value_on_zero'])) { + $sql_modes[] = 'NO_AUTO_VALUE_ON_ZERO'; + } + if (count($sql_modes) > 0) { + $GLOBALS['dbi']->tryQuery( + 'SET SQL_MODE="' . implode(',', $sql_modes) . '"' + ); + } + unset($sql_modes); + + /** + * will be set in PMA_importGetNextChunk() + * + * @global boolean $GLOBALS['finished'] + */ + $GLOBALS['finished'] = false; + + while (! ($GLOBALS['finished'] && $i >= $len) + && ! $error + && ! $timeout_passed + ) { + $data = PMA_importGetNextChunk(); + if ($data === false) { + // subtract data we didn't handle yet and stop processing + $GLOBALS['offset'] -= strlen($buffer); + break; + } elseif ($data === true) { + // Handle rest of buffer + } else { + // Append new data to buffer + $buffer .= $data; + // free memory + unset($data); + // Do not parse string when we're not at the end + // and don't have ; inside + if ((strpos($buffer, $sql_delimiter, $i) === false) + && ! $GLOBALS['finished'] + ) { + continue; + } + } + + // Convert CR (but not CRLF) to LF otherwise all queries + // may not get executed on some platforms + $buffer = preg_replace("/\r($|[^\n])/", "\n$1", $buffer); + + // Current length of our buffer + $len = strlen($buffer); + + // Grab some SQL queries out of it + while ($i < $len) { + $found_delimiter = false; + // Find first interesting character + $old_i = $i; + // this is about 7 times faster that looking for each sequence i + // one by one with strpos() + $match = preg_match( + '/(\'|"|#|-- |\/\*|`|(?i)(? unclosed quote, + // but we handle it as end of query + if ($GLOBALS['finished']) { + $endq = true; + $i = $len - 1; + } + $found_delimiter = false; + break; + } + // Was not the quote escaped? + $j = $pos - 1; + while ($buffer[$j] == '\\') { + $j--; + } + // Even count means it was not escaped + $endq = (((($pos - 1) - $j) % 2) == 0); + // Skip the string + $i = $pos; + + if ($first_sql_delimiter < $pos) { + $found_delimiter = false; + } + } + if (! $endq) { + break; + } + $i++; + // Aren't we at the end? + if ($GLOBALS['finished'] && $i == $len) { + $i--; + } else { + continue; + } + } + + // Not enough data to decide + if ((($i == ($len - 1) && ($ch == '-' || $ch == '/')) + || ($i == ($len - 2) && (($ch == '-' && $buffer[$i + 1] == '-') + || ($ch == '/' && $buffer[$i + 1] == '*')))) + && ! $GLOBALS['finished'] + ) { + break; + } + + // Comments + if ($ch == '#' + || ($i < ($len - 1) && $ch == '-' && $buffer[$i + 1] == '-' + && (($i < ($len - 2) && $buffer[$i + 2] <= ' ') + || ($i == ($len - 1) && $GLOBALS['finished']))) + || ($i < ($len - 1) && $ch == '/' && $buffer[$i + 1] == '*') + ) { + // Copy current string to SQL + if ($start_pos != $i) { + $sql .= substr($buffer, $start_pos, $i - $start_pos); + } + // Skip the rest + $start_of_comment = $i; + // do not use PHP_EOL here instead of "\n", because the export + // file might have been produced on a different system + $i = strpos($buffer, $ch == '/' ? '*/' : "\n", $i); + // didn't we hit end of string? + if ($i === false) { + if ($GLOBALS['finished']) { + $i = $len - 1; + } else { + break; + } + } + // Skip * + if ($ch == '/') { + $i++; + } + // Skip last char + $i++; + // We need to send the comment part in case we are defining + // a procedure or function and comments in it are valuable + $sql .= substr( + $buffer, + $start_of_comment, + $i - $start_of_comment + ); + // Next query part will start here + $start_pos = $i; + // Aren't we at the end? + if ($i == $len) { + $i--; + } else { + continue; + } + } + // Change delimiter, if redefined, and skip it + // (don't send to server!) + if (($i + $length_of_delimiter_keyword < $len) + && strtoupper( + substr($buffer, $i, $length_of_delimiter_keyword) + ) == $delimiter_keyword + ) { + // look for EOL on the character immediately after 'DELIMITER ' + // (see previous comment about PHP_EOL) + $new_line_pos = strpos( + $buffer, + "\n", + $i + $length_of_delimiter_keyword + ); + // it might happen that there is no EOL + if (false === $new_line_pos) { + $new_line_pos = $len; + } + $sql_delimiter = substr( + $buffer, + $i + $length_of_delimiter_keyword, + $new_line_pos - $i - $length_of_delimiter_keyword + ); + $i = $new_line_pos + 1; + // Next query part will start here + $start_pos = $i; + continue; + } + + // End of SQL + if ($found_delimiter + || ($GLOBALS['finished'] + && ($i == $len - 1)) + ) { + $tmp_sql = $sql; + if ($start_pos < $len) { + $length_to_grab = $i - $start_pos; + + if (! $found_delimiter) { + $length_to_grab++; + } + $tmp_sql .= substr($buffer, $start_pos, $length_to_grab); + unset($length_to_grab); + } + // Do not try to execute empty SQL + if (! preg_match('/^([\s]*;)*$/', trim($tmp_sql))) { + $sql = $tmp_sql; + PMA_importRunQuery( + $sql, + substr($buffer, 0, $i + strlen($sql_delimiter)), + false, + $sql_data + ); + $buffer = substr($buffer, $i + strlen($sql_delimiter)); + // Reset parser: + $len = strlen($buffer); + $sql = ''; + $i = 0; + $start_pos = 0; + // Any chance we will get a complete query? + //if ((strpos($buffer, ';') === false) + //&& ! $GLOBALS['finished']) { + if (strpos($buffer, $sql_delimiter) === false + && ! $GLOBALS['finished'] + ) { + break; + } + } else { + $i++; + $start_pos = $i; + } + } + } // End of parser loop + } // End of import loop + // Commit any possible data in buffers + PMA_importRunQuery('', substr($buffer, 0, $len), false, $sql_data); + PMA_importRunQuery('', '', false, $sql_data); + } +} diff --git a/phpMyAdmin/libraries/plugins/import/ImportXml.class.php b/phpMyAdmin/libraries/plugins/import/ImportXml.class.php new file mode 100644 index 0000000..7c7afa0 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/import/ImportXml.class.php @@ -0,0 +1,379 @@ +setProperties(); + } + + /** + * Sets the import plugin properties. + * Called in the constructor. + * + * @return void + */ + protected function setProperties() + { + $props = 'libraries/properties/'; + include_once "$props/plugins/ImportPluginProperties.class.php"; + + $importPluginProperties = new ImportPluginProperties(); + $importPluginProperties->setText(__('XML')); + $importPluginProperties->setExtension('xml'); + $importPluginProperties->setMimeType('text/xml'); + $importPluginProperties->setOptions(array()); + $importPluginProperties->setOptionsText(__('Options')); + + $this->properties = $importPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Handles the whole import logic + * + * @return void + */ + public function doImport() + { + global $error, $timeout_passed, $finished, $db; + + $i = 0; + $len = 0; + $buffer = ""; + + /** + * Read in the file via PMA_importGetNextChunk so that + * it can process compressed files + */ + while (! ($finished && $i >= $len) && ! $error && ! $timeout_passed) { + $data = PMA_importGetNextChunk(); + if ($data === false) { + /* subtract data we didn't handle yet and stop processing */ + $GLOBALS['offset'] -= strlen($buffer); + break; + } elseif ($data === true) { + /* Handle rest of buffer */ + } else { + /* Append new data to buffer */ + $buffer .= $data; + unset($data); + } + } + + unset($data); + + /** + * Disable loading of external XML entities. + */ + libxml_disable_entity_loader(); + + /** + * Load the XML string + * + * The option LIBXML_COMPACT is specified because it can + * result in increased performance without the need to + * alter the code in any way. It's basically a freebee. + */ + $xml = simplexml_load_string($buffer, "SimpleXMLElement", LIBXML_COMPACT); + + unset($buffer); + + /** + * The XML was malformed + */ + if ($xml === false) { + PMA_Message::error( + __( + 'The XML file specified was either malformed or incomplete.' + . ' Please correct the issue and try again.' + ) + )->display(); + unset($xml); + $GLOBALS['finished'] = false; + return; + } + + /** + * Table accumulator + */ + $tables = array(); + /** + * Row accumulator + */ + $rows = array(); + + /** + * Temp arrays + */ + $tempRow = array(); + $tempCells = array(); + + /** + * CREATE code included (by default: no) + */ + $struct_present = false; + + /** + * Analyze the data in each table + */ + $namespaces = $xml->getNameSpaces(true); + + /** + * Get the database name, collation and charset + */ + $db_attr = $xml->children($namespaces['pma']) + ->{'structure_schemas'}->{'database'}; + + if ($db_attr instanceof SimpleXMLElement) { + $db_attr = $db_attr->attributes(); + $db_name = (string)$db_attr['name']; + $collation = (string)$db_attr['collation']; + $charset = (string)$db_attr['charset']; + } else { + /** + * If the structure section is not present + * get the database name from the data section + */ + $db_attr = $xml->children()->attributes(); + $db_name = (string)$db_attr['name']; + $collation = null; + $charset = null; + } + + /** + * The XML was malformed + */ + if ($db_name === null) { + PMA_Message::error( + __( + 'The XML file specified was either malformed or incomplete.' + . ' Please correct the issue and try again.' + ) + )->display(); + unset($xml); + $GLOBALS['finished'] = false; + return; + } + + /** + * Retrieve the structure information + */ + if (isset($namespaces['pma'])) { + /** + * Get structures for all tables + */ + $struct = $xml->children($namespaces['pma']); + + $create = array(); + + foreach ($struct as $val1) { + foreach ($val1 as $val2) { + // Need to select the correct database for the creation of + // tables, views, triggers, etc. + /** + * @todo Generating a USE here blocks importing of a table + * into another database. + */ + $attrs = $val2->attributes(); + $create[] = "USE " + . PMA_Util::backquote( + $attrs["name"] + ); + + foreach ($val2 as $val3) { + /** + * Remove the extra cosmetic spacing + */ + $val3 = str_replace(" ", "", (string)$val3); + $create[] = $val3; + } + } + } + + $struct_present = true; + } + + /** + * Move down the XML tree to the actual data + */ + $xml = $xml->children()->children(); + + $data_present = false; + + /** + * Only attempt to analyze/collect data if there is data present + */ + if ($xml && @count($xml->children())) { + $data_present = true; + + /** + * Process all database content + */ + foreach ($xml as $v1) { + $tbl_attr = $v1->attributes(); + + $isInTables = false; + for ($i = 0; $i < count($tables); ++$i) { + if (! strcmp($tables[$i][TBL_NAME], (string)$tbl_attr['name'])) { + $isInTables = true; + break; + } + } + + if ($isInTables == false) { + $tables[] = array((string)$tbl_attr['name']); + } + + foreach ($v1 as $v2) { + $row_attr = $v2->attributes(); + if (! array_search((string)$row_attr['name'], $tempRow)) { + $tempRow[] = (string)$row_attr['name']; + } + $tempCells[] = (string)$v2; + } + + $rows[] = array((string)$tbl_attr['name'], $tempRow, $tempCells); + + $tempRow = array(); + $tempCells = array(); + } + + unset($tempRow); + unset($tempCells); + unset($xml); + + /** + * Bring accumulated rows into the corresponding table + */ + $num_tbls = count($tables); + for ($i = 0; $i < $num_tbls; ++$i) { + for ($j = 0; $j < count($rows); ++$j) { + if (! strcmp($tables[$i][TBL_NAME], $rows[$j][TBL_NAME])) { + if (! isset($tables[$i][COL_NAMES])) { + $tables[$i][] = $rows[$j][COL_NAMES]; + } + + $tables[$i][ROWS][] = $rows[$j][ROWS]; + } + } + } + + unset($rows); + + if (! $struct_present) { + $analyses = array(); + + $len = count($tables); + for ($i = 0; $i < $len; ++$i) { + $analyses[] = PMA_analyzeTable($tables[$i]); + } + } + } + + unset($xml); + unset($tempCells); + unset($rows); + + /** + * Only build SQL from data if there is data present + */ + if ($data_present) { + /** + * Set values to NULL if they were not present + * to maintain PMA_buildSQL() call integrity + */ + if (! isset($analyses)) { + $analyses = null; + if (! $struct_present) { + $create = null; + } + } + } + + /** + * string $db_name (no backquotes) + * + * array $table = array(table_name, array() column_names, array()() rows) + * array $tables = array of "$table"s + * + * array $analysis = array(array() column_types, array() column_sizes) + * array $analyses = array of "$analysis"s + * + * array $create = array of SQL strings + * + * array $options = an associative array of options + */ + + /* Set database name to the currently selected one, if applicable */ + if (strlen($db)) { + /* Override the database name in the XML file, if one is selected */ + $db_name = $db; + $options = array('create_db' => false); + } else { + if ($db_name === null) { + $db_name = 'XML_DB'; + } + + /* Set database collation/charset */ + $options = array( + 'db_collation' => $collation, + 'db_charset' => $charset, + ); + } + + /* Created and execute necessary SQL statements from data */ + PMA_buildSQL($db_name, $tables, $analyses, $create, $options); + + unset($analyses); + unset($tables); + unset($create); + + /* Commit any possible data in buffers */ + PMA_importRunQuery(); + } +} diff --git a/phpMyAdmin/libraries/plugins/import/README b/phpMyAdmin/libraries/plugins/import/README new file mode 100644 index 0000000..815cf2b --- /dev/null +++ b/phpMyAdmin/libraries/plugins/import/README @@ -0,0 +1,172 @@ +This directory holds import plugins for phpMyAdmin. Any new plugin should +basically follow the structure presented here. The messages must use our +gettext mechanism, see http://wiki.phpmyadmin.net/pma/Gettext_for_developers. + +setProperties(); + } + + /** + * Sets the import plugin properties. + * Called in the constructor. + * + * @return void + */ + protected function setProperties() + { + // set properties + $props = 'libraries/properties/'; + // include the main class for properties for the import plug-ins + include_once "$props/plugins/ImportPluginProperties.class.php"; + // include the group properties classes + include_once "$props/options/groups/OptionsPropertyRootGroup.class.php"; + include_once "$props/options/groups/OptionsPropertyMainGroup.class.php"; + // include the needed single property items + include_once "$props/options/items/RadioPropertyItem.class.php"; + + $importPluginProperties = new ImportPluginProperties(); + $importPluginProperties->setText('[name]'); // the name of your plug-in + $importPluginProperties->setExtension('[ext]'); // extension this plug-in can handle + $importPluginProperties->setOptionsText(__('Options')); + + // create the root group that will be the options field for + // $importPluginProperties + // this will be shown as "Format specific options" + $importSpecificOptions = new OptionsPropertyRootGroup(); + $importSpecificOptions->setName("Format Specific Options"); + + // general options main group + $generalOptions = new OptionsPropertyMainGroup(); + $generalOptions->setName("general_opts"); + + // optional : + // create primary items and add them to the group + // type - one of the classes listed in libraries/properties/options/items/ + // name - form element name + // text - description in GUI + // size - size of text element + // len - maximal size of input + // values - possible values of the item + $leaf = new RadioPropertyItem(); + $leaf->setName("structure_or_data"); + $leaf->setValues( + array( + 'structure' => __('structure'), + 'data' => __('data'), + 'structure_and_data' => __('structure and data') + ) + ); + $generalOptions->addProperty($leaf); + + // add the main group to the root group + $importSpecificOptions->addProperty($generalOptions); + + // set the options for the import plugin property item + $importPluginProperties->setOptions($importSpecificOptions); + $this->properties = $importPluginProperties; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @return void + */ + public function update (SplSubject $subject) + { + } + + /** + * Handles the whole import logic + * + * @return void + */ + public function doImport() + { + // get globals (others are optional) + global $error, $timeout_passed, $finished; + + $buffer = ''; + while (! ($finished && $i >= $len) && ! $error && ! $timeout_passed) { + $data = PMA_importGetNextChunk(); + if ($data === false) { + // subtract data we didn't handle yet and stop processing + $GLOBALS['offset'] -= strlen($buffer); + break; + } elseif ($data === true) { + // Handle rest of buffer + } else { + // Append new data to buffer + $buffer .= $data; + } + // PARSE $buffer here, post sql queries using: + PMA_importRunQuery($sql, $verbose_sql_with_comments); + } // End of import loop + // Commit any possible data in buffers + PMA_importRunQuery(); + } + + + // optional: + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Getter description + * + * @return type + */ + private function _getMyOptionalVariable() + { + return $this->_myOptionalVariable; + } + + /** + * Setter description + * + * @param type $my_optional_variable description + * + * @return void + */ + private function _setMyOptionalVariable($my_optional_variable) + { + $this->_myOptionalVariable = $my_optional_variable; + } +} +?> diff --git a/phpMyAdmin/libraries/plugins/import/ShapeFile.class.php b/phpMyAdmin/libraries/plugins/import/ShapeFile.class.php new file mode 100644 index 0000000..bad2751 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/import/ShapeFile.class.php @@ -0,0 +1,102 @@ +_loadHeaders(); + $this->_loadRecords(); + if ($this->_isDbaseLoaded()) { + $this->_closeDBFFile(); + } + } + + /** + * Loads metadata from the ESRI shape file header + * + * @return void + * @see ShapeFile::_loadHeaders() + */ + function _loadHeaders() + { + ImportShp::readFromBuffer(24); + $this->fileLength = loadData("N", ImportShp::readFromBuffer(4)); + + ImportShp::readFromBuffer(4); + $this->shapeType = loadData("V", ImportShp::readFromBuffer(4)); + + $this->boundingBox = array(); + $this->boundingBox["xmin"] = loadData("d", ImportShp::readFromBuffer(8)); + $this->boundingBox["ymin"] = loadData("d", ImportShp::readFromBuffer(8)); + $this->boundingBox["xmax"] = loadData("d", ImportShp::readFromBuffer(8)); + $this->boundingBox["ymax"] = loadData("d", ImportShp::readFromBuffer(8)); + + if ($this->_isDbaseLoaded() && $this->_openDBFFile()) { + $this->DBFHeader = $this->_loadDBFHeader(); + } + } + + /** + * Loads geometry data from the ESRI shape file + * + * @return boolean|void + * @see ShapeFile::_loadRecords() + */ + function _loadRecords() + { + global $eof; + ImportShp::readFromBuffer(32); + while (true) { + $record = new PMA_ShapeRecord(-1); + $record->loadFromFile($this->SHPFile, $this->DBFFile); + if ($record->lastError != "") { + return false; + } + if ($eof) { + break; + } + + $this->records[] = $record; + } + } +} +?> diff --git a/phpMyAdmin/libraries/plugins/import/ShapeRecord.class.php b/phpMyAdmin/libraries/plugins/import/ShapeRecord.class.php new file mode 100644 index 0000000..7317c00 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/import/ShapeRecord.class.php @@ -0,0 +1,161 @@ +DBFFile = $DBFFile; + $this->_loadHeaders(); + + switch ($this->shapeType) { + case 0: + $this->_loadNullRecord(); + break; + case 1: + $this->_loadPointRecord(); + break; + case 3: + $this->_loadPolyLineRecord(); + break; + case 5: + $this->_loadPolygonRecord(); + break; + case 8: + $this->_loadMultiPointRecord(); + break; + default: + $this->setError( + sprintf( + __("Geometry type '%s' is not supported by MySQL."), + $this->shapeType + ) + ); + break; + } + if (extension_loaded('dbase') && isset($this->DBFFile)) { + $this->_loadDBFData(); + } + } + + /** + * Loads metadata from the ESRI shape record header + * + * @return void + * @see ShapeRecord::_loadHeaders() + */ + function _loadHeaders() + { + $this->recordNumber = loadData("N", ImportShp::readFromBuffer(4)); + ImportShp::readFromBuffer(4); + $this->shapeType = loadData("V", ImportShp::readFromBuffer(4)); + } + + /** + * Loads data from a point record + * + * @return array + * @see ShapeRecord::_loadPoint() + */ + function _loadPoint() + { + $data = array(); + + $data["x"] = loadData("d", ImportShp::readFromBuffer(8)); + $data["y"] = loadData("d", ImportShp::readFromBuffer(8)); + + return $data; + } + + /** + * Loads data from a multipoint record + * + * @return void + * @see ShapeRecord::_loadMultiPointRecord() + */ + function _loadMultiPointRecord() + { + $this->SHPData = array(); + $this->SHPData["xmin"] = loadData("d", ImportShp::readFromBuffer(8)); + $this->SHPData["ymin"] = loadData("d", ImportShp::readFromBuffer(8)); + $this->SHPData["xmax"] = loadData("d", ImportShp::readFromBuffer(8)); + $this->SHPData["ymax"] = loadData("d", ImportShp::readFromBuffer(8)); + + $this->SHPData["numpoints"] = loadData("V", ImportShp::readFromBuffer(4)); + + for ($i = 0; $i <= $this->SHPData["numpoints"]; $i++) { + $this->SHPData["points"][] = $this->_loadPoint(); + } + } + + /** + * Loads data from a polyline record + * + * @return void + * @see ShapeRecord::_loadPolyLineRecord() + */ + function _loadPolyLineRecord() + { + $this->SHPData = array(); + $this->SHPData["xmin"] = loadData("d", ImportShp::readFromBuffer(8)); + $this->SHPData["ymin"] = loadData("d", ImportShp::readFromBuffer(8)); + $this->SHPData["xmax"] = loadData("d", ImportShp::readFromBuffer(8)); + $this->SHPData["ymax"] = loadData("d", ImportShp::readFromBuffer(8)); + + $this->SHPData["numparts"] = loadData("V", ImportShp::readFromBuffer(4)); + $this->SHPData["numpoints"] = loadData("V", ImportShp::readFromBuffer(4)); + + for ($i = 0; $i < $this->SHPData["numparts"]; $i++) { + $this->SHPData["parts"][$i] = loadData( + "V", ImportShp::readFromBuffer(4) + ); + } + + $readPoints = 0; + reset($this->SHPData["parts"]); + while (list($partIndex, $partData) = each($this->SHPData["parts"])) { + if (! isset($this->SHPData["parts"][$partIndex]["points"]) + || !is_array($this->SHPData["parts"][$partIndex]["points"]) + ) { + $this->SHPData["parts"][$partIndex] = array(); + $this->SHPData["parts"][$partIndex]["points"] = array(); + } + while (! in_array($readPoints, $this->SHPData["parts"]) + && ($readPoints < ($this->SHPData["numpoints"])) + ) { + $this->SHPData["parts"][$partIndex]["points"][] + = $this->_loadPoint(); + $readPoints++; + } + } + } +} +?> diff --git a/phpMyAdmin/libraries/plugins/import/upload/UploadApc.class.php b/phpMyAdmin/libraries/plugins/import/upload/UploadApc.class.php new file mode 100644 index 0000000..3ddb7a7 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/import/upload/UploadApc.class.php @@ -0,0 +1,84 @@ + $id, + 'finished' => false, + 'percent' => 0, + 'total' => 0, + 'complete' => 0, + 'plugin' => UploadApc::getIdKey() + ); + } + $ret = $_SESSION[$SESSION_KEY][$id]; + + if (! PMA_Import_apcCheck() || $ret['finished']) { + return $ret; + } + $status = apc_fetch('upload_' . $id); + + if ($status) { + $ret['finished'] = (bool)$status['done']; + $ret['total'] = $status['total']; + $ret['complete'] = $status['current']; + + if ($ret['total'] > 0) { + $ret['percent'] = $ret['complete'] / $ret['total'] * 100; + } + + if ($ret['percent'] == 100) { + $ret['finished'] = (bool)true; + } + + $_SESSION[$SESSION_KEY][$id] = $ret; + } + + return $ret; + } +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/import/upload/UploadNoplugin.class.php b/phpMyAdmin/libraries/plugins/import/upload/UploadNoplugin.class.php new file mode 100644 index 0000000..90148de --- /dev/null +++ b/phpMyAdmin/libraries/plugins/import/upload/UploadNoplugin.class.php @@ -0,0 +1,64 @@ + $id, + 'finished' => false, + 'percent' => 0, + 'total' => 0, + 'complete' => 0, + 'plugin' => UploadNoplugin::getIdKey() + ); + } + $ret = $_SESSION[$SESSION_KEY][$id]; + + return $ret; + } +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/import/upload/UploadProgress.class.php b/phpMyAdmin/libraries/plugins/import/upload/UploadProgress.class.php new file mode 100644 index 0000000..d7647b3 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/import/upload/UploadProgress.class.php @@ -0,0 +1,94 @@ + $id, + 'finished' => false, + 'percent' => 0, + 'total' => 0, + 'complete' => 0, + 'plugin' => UploadProgress::getIdKey() + ); + } + $ret = $_SESSION[$SESSION_KEY][$id]; + + if (! PMA_Import_progressCheck() || $ret['finished']) { + return $ret; + } + + $status = uploadprogress_get_info($id); + + if ($status) { + if ($status['bytes_uploaded'] == $status['bytes_total']) { + $ret['finished'] = true; + } else { + $ret['finished'] = false; + } + $ret['total'] = $status['bytes_total']; + $ret['complete'] = $status['bytes_uploaded']; + + if ($ret['total'] > 0) { + $ret['percent'] = $ret['complete'] / $ret['total'] * 100; + } + } else { + $ret = array( + 'id' => $id, + 'finished' => true, + 'percent' => 100, + 'total' => $ret['total'], + 'complete' => $ret['total'], + 'plugin' => UploadProgress::getIdKey() + ); + } + + $_SESSION[$SESSION_KEY][$id] = $ret; + return $ret; + } +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/import/upload/UploadSession.class.php b/phpMyAdmin/libraries/plugins/import/upload/UploadSession.class.php new file mode 100644 index 0000000..d9bdd53 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/import/upload/UploadSession.class.php @@ -0,0 +1,96 @@ + $id, + 'finished' => false, + 'percent' => 0, + 'total' => 0, + 'complete' => 0, + 'plugin' => UploadSession::getIdKey() + ); + } + $ret = $_SESSION[$SESSION_KEY][$id]; + + if (! PMA_Import_sessionCheck() || $ret['finished']) { + return $ret; + } + + $status = false; + $sessionkey = ini_get('session.upload_progress.prefix') . $id; + + if (isset($_SESSION[$sessionkey])) { + $status = $_SESSION[$sessionkey]; + } + + if ($status) { + $ret['finished'] = $status['done']; + $ret['total'] = $status['content_length']; + $ret['complete'] = $status['bytes_processed']; + + if ($ret['total'] > 0) { + $ret['percent'] = $ret['complete'] / $ret['total'] * 100; + } + } else { + $ret = array( + 'id' => $id, + 'finished' => true, + 'percent' => 100, + 'total' => $ret['total'], + 'complete' => $ret['total'], + 'plugin' => UploadSession::getIdKey() + ); + } + + $_SESSION[$SESSION_KEY][$id] = $ret; + + return $ret; + } +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/transformations/Application_Octetstream_Download.class.php b/phpMyAdmin/libraries/plugins/transformations/Application_Octetstream_Download.class.php new file mode 100644 index 0000000..069eda7 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/Application_Octetstream_Download.class.php @@ -0,0 +1,43 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/transformations/Application_Octetstream_Hex.class.php b/phpMyAdmin/libraries/plugins/transformations/Application_Octetstream_Hex.class.php new file mode 100644 index 0000000..f6f4297 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/Application_Octetstream_Hex.class.php @@ -0,0 +1,44 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/transformations/Image_JPEG_Inline.class.php b/phpMyAdmin/libraries/plugins/transformations/Image_JPEG_Inline.class.php new file mode 100644 index 0000000..501205a --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/Image_JPEG_Inline.class.php @@ -0,0 +1,44 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/transformations/Image_JPEG_Link.class.php b/phpMyAdmin/libraries/plugins/transformations/Image_JPEG_Link.class.php new file mode 100644 index 0000000..ca3c1d1 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/Image_JPEG_Link.class.php @@ -0,0 +1,44 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/transformations/Image_PNG_Inline.class.php b/phpMyAdmin/libraries/plugins/transformations/Image_PNG_Inline.class.php new file mode 100644 index 0000000..40b709d --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/Image_PNG_Inline.class.php @@ -0,0 +1,44 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/transformations/README b/phpMyAdmin/libraries/plugins/transformations/README new file mode 100644 index 0000000..7d7a125 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/README @@ -0,0 +1,4 @@ +TRANSFORMATION USAGE (Garvin Hicking, ) +==================== + +See the documentation for complete instructions on how to use transformation plugins. diff --git a/phpMyAdmin/libraries/plugins/transformations/TEMPLATE b/phpMyAdmin/libraries/plugins/transformations/TEMPLATE new file mode 100644 index 0000000..6f116ce --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/TEMPLATE @@ -0,0 +1,46 @@ + diff --git a/phpMyAdmin/libraries/plugins/transformations/TEMPLATE_ABSTRACT b/phpMyAdmin/libraries/plugins/transformations/TEMPLATE_ABSTRACT new file mode 100644 index 0000000..5cc1d26 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/TEMPLATE_ABSTRACT @@ -0,0 +1,89 @@ +mimetype contains the original MimeType of the field (i.e. 'text/plain', 'image/jpeg' etc.) + + return $buffer; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the TransformationName of the specific plugin + * + * @return string + */ + public static function getName() + { + return "[TransformationName]"; + } +} +?> diff --git a/phpMyAdmin/libraries/plugins/transformations/Text_Plain_Append.class.php b/phpMyAdmin/libraries/plugins/transformations/Text_Plain_Append.class.php new file mode 100644 index 0000000..567c2cc --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/Text_Plain_Append.class.php @@ -0,0 +1,45 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/transformations/Text_Plain_Dateformat.class.php b/phpMyAdmin/libraries/plugins/transformations/Text_Plain_Dateformat.class.php new file mode 100644 index 0000000..70db98a --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/Text_Plain_Dateformat.class.php @@ -0,0 +1,44 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/transformations/Text_Plain_External.class.php b/phpMyAdmin/libraries/plugins/transformations/Text_Plain_External.class.php new file mode 100644 index 0000000..18da613 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/Text_Plain_External.class.php @@ -0,0 +1,44 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/transformations/Text_Plain_Formatted.class.php b/phpMyAdmin/libraries/plugins/transformations/Text_Plain_Formatted.class.php new file mode 100644 index 0000000..3942a93 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/Text_Plain_Formatted.class.php @@ -0,0 +1,44 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/transformations/Text_Plain_Imagelink.class.php b/phpMyAdmin/libraries/plugins/transformations/Text_Plain_Imagelink.class.php new file mode 100644 index 0000000..670e52e --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/Text_Plain_Imagelink.class.php @@ -0,0 +1,44 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/transformations/Text_Plain_Link.class.php b/phpMyAdmin/libraries/plugins/transformations/Text_Plain_Link.class.php new file mode 100644 index 0000000..d1b17d5 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/Text_Plain_Link.class.php @@ -0,0 +1,44 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/transformations/Text_Plain_Longtoipv4.class.php b/phpMyAdmin/libraries/plugins/transformations/Text_Plain_Longtoipv4.class.php new file mode 100644 index 0000000..9f58a45 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/Text_Plain_Longtoipv4.class.php @@ -0,0 +1,44 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/transformations/Text_Plain_Sql.class.php b/phpMyAdmin/libraries/plugins/transformations/Text_Plain_Sql.class.php new file mode 100644 index 0000000..1987ba9 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/Text_Plain_Sql.class.php @@ -0,0 +1,44 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/transformations/Text_Plain_Substring.class.php b/phpMyAdmin/libraries/plugins/transformations/Text_Plain_Substring.class.php new file mode 100644 index 0000000..051ae51 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/Text_Plain_Substring.class.php @@ -0,0 +1,44 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/transformations/abstract/AppendTransformationsPlugin.class.php b/phpMyAdmin/libraries/plugins/transformations/abstract/AppendTransformationsPlugin.class.php new file mode 100644 index 0000000..86bb0be --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/abstract/AppendTransformationsPlugin.class.php @@ -0,0 +1,84 @@ + diff --git a/phpMyAdmin/libraries/plugins/transformations/abstract/DateFormatTransformationsPlugin.class.php b/phpMyAdmin/libraries/plugins/transformations/abstract/DateFormatTransformationsPlugin.class.php new file mode 100644 index 0000000..b687934 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/abstract/DateFormatTransformationsPlugin.class.php @@ -0,0 +1,178 @@ +type == 'int') { + $timestamp = $buffer; + + // Detect TIMESTAMP(6 | 8 | 10 | 12 | 14) + // TIMESTAMP (2 | 4) not supported here. + // (Note: prior to MySQL 4.1, TIMESTAMP has a display size + // for example TIMESTAMP(8) means YYYYMMDD) + } else if (preg_match('/^(\d{2}){3,7}$/', $buffer)) { + + if (strlen($buffer) == 14 || strlen($buffer) == 8) { + $offset = 4; + } else { + $offset = 2; + } + + $d = array(); + $d['year'] = substr($buffer, 0, $offset); + $d['month'] = substr($buffer, $offset, 2); + $d['day'] = substr($buffer, $offset + 2, 2); + $d['hour'] = substr($buffer, $offset + 4, 2); + $d['minute'] = substr($buffer, $offset + 6, 2); + $d['second'] = substr($buffer, $offset + 8, 2); + + if (checkdate($d['month'], $d['day'], $d['year'])) { + $timestamp = mktime( + $d['hour'], + $d['minute'], + $d['second'], + $d['month'], + $d['day'], + $d['year'] + ); + } + // If all fails, assume one of the dozens of valid strtime() syntaxes + // (http://www.gnu.org/manual/tar-1.12/html_chapter/tar_7.html) + } else { + if (preg_match('/^[0-9]\d{1,9}$/', $buffer)) { + $timestamp = (int)$buffer; + } else { + $timestamp = strtotime($buffer); + } + } + + // If all above failed, maybe it's a Unix timestamp already? + if ($timestamp < 0 && preg_match('/^[1-9]\d{1,9}$/', $buffer)) { + $timestamp = $buffer; + } + + // Reformat a valid timestamp + if ($timestamp >= 0) { + $timestamp -= $options[0] * 60 * 60; + $source = $buffer; + if ($options[2] == 'local') { + $text = PMA_Util::localisedDate( + $timestamp, + $options[1] + ); + } elseif ($options[2] == 'utc') { + $text = gmdate($options[1], $timestamp); + } else { + $text = 'INVALID DATE TYPE'; + } + $buffer = '' . $text . ''; + } + + return $buffer; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the transformation name of the specific plugin + * + * @return string + */ + public static function getName() + { + return "Date Format"; + } +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/transformations/abstract/DownloadTransformationsPlugin.class.php b/phpMyAdmin/libraries/plugins/transformations/abstract/DownloadTransformationsPlugin.class.php new file mode 100644 index 0000000..134fb7f --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/abstract/DownloadTransformationsPlugin.class.php @@ -0,0 +1,110 @@ + $val) { + if ($val->name == $options[1]) { + $pos = $key; + break; + } + } + if (isset($pos)) { + $cn = $row[$pos]; + } + } + if (empty($cn)) { + $cn = 'binary_file.dat'; + } + } + + return sprintf( + '%s', + $options['wrapper_link'], + urlencode($cn), + htmlspecialchars($cn), + htmlspecialchars($cn) + ); + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the transformation name of the specific plugin + * + * @return string + */ + public static function getName() + { + return "Download"; + } +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/transformations/abstract/ExternalTransformationsPlugin.class.php b/phpMyAdmin/libraries/plugins/transformations/abstract/ExternalTransformationsPlugin.class.php new file mode 100644 index 0000000..86ba1ac --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/abstract/ExternalTransformationsPlugin.class.php @@ -0,0 +1,182 @@ += 4.3.0 + $newstring = ''; + $descriptorspec = array( + 0 => array("pipe", "r"), + 1 => array("pipe", "w") + ); + $process = proc_open($program . ' ' . $poptions, $descriptorspec, $pipes); + if (is_resource($process)) { + fwrite($pipes[0], $buffer); + fclose($pipes[0]); + + while (!feof($pipes[1])) { + $newstring .= fgets($pipes[1], 1024); + } + fclose($pipes[1]); + // we don't currently use the return value + proc_close($process); + } + + if ($options[2] == 1 || $options[2] == '2') { + $retstring = htmlspecialchars($newstring); + } else { + $retstring = $newstring; + } + + return $retstring; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the transformation name of the specific plugin + * + * @return string + */ + public static function getName() + { + return "External"; + } +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/transformations/abstract/FormattedTransformationsPlugin.class.php b/phpMyAdmin/libraries/plugins/transformations/abstract/FormattedTransformationsPlugin.class.php new file mode 100644 index 0000000..7a39e45 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/abstract/FormattedTransformationsPlugin.class.php @@ -0,0 +1,80 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/transformations/abstract/HexTransformationsPlugin.class.php b/phpMyAdmin/libraries/plugins/transformations/abstract/HexTransformationsPlugin.class.php new file mode 100644 index 0000000..2809837 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/abstract/HexTransformationsPlugin.class.php @@ -0,0 +1,91 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/transformations/abstract/ImageLinkTransformationsPlugin.class.php b/phpMyAdmin/libraries/plugins/transformations/abstract/ImageLinkTransformationsPlugin.class.php new file mode 100644 index 0000000..d5059fd --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/abstract/ImageLinkTransformationsPlugin.class.php @@ -0,0 +1,87 @@ + '[BLOB]' + ); + return PMA_Transformation_globalHtmlReplace( + $buffer, + $transform_options + ); + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the transformation name of the specific plugin + * + * @return string + */ + public static function getName() + { + return "ImageLink"; + } +} +?> diff --git a/phpMyAdmin/libraries/plugins/transformations/abstract/InlineTransformationsPlugin.class.php b/phpMyAdmin/libraries/plugins/transformations/abstract/InlineTransformationsPlugin.class.php new file mode 100644 index 0000000..e6c9ca8 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/abstract/InlineTransformationsPlugin.class.php @@ -0,0 +1,101 @@ + '[__BUFFER__]' + ); + } else { + $transform_options = array ( + 'string' => '[__BUFFER__]' + ); + } + return PMA_Transformation_globalHtmlReplace( + $buffer, + $transform_options + ); + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the transformation name of the specific plugin + * + * @return string + */ + public static function getName() + { + return "Inline"; + } +} +?> diff --git a/phpMyAdmin/libraries/plugins/transformations/abstract/LongToIPv4TransformationsPlugin.class.php b/phpMyAdmin/libraries/plugins/transformations/abstract/LongToIPv4TransformationsPlugin.class.php new file mode 100644 index 0000000..d1431ce --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/abstract/LongToIPv4TransformationsPlugin.class.php @@ -0,0 +1,83 @@ + 4294967295) { + return $buffer; + } + + return long2ip($buffer); + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the transformation name of the specific plugin + * + * @return string + */ + public static function getName() + { + return "Long To IPv4"; + } +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/transformations/abstract/SQLTransformationsPlugin.class.php b/phpMyAdmin/libraries/plugins/transformations/abstract/SQLTransformationsPlugin.class.php new file mode 100644 index 0000000..991f54d --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/abstract/SQLTransformationsPlugin.class.php @@ -0,0 +1,82 @@ + diff --git a/phpMyAdmin/libraries/plugins/transformations/abstract/SubstringTransformationsPlugin.class.php b/phpMyAdmin/libraries/plugins/transformations/abstract/SubstringTransformationsPlugin.class.php new file mode 100644 index 0000000..b6fb75a --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/abstract/SubstringTransformationsPlugin.class.php @@ -0,0 +1,118 @@ +substr( + $buffer, $options[0], $options[1] + ); + } else { + $newtext = $GLOBALS['PMA_String']->substr($buffer, $options[0]); + } + + $length = strlen($newtext); + $baselength = strlen($buffer); + if ($length != $baselength) { + if ($options[0] != 0) { + $newtext = $options[2] . $newtext; + } + + if (($length + $options[0]) != $baselength) { + $newtext .= $options[2]; + } + } + + return $newtext; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the transformation name of the specific plugin + * + * @return string + */ + public static function getName() + { + return "Substring"; + } +} +?> diff --git a/phpMyAdmin/libraries/plugins/transformations/abstract/TextImageLinkTransformationsPlugin.class.php b/phpMyAdmin/libraries/plugins/transformations/abstract/TextImageLinkTransformationsPlugin.class.php new file mode 100644 index 0000000..a1824c9 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/abstract/TextImageLinkTransformationsPlugin.class.php @@ -0,0 +1,96 @@ + '' + . $buffer . '' + ); + + $buffer = PMA_Transformation_globalHtmlReplace( + $buffer, + $transform_options + ); + + return $buffer; + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the transformation name of the specific plugin + * + * @return string + */ + public static function getName() + { + return "Image Link"; + } +} +?> diff --git a/phpMyAdmin/libraries/plugins/transformations/abstract/TextLinkTransformationsPlugin.class.php b/phpMyAdmin/libraries/plugins/transformations/abstract/TextLinkTransformationsPlugin.class.php new file mode 100644 index 0000000..da8fb59 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/abstract/TextLinkTransformationsPlugin.class.php @@ -0,0 +1,98 @@ + '' + . htmlspecialchars(isset($options[1]) ? $options[1] : $buffer) + . '' + ); + + return PMA_Transformation_globalHtmlReplace( + $buffer, + $transform_options + ); + } + + /** + * This method is called when any PluginManager to which the observer + * is attached calls PluginManager::notify() + * + * @param SplSubject $subject The PluginManager notifying the observer + * of an update. + * + * @todo implement + * @return void + */ + public function update (SplSubject $subject) + { + ; + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the transformation name of the specific plugin + * + * @return string + */ + public static function getName() + { + return "TextLink"; + } +} +?> diff --git a/phpMyAdmin/libraries/plugins/transformations/generator_main_class.sh b/phpMyAdmin/libraries/plugins/transformations/generator_main_class.sh new file mode 100755 index 0000000..0587667 --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/generator_main_class.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# +# Shell script that creates only the main class for a new transformation +# plug-in, using a template +# +# $1: MIMEType +# $2: MIMESubtype +# $3: Transformation Name + +if [ $# != 3 ] +then + echo -e "Usage: ./generator_main_class.sh MIMEType MIMESubtype TransformationName\n" + exit 65 +fi + +./generator_plugin.sh "$1" "$2" "$3" "--generate_only_main_class" \ No newline at end of file diff --git a/phpMyAdmin/libraries/plugins/transformations/generator_plugin.sh b/phpMyAdmin/libraries/plugins/transformations/generator_plugin.sh new file mode 100755 index 0000000..225a2cb --- /dev/null +++ b/phpMyAdmin/libraries/plugins/transformations/generator_plugin.sh @@ -0,0 +1,64 @@ +#!/bin/bash +# +# Shell script that creates a new transformation plug-in (both main and +# abstract class) using a template. +# +# The 'description' parameter will add a new entry in the language file. +# Watch out for special escaping. +# +# $1: MIMEType +# $2: MIMESubtype +# $3: Transformation Name +# $4: (optional) Description + +echo $# +if [ $# -ne 3 -a $# -ne 4 ]; then + echo -e "Usage: ./generator_plugin.sh MIMEType MIMESubtype TransformationName [Description]\n" + exit 65 +fi + +# make sure that the MIME Type, MIME Subtype and Transformation names +# are in the correct format + +# make all names lowercase +MT="`echo $1 | tr [:upper:] [:lower:]`" +MS="`echo $2 | tr [:upper:] [:lower:]`" +TN="`echo $3 | tr [:upper:] [:lower:]`" +# make first letter uppercase +MT="${MT^}" +MS="${MS^}" +TN="${TN^}" +# make the first letter after each underscore uppercase +MT="`echo $MT`" +MT="`echo $MT | sed -e 's/_./\U&\E/g'`" +MS="`echo $MS`" +MS="`echo $MS | sed -e 's/_./\U&\E/g'`" +TN="`echo $TN`" +TN="`echo $TN | sed -e 's/_./\U&\E/g'`" + +# define the name of the main class file and of its template +ClassFile=$MT\_$MS\_$TN.class.php +Template=TEMPLATE +# define the name of the abstract class file and its template +AbstractClassFile=abstract/"$TN"TransformationsPlugin.class.php +AbstractTemplate=TEMPLATE_ABSTRACT +# replace template names with argument names +sed "s/\[MIMEType]/$MT/; s/\[MIMESubtype\]/$MS/; s/\[TransformationName\]/$TN/;" < $Template > $ClassFile +echo "Created $ClassFile" + +GenerateAbstractClass=1 +if [ -n $4 ]; then + if [ "$4" == "--generate_only_main_class" ]; then + if [ -e $AbstractClassFile ]; then + GenerateAbstractClass=0 + fi + fi +fi + +if [ $GenerateAbstractClass -eq 1 ]; then + # replace template names with argument names + sed "s/\[TransformationName\]/$TN/; s/Description of the transformation./$4/;" < $AbstractTemplate > $AbstractClassFile + echo "Created $AbstractClassFile" +fi + +echo "" \ No newline at end of file diff --git a/phpMyAdmin/libraries/pmd_common.php b/phpMyAdmin/libraries/pmd_common.php index d5f13e2..6583991 100644 --- a/phpMyAdmin/libraries/pmd_common.php +++ b/phpMyAdmin/libraries/pmd_common.php @@ -3,85 +3,103 @@ /** * @package PhpMyAdmin-Designer */ +/** + * block attempts to directly run this script + */ +if (getcwd() == dirname(__FILE__)) { + die('Attack stopped'); +} /** * */ -require_once './libraries/common.inc.php'; -// not understand -require_once './libraries/header_http.inc.php'; +if (! defined('PHPMYADMIN')) { + exit; +} $GLOBALS['PMD']['STYLE'] = 'default'; $cfgRelation = PMA_getRelationsParam(); -$GLOBALS['script_display_field'] - = '' . "\n"; - // return $GLOBALS['PMD']; // many bases // not use ?????? + return $retval; } /** * retrieves table column info * - * @return array table column nfo + * @return array table column nfo */ -function get_tab_info() +function get_columns_info() { - PMA_DBI_select_db($GLOBALS['db']); + $GLOBALS['dbi']->selectDb($GLOBALS['db']); $tab_column = array(); for ($i = 0, $cnt = count($GLOBALS['PMD']["TABLE_NAME"]); $i < $cnt; $i++) { - $fields_rs = PMA_DBI_query(PMA_DBI_get_columns_sql($GLOBALS['db'], $GLOBALS['PMD']["TABLE_NAME_SMALL"][$i], null, true), null, PMA_DBI_QUERY_STORE); + $fields_rs = $GLOBALS['dbi']->query( + $GLOBALS['dbi']->getColumnsSql( + $GLOBALS['db'], + $GLOBALS['PMD']["TABLE_NAME_SMALL"][$i], + null, + true + ), + null, + PMA_DatabaseInterface::QUERY_STORE + ); + $tbl_name_i = $GLOBALS['PMD']['TABLE_NAME'][$i]; $j = 0; - while ($row = PMA_DBI_fetch_assoc($fields_rs)) { - $tab_column[$GLOBALS['PMD']['TABLE_NAME'][$i]]['COLUMN_ID'][$j] = $j; - $tab_column[$GLOBALS['PMD']['TABLE_NAME'][$i]]['COLUMN_NAME'][$j] = $row['Field']; - $tab_column[$GLOBALS['PMD']['TABLE_NAME'][$i]]['TYPE'][$j] = $row['Type']; - $tab_column[$GLOBALS['PMD']['TABLE_NAME'][$i]]['NULLABLE'][$j] = $row['Null']; + while ($row = $GLOBALS['dbi']->fetchAssoc($fields_rs)) { + $tab_column[$tbl_name_i]['COLUMN_ID'][$j] = $j; + $tab_column[$tbl_name_i]['COLUMN_NAME'][$j] = $row['Field']; + $tab_column[$tbl_name_i]['TYPE'][$j] = $row['Type']; + $tab_column[$tbl_name_i]['NULLABLE'][$j] = $row['Null']; $j++; } } @@ -95,11 +113,15 @@ function get_tab_info() */ function get_script_contr() { - PMA_DBI_select_db($GLOBALS['db']); + $GLOBALS['dbi']->selectDb($GLOBALS['db']); $con["C_NAME"] = array(); $i = 0; - $alltab_rs = PMA_DBI_query('SHOW TABLES FROM ' . PMA_backquote($GLOBALS['db']), null, PMA_DBI_QUERY_STORE); - while ($val = @PMA_DBI_fetch_row($alltab_rs)) { + $alltab_rs = $GLOBALS['dbi']->query( + 'SHOW TABLES FROM ' . PMA_Util::backquote($GLOBALS['db']), + null, + PMA_DatabaseInterface::QUERY_STORE + ); + while ($val = @$GLOBALS['dbi']->fetchRow($alltab_rs)) { $row = PMA_getForeigners($GLOBALS['db'], $val[0], '', 'internal'); //echo "
    internal ".$GLOBALS['db']." - ".$val[0]." - "; //print_r($row); @@ -108,7 +130,9 @@ function get_script_contr() $con['C_NAME'][$i] = ''; $con['DTN'][$i] = urlencode($GLOBALS['db'] . "." . $val[0]); $con['DCN'][$i] = urlencode($field); - $con['STN'][$i] = urlencode($value['foreign_db'] . "." . $value['foreign_table']); + $con['STN'][$i] = urlencode( + $value['foreign_db'] . "." . $value['foreign_table'] + ); $con['SCN'][$i] = urlencode($value['foreign_field']); $i++; } @@ -121,7 +145,9 @@ function get_script_contr() $con['C_NAME'][$i] = ''; $con['DTN'][$i] = urlencode($GLOBALS['db'].".".$val[0]); $con['DCN'][$i] = urlencode($field); - $con['STN'][$i] = urlencode($value['foreign_db'].".".$value['foreign_table']); + $con['STN'][$i] = urlencode( + $value['foreign_db'].".".$value['foreign_table'] + ); $con['SCN'][$i] = urlencode($value['foreign_field']); $i++; } @@ -129,35 +155,30 @@ function get_script_contr() } $ti = 0; - $script_contr - = '' . "\n"; - return $script_contr; + return $retval; } /** - * @return array unique or primary indizes + * Returns UNIQUE and PRIMARY indices + * + * @return array unique or primary indices */ function get_pk_or_unique_keys() { @@ -165,10 +186,11 @@ function get_pk_or_unique_keys() } /** - * returns all indizes + * returns all indices + * + * @param bool $unique_only whether to include only unique ones * - * @param boolean whether to include ony unique ones - * @return array indizes + * @return array indices */ function get_all_keys($unique_only = false) { @@ -193,30 +215,32 @@ function get_all_keys($unique_only = false) } /** + * Return script to create j_tab and h_tab arrays * - * - * @return array ??? + * @return string */ function get_script_tabs() { - $script_tabs - = '' . "\n"; - return $script_tabs; + return $retval; } /** - * @return array table positions and sizes + * Returns table position + * + * @return array table positions and sizes */ function get_tab_pos() { @@ -232,20 +256,29 @@ function get_tab_pos() `y` AS `Y`, `v` AS `V`, `h` AS `H` - FROM " . PMA_backquote($cfgRelation['db']) . "." . PMA_backquote($cfgRelation['designer_coords']); - $tab_pos = PMA_DBI_fetch_result($query, 'name', null, $GLOBALS['controllink'], PMA_DBI_QUERY_STORE); + FROM " . PMA_Util::backquote($cfgRelation['db']) + . "." . PMA_Util::backquote($cfgRelation['designer_coords']); + $tab_pos = $GLOBALS['dbi']->fetchResult( + $query, + 'name', + null, + $GLOBALS['controllink'], + PMA_DatabaseInterface::QUERY_STORE + ); return count($tab_pos) ? $tab_pos : null; } /** - * returns distinct values from $GLOBALS['PMD']['OWNER'] + * Prepares XML output for js/pmd/ajax.js to display a message * - * @return array owner */ -function get_owners() +function PMD_return_upd($b, $ret) { - return array_values(array_unique($GLOBALS['PMD']['OWNER'])); -} + // not sure where this was defined... + global $K; -get_tabs(); + header("Content-Type: text/xml; charset=utf-8"); + header("Cache-Control: no-cache"); + die(''); +} ?> diff --git a/phpMyAdmin/libraries/properties/PropertyItem.class.php b/phpMyAdmin/libraries/properties/PropertyItem.class.php new file mode 100644 index 0000000..83a5b26 --- /dev/null +++ b/phpMyAdmin/libraries/properties/PropertyItem.class.php @@ -0,0 +1,49 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/properties/options/OptionsPropertyGroup.class.php b/phpMyAdmin/libraries/properties/options/OptionsPropertyGroup.class.php new file mode 100644 index 0000000..fe2fe40 --- /dev/null +++ b/phpMyAdmin/libraries/properties/options/OptionsPropertyGroup.class.php @@ -0,0 +1,102 @@ +getProperties() == null + && in_array($property, $this->getProperties(), true) + ) { + return; + } + $this->_properties [] = $property; + } + + /** + * Removes a property from the group of properties + * + * @param OptionsPropertyItem $property the property instance to be removed + * from the group + * + * @return void + */ + public function removeProperty($property) + { + $this->_properties = array_udiff( + $this->getProperties(), + array($property), + function ($a, $b) { + return ($a === $b ) ? 0 : 1; + } + ); + } + + + /* ~~~~~~~~~~~~~~~~~~~~ Getters and Setters ~~~~~~~~~~~~~~~~~~~~ */ + + + /** + * Gets the instance of the class + * + * @return array + */ + public function getGroup() + { + return $this; + } + + /** + * Gets the group of properties + * + * @return array + */ + public function getProperties() + { + return $this->_properties; + } + + /** + * Gets the number of properties + * + * @return int + */ + public function getNrOfProperties() + { + return count($this->_properties); + } +} +?> diff --git a/phpMyAdmin/libraries/properties/options/OptionsPropertyItem.class.php b/phpMyAdmin/libraries/properties/options/OptionsPropertyItem.class.php new file mode 100644 index 0000000..a1718a2 --- /dev/null +++ b/phpMyAdmin/libraries/properties/options/OptionsPropertyItem.class.php @@ -0,0 +1,127 @@ +_name; + } + + /** + * Sets the name + * + * @param string $name name + * + * @return void + */ + public function setName($name) + { + $this->_name = $name; + } + + /** + * Gets the text + * + * @return string + */ + public function getText() + { + return $this->_text; + } + + /** + * Sets the text + * + * @param string $text text + * + * @return void + */ + public function setText($text) + { + $this->_text = $text; + } + + /** + * Gets the force parameter + * + * @return string + */ + public function getForce() + { + return $this->_force; + } + + /** + * Sets the force paramter + * + * @param string $force force parameter + * + * @return void + */ + public function setForce($force) + { + $this->_force = $force; + } + + /** + * Returns the property type ( either "options", or "plugin" ). + * + * @return string + */ + public function getPropertyType() + { + return "options"; + } +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/properties/options/OptionsPropertyOneItem.class.php b/phpMyAdmin/libraries/properties/options/OptionsPropertyOneItem.class.php new file mode 100644 index 0000000..e19c15c --- /dev/null +++ b/phpMyAdmin/libraries/properties/options/OptionsPropertyOneItem.class.php @@ -0,0 +1,172 @@ +_force; + } + + /** + * Sets the force parameter + * + * @param bool $force force parameter + * + * @return void + */ + public function setForce($force) + { + $this->_force = $force; + } + + /** + * Gets the values + * + * @return string + */ + public function getValues() + { + return $this->_values; + } + + /** + * Sets the values + * + * @param array $values values + * + * @return void + */ + public function setValues($values) + { + $this->_values = $values; + } + + /** + * Gets the type of the newline character + * + * @return string + */ + public function getDoc() + { + return $this->_doc; + } + + /** + * Sets the doc + * + * @param string $doc doc + * + * @return void + */ + public function setDoc($doc) + { + $this->_doc = $doc; + } + + /** + * Gets the length + * + * @return int + */ + public function getLen() + { + return $this->_len; + } + + /** + * Sets the length + * + * @param int $len length + * + * @return void + */ + public function setLen($len) + { + $this->_len = $len; + } + + /** + * Gets the size + * + * @return int + */ + public function getSize() + { + return $this->_size; + } + + /** + * Sets the size + * + * @param int $size size + * + * @return void + */ + public function setSize($size) + { + $this->_size = $size; + } +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/properties/options/groups/OptionsPropertyMainGroup.class.php b/phpMyAdmin/libraries/properties/options/groups/OptionsPropertyMainGroup.class.php new file mode 100644 index 0000000..4e69aa7 --- /dev/null +++ b/phpMyAdmin/libraries/properties/options/groups/OptionsPropertyMainGroup.class.php @@ -0,0 +1,35 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/properties/options/groups/OptionsPropertyRootGroup.class.php b/phpMyAdmin/libraries/properties/options/groups/OptionsPropertyRootGroup.class.php new file mode 100644 index 0000000..a081744 --- /dev/null +++ b/phpMyAdmin/libraries/properties/options/groups/OptionsPropertyRootGroup.class.php @@ -0,0 +1,35 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/properties/options/groups/OptionsPropertySubgroup.class.php b/phpMyAdmin/libraries/properties/options/groups/OptionsPropertySubgroup.class.php new file mode 100644 index 0000000..0eeb524 --- /dev/null +++ b/phpMyAdmin/libraries/properties/options/groups/OptionsPropertySubgroup.class.php @@ -0,0 +1,68 @@ +_subgroupHeader; + } + + /** + * Sets the subgroup header + * + * @param string $subgroupHeader subgroup header + * + * @return void + */ + public function setSubgroupHeader($subgroupHeader) + { + $this->_subgroupHeader = $subgroupHeader; + } +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/properties/options/items/BoolPropertyItem.class.php b/phpMyAdmin/libraries/properties/options/items/BoolPropertyItem.class.php new file mode 100644 index 0000000..f33067f --- /dev/null +++ b/phpMyAdmin/libraries/properties/options/items/BoolPropertyItem.class.php @@ -0,0 +1,35 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/properties/options/items/DocPropertyItem.class.php b/phpMyAdmin/libraries/properties/options/items/DocPropertyItem.class.php new file mode 100644 index 0000000..55aff61 --- /dev/null +++ b/phpMyAdmin/libraries/properties/options/items/DocPropertyItem.class.php @@ -0,0 +1,35 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/properties/options/items/HiddenPropertyItem.class.php b/phpMyAdmin/libraries/properties/options/items/HiddenPropertyItem.class.php new file mode 100644 index 0000000..53bfe46 --- /dev/null +++ b/phpMyAdmin/libraries/properties/options/items/HiddenPropertyItem.class.php @@ -0,0 +1,35 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/properties/options/items/MessageOnlyPropertyItem.class.php b/phpMyAdmin/libraries/properties/options/items/MessageOnlyPropertyItem.class.php new file mode 100644 index 0000000..98f2e70 --- /dev/null +++ b/phpMyAdmin/libraries/properties/options/items/MessageOnlyPropertyItem.class.php @@ -0,0 +1,35 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/properties/options/items/NumberPropertyItem.class.php b/phpMyAdmin/libraries/properties/options/items/NumberPropertyItem.class.php new file mode 100644 index 0000000..7c687c7 --- /dev/null +++ b/phpMyAdmin/libraries/properties/options/items/NumberPropertyItem.class.php @@ -0,0 +1,35 @@ + diff --git a/phpMyAdmin/libraries/properties/options/items/RadioPropertyItem.class.php b/phpMyAdmin/libraries/properties/options/items/RadioPropertyItem.class.php new file mode 100644 index 0000000..4d8ed7a --- /dev/null +++ b/phpMyAdmin/libraries/properties/options/items/RadioPropertyItem.class.php @@ -0,0 +1,35 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/properties/options/items/SelectPropertyItem.class.php b/phpMyAdmin/libraries/properties/options/items/SelectPropertyItem.class.php new file mode 100644 index 0000000..28460c9 --- /dev/null +++ b/phpMyAdmin/libraries/properties/options/items/SelectPropertyItem.class.php @@ -0,0 +1,35 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/properties/options/items/TextPropertyItem.class.php b/phpMyAdmin/libraries/properties/options/items/TextPropertyItem.class.php new file mode 100644 index 0000000..9339cdf --- /dev/null +++ b/phpMyAdmin/libraries/properties/options/items/TextPropertyItem.class.php @@ -0,0 +1,35 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/properties/plugins/ExportPluginProperties.class.php b/phpMyAdmin/libraries/properties/plugins/ExportPluginProperties.class.php new file mode 100644 index 0000000..6170897 --- /dev/null +++ b/phpMyAdmin/libraries/properties/plugins/ExportPluginProperties.class.php @@ -0,0 +1,214 @@ +_text; + } + + /** + * Sets the text + * + * @param string $text text + * + * @return void + */ + public function setText($text) + { + $this->_text = $text; + } + + /** + * Gets the extension + * + * @return string + */ + public function getExtension() + { + return $this->_extension; + } + + /** + * Sets the extension + * + * @param string $extension extension + * + * @return void + */ + public function setExtension($extension) + { + $this->_extension = $extension; + } + + /** + * Gets the options + * + * @return OptionsPropertyRootGroup + */ + public function getOptions() + { + return $this->_options; + } + + /** + * Sets the options + * + * @param OptionsPropertyRootGroup $options options + * + * @return void + */ + public function setOptions($options) + { + $this->_options = $options; + } + + /** + * Gets the options text + * + * @return string + */ + public function getOptionsText() + { + return $this->_optionsText; + } + + /** + * Sets the options text + * + * @param string $optionsText optionsText + * + * @return void + */ + public function setOptionsText($optionsText) + { + $this->_optionsText = $optionsText; + } + + /** + * Gets the MIME type + * + * @return string + */ + public function getMimeType() + { + return $this->_mimeType; + } + + /** + * Sets the MIME type + * + * @param string $mimeType MIME type + * + * @return void + */ + public function setMimeType($mimeType) + { + $this->_mimeType = $mimeType; + } + + /** + * Gets the force file parameter + * + * @return bool + */ + public function getForceFile() + { + return $this->_forceFile; + } + + /** + * Sets the force file parameter + * + * @param bool $forceFile the force file parameter + * + * @return void + */ + public function setForceFile($forceFile) + { + $this->_forceFile = $forceFile; + } +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/properties/plugins/ImportPluginProperties.class.php b/phpMyAdmin/libraries/properties/plugins/ImportPluginProperties.class.php new file mode 100644 index 0000000..65c3092 --- /dev/null +++ b/phpMyAdmin/libraries/properties/plugins/ImportPluginProperties.class.php @@ -0,0 +1,184 @@ +_text; + } + + /** + * Sets the text + * + * @param string $text text + * + * @return void + */ + public function setText($text) + { + $this->_text = $text; + } + + /** + * Gets the extension + * + * @return string + */ + public function getExtension() + { + return $this->_extension; + } + + /** + * Sets the extension + * + * @param string $extension extension + * + * @return void + */ + public function setExtension($extension) + { + $this->_extension = $extension; + } + + /** + * Gets the options + * + * @return OptionsPropertyRootGroup + */ + public function getOptions() + { + return $this->_options; + } + + /** + * Sets the options + * + * @param OptionsPropertyRootGroup $options options + * + * @return void + */ + public function setOptions($options) + { + $this->_options = $options; + } + + /** + * Gets the options text + * + * @return string + */ + public function getOptionsText() + { + return $this->_optionsText; + } + + /** + * Sets the options text + * + * @param string $optionsText options text + * + * @return void + */ + public function setOptionsText($optionsText) + { + $this->_optionsText = $optionsText; + } + + /** + * Gets the MIME type + * + * @return string + */ + public function getMimeType() + { + return $this->_mimeType; + } + + /** + * Sets the MIME type + * + * @param string $mimeType MIME type + * + * @return void + */ + public function setMimeType($mimeType) + { + $this->_mimeType = $mimeType; + } +} +?> \ No newline at end of file diff --git a/phpMyAdmin/libraries/properties/plugins/PluginPropertyItem.class.php b/phpMyAdmin/libraries/properties/plugins/PluginPropertyItem.class.php new file mode 100644 index 0000000..af46be2 --- /dev/null +++ b/phpMyAdmin/libraries/properties/plugins/PluginPropertyItem.class.php @@ -0,0 +1,36 @@ + \ No newline at end of file diff --git a/phpMyAdmin/libraries/relation.lib.php b/phpMyAdmin/libraries/relation.lib.php index cb6af86..d49ec14 100644 --- a/phpMyAdmin/libraries/relation.lib.php +++ b/phpMyAdmin/libraries/relation.lib.php @@ -16,12 +16,12 @@ * @param boolean $show_error whether to display SQL error messages or not * @param int $options query options * - * @return integer the result set, or false if no result set + * @return integer the result set, or false if no result set * * @access public * */ -function PMA_query_as_controluser($sql, $show_error = true, $options = 0) +function PMA_queryAsControlUser($sql, $show_error = true, $options = 0) { // Avoid caching of the number of rows affected; for example, this function // is called for tracking purposes but we want to display the correct number @@ -30,9 +30,19 @@ function PMA_query_as_controluser($sql, $show_error = true, $options = 0) $cache_affected_rows = false; if ($show_error) { - $result = PMA_DBI_query($sql, $GLOBALS['controllink'], $options, $cache_affected_rows); + $result = $GLOBALS['dbi']->query( + $sql, + $GLOBALS['controllink'], + $options, + $cache_affected_rows + ); } else { - $result = @PMA_DBI_try_query($sql, $GLOBALS['controllink'], $options, $cache_affected_rows); + $result = @$GLOBALS['dbi']->tryQuery( + $sql, + $GLOBALS['controllink'], + $options, + $cache_affected_rows + ); } // end if... else... if ($result) { @@ -40,122 +50,268 @@ function PMA_query_as_controluser($sql, $show_error = true, $options = 0) } else { return false; } -} // end of the "PMA_query_as_controluser()" function +} // end of the "PMA_queryAsControlUser()" function /** - * @param bool $verbose whether to print diagnostic info + * Returns current relation parameters * - * @return array $cfgRelation + * @return array $cfgRelation */ -function PMA_getRelationsParam($verbose = false) +function PMA_getRelationsParam() { + // avoid breakage if pmadb got unconfigured after login + if (! defined('TESTSUITE') && empty($GLOBALS['cfg']['Server']['pmadb'])) { + unset($_SESSION['relation'][$GLOBALS['server']]); + } if (empty($_SESSION['relation'][$GLOBALS['server']])) { - $_SESSION['relation'][$GLOBALS['server']] = PMA__getRelationsParam(); + $_SESSION['relation'][$GLOBALS['server']] = PMA_checkRelationsParam(); } - // just for BC but needs to be before PMA_printRelationsParamDiagnostic() + // just for BC but needs to be before PMA_getRelationsParamDiagnostic() // which uses it $GLOBALS['cfgRelation'] = $_SESSION['relation'][$GLOBALS['server']]; - if ($verbose) { - PMA_printRelationsParamDiagnostic($_SESSION['relation'][$GLOBALS['server']]); - } - return $_SESSION['relation'][$GLOBALS['server']]; } /** * prints out diagnostic info for pma relation feature * - * @param array $cfgRelation + * @param array $cfgRelation Relation configuration * - * @return nothing + * @return string */ -function PMA_printRelationsParamDiagnostic($cfgRelation) +function PMA_getRelationsParamDiagnostic($cfgRelation) { - $messages['error'] = '' . __('not OK') - . ' [ ' - . __('Documentation') . ' ]'; + $retval = ''; + + $messages['error'] = '' + . __('not OK') + . '' + . ' [ ' + . __('Documentation') + . ' ]'; + + $messages['ok'] = '' + . _pgettext('Correctly working', 'OK') + . ''; - $messages['ok'] = '' . __('OK') . ''; $messages['enabled'] = '' . __('Enabled') . ''; $messages['disabled'] = '' . __('Disabled') . ''; if (false === $GLOBALS['cfg']['Server']['pmadb']) { - echo 'PMA Database ... ' + $retval .= 'PMA Database ... ' . sprintf($messages['error'], 'pmadb') . '
    ' . "\n" . __('General relation features') . ' ' . __('Disabled') . '' . "\n"; - return; - } - - echo '' . "\n"; - - PMA_printDiagMessageForParameter('pmadb', $GLOBALS['cfg']['Server']['pmadb'], $messages, 'pmadb'); - - PMA_printDiagMessageForParameter('relation', isset($cfgRelation['relation']), $messages, 'relation'); - - PMA_printDiagMessageForFeature(__('General relation features'), 'relwork', $messages); - - PMA_printDiagMessageForParameter('table_info', isset($cfgRelation['table_info']), $messages, 'table_info'); - - PMA_printDiagMessageForFeature(__('Display Features'), 'displaywork', $messages); - - PMA_printDiagMessageForParameter('table_coords', isset($cfgRelation['table_coords']), $messages, 'table_coords'); - - PMA_printDiagMessageForParameter('pdf_pages', isset($cfgRelation['pdf_pages']), $messages, 'table_coords'); - - PMA_printDiagMessageForFeature(__('Creation of PDFs'), 'pdfwork', $messages); - - PMA_printDiagMessageForParameter('column_info', isset($cfgRelation['column_info']), $messages, 'col_com'); - - PMA_printDiagMessageForFeature(__('Displaying Column Comments'), 'commwork', $messages, false); - - PMA_printDiagMessageForFeature(__('Browser transformation'), 'mimework', $messages); - - if ($cfgRelation['commwork'] && ! $cfgRelation['mimework']) { - echo '' . "\n"; + } else { + $retval .= '
    ' . __('Please see the documentation on how to update your column_comments table') . '
    ' . "\n"; + $retval .= PMA_getDiagMessageForParameter( + 'pmadb', + $GLOBALS['cfg']['Server']['pmadb'], + $messages, + 'pmadb' + ); + $retval .= PMA_getDiagMessageForParameter( + 'relation', + isset($cfgRelation['relation']), + $messages, + 'relation' + ); + $retval .= PMA_getDiagMessageForFeature( + __('General relation features'), + 'relwork', + $messages + ); + $retval .= PMA_getDiagMessageForParameter( + 'table_info', + isset($cfgRelation['table_info']), + $messages, + 'table_info' + ); + $retval .= PMA_getDiagMessageForFeature( + __('Display Features'), + 'displaywork', + $messages + ); + $retval .= PMA_getDiagMessageForParameter( + 'table_coords', + isset($cfgRelation['table_coords']), + $messages, + 'table_coords' + ); + $retval .= PMA_getDiagMessageForParameter( + 'pdf_pages', + isset($cfgRelation['pdf_pages']), + $messages, + 'pdf_pages' + ); + $retval .= PMA_getDiagMessageForFeature( + __('Creation of PDFs'), + 'pdfwork', + $messages + ); + $retval .= PMA_getDiagMessageForParameter( + 'column_info', + isset($cfgRelation['column_info']), + $messages, + 'column_info' + ); + $retval .= PMA_getDiagMessageForFeature( + __('Displaying Column Comments'), + 'commwork', + $messages, + false + ); + $retval .= PMA_getDiagMessageForFeature( + __('Browser transformation'), + 'mimework', + $messages + ); + if ($cfgRelation['commwork'] && ! $cfgRelation['mimework']) { + $retval .= ''; + } + $retval .= PMA_getDiagMessageForParameter( + 'bookmarktable', + isset($cfgRelation['bookmark']), + $messages, + 'bookmark' + ); + $retval .= PMA_getDiagMessageForFeature( + __('Bookmarked SQL query'), + 'bookmarkwork', + $messages + ); + $retval .= PMA_getDiagMessageForParameter( + 'history', + isset($cfgRelation['history']), + $messages, + 'history' + ); + $retval .= PMA_getDiagMessageForFeature( + __('SQL history'), + 'historywork', + $messages + ); + $retval .= PMA_getDiagMessageForParameter( + 'designer_coords', + isset($cfgRelation['designer_coords']), + $messages, + 'designer_coords' + ); + $retval .= PMA_getDiagMessageForFeature( + __('Designer'), + 'designerwork', + $messages + ); + $retval .= PMA_getDiagMessageForParameter( + 'recent', + isset($cfgRelation['recent']), + $messages, + 'recent' + ); + $retval .= PMA_getDiagMessageForFeature( + __('Persistent recently used tables'), + 'recentwork', + $messages + ); + $retval .= PMA_getDiagMessageForParameter( + 'table_uiprefs', + isset($cfgRelation['table_uiprefs']), + $messages, + 'table_uiprefs' + ); + $retval .= PMA_getDiagMessageForFeature( + __('Persistent tables\' UI preferences'), + 'uiprefswork', + $messages + ); + $retval .= PMA_getDiagMessageForParameter( + 'tracking', + isset($cfgRelation['tracking']), + $messages, + 'tracking' + ); + $retval .= PMA_getDiagMessageForFeature( + __('Tracking'), + 'trackingwork', + $messages + ); + $retval .= PMA_getDiagMessageForParameter( + 'userconfig', + isset($cfgRelation['userconfig']), + $messages, + 'userconfig' + ); + $retval .= PMA_getDiagMessageForFeature( + __('User preferences'), + 'userconfigwork', + $messages + ); + $retval .= PMA_getDiagMessageForParameter( + 'users', + isset($cfgRelation['users']), + $messages, + 'users' + ); + $retval .= PMA_getDiagMessageForParameter( + 'usergroups', + isset($cfgRelation['usergroups']), + $messages, + 'usergroups' + ); + $retval .= PMA_getDiagMessageForFeature( + __('Configurable menus'), + 'menuswork', + $messages + ); + $retval .= PMA_getDiagMessageForParameter( + 'navigationhiding', + isset($cfgRelation['navigationhiding']), + $messages, + 'navigationhiding' + ); + $retval .= PMA_getDiagMessageForFeature( + __('Hide/show navigation items'), + 'navwork', + $messages + ); + $retval .= '
    '; + $retval .= __('Please see the documentation on how to update your column_comments table.'); + $retval .= '
    ' . "\n"; + + $retval .= '

    ' . __('Quick steps to setup advanced features:') . '

    '; + $retval .= '
      '; + $retval .= '
    • '; + $retval .= __( + 'Create the needed tables with the ' + . 'examples/create_tables.sql.' + ); + $retval .= ' ' . PMA_Util::showDocu('setup', 'linked-tables'); + $retval .= '
    • '; + $retval .= '
    • '; + $retval .= __('Create a pma user and give access to these tables.'); + $retval .= ' ' . PMA_Util::showDocu('config', 'cfg_Servers_controluser'); + $retval .= '
    • '; + $retval .= '
    • '; + $retval .= __( + 'Enable advanced features in configuration file ' + . '(config.inc.php), for example by ' + . 'starting from config.sample.inc.php.' + ); + $retval .= ' ' . PMA_Util::showDocu('setup', 'quick-install'); + $retval .= '
    • '; + $retval .= '
    • '; + $retval .= __( + 'Re-login to phpMyAdmin to load the updated configuration file.' + ); + $retval .= '
    • '; + $retval .= '
    '; } - PMA_printDiagMessageForParameter('bookmarktable', isset($cfgRelation['bookmark']), $messages, 'bookmark'); - - PMA_printDiagMessageForFeature(__('Bookmarked SQL query'), 'bookmarkwork', $messages); - - PMA_printDiagMessageForParameter('history', isset($cfgRelation['history']), $messages, 'history'); - - PMA_printDiagMessageForFeature(__('SQL history'), 'historywork', $messages); - - PMA_printDiagMessageForParameter('designer_coords', isset($cfgRelation['designer_coords']), $messages, 'designer_coords'); - - PMA_printDiagMessageForFeature(__('Designer'), 'designerwork', $messages); - - PMA_printDiagMessageForParameter('recent', isset($cfgRelation['recent']), $messages, 'recent'); - - PMA_printDiagMessageForFeature(__('Persistent recently used tables'), 'recentwork', $messages); - - PMA_printDiagMessageForParameter('table_uiprefs', isset($cfgRelation['table_uiprefs']), $messages, 'table_uiprefs'); - - PMA_printDiagMessageForFeature(__('Persistent tables\' UI preferences'), 'uiprefswork', $messages); - - PMA_printDiagMessageForParameter('tracking', isset($cfgRelation['tracking']), $messages, 'tracking'); - - PMA_printDiagMessageForFeature(__('Tracking'), 'trackingwork', $messages); - - PMA_printDiagMessageForParameter('userconfig', isset($cfgRelation['userconfig']), $messages, 'userconfig'); - - PMA_printDiagMessageForFeature(__('User preferences'), 'userconfigwork', $messages); - - echo '' . "\n"; - - echo '

    ' . __('Quick steps to setup advanced features:') . '

    '; - echo '
      '; - echo '
    • ' . __('Create the needed tables with the examples/create_tables.sql.') . ' ' . PMA_showDocu('linked-tables') . '
    • '; - echo '
    • ' . __('Create a pma user and give access to these tables.') . ' ' . PMA_showDocu('pmausr') . '
    • '; - echo '
    • ' . __('Enable advanced features in configuration file (config.inc.php), for example by starting from config.sample.inc.php.') . ' ' . PMA_showDocu('quick_install') . '
    • '; - echo '
    • ' . __('Re-login to phpMyAdmin to load the updated configuration file.') . '
    • '; - echo '
    '; + return $retval; } /** @@ -166,16 +322,22 @@ function PMA_printRelationsParamDiagnostic($cfgRelation) * @param array $messages utility messages * @param boolean $skip_line whether to skip a line after the message * - * @return nothing + * @return string */ -function PMA_printDiagMessageForFeature($feature_name, $relation_parameter, $messages, $skip_line=true) -{ - echo ' ' . $feature_name . ': ' - . ($GLOBALS['cfgRelation'][$relation_parameter] ? $messages['enabled'] : $messages['disabled']) - . '' . "\n"; +function PMA_getDiagMessageForFeature($feature_name, + $relation_parameter, $messages, $skip_line = true +) { + $retval = ' ' . $feature_name . ': '; + if ($GLOBALS['cfgRelation'][$relation_parameter]) { + $retval .= $messages['enabled']; + } else { + $retval .= $messages['disabled']; + } + $retval .= ''; if ($skip_line) { - echo '  ' . "\n"; + $retval .= ' '; } + return $retval; } /** @@ -184,15 +346,26 @@ function PMA_printDiagMessageForFeature($feature_name, $relation_parameter, $mes * @param string $parameter config parameter name to display * @param boolean $relation_parameter_set whether this parameter is set * @param array $messages utility messages - * @param string $doc_anchor anchor in Documentation.html + * @param string $doc_anchor anchor in documentation * - * @return nothing + * @return string */ -function PMA_printDiagMessageForParameter($parameter, $relation_parameter_set, $messages, $doc_anchor) -{ - echo ' '; - echo '$cfg[\'Servers\'][$i][\'' . $parameter . '\'] ... '; - echo ($relation_parameter_set ? $messages['ok'] : sprintf($messages['error'], $doc_anchor)) . '' . "\n"; +function PMA_getDiagMessageForParameter($parameter, + $relation_parameter_set, $messages, $doc_anchor +) { + $retval = ''; + $retval .= '$cfg[\'Servers\'][$i][\'' . $parameter . '\'] ... '; + $retval .= ''; + if ($relation_parameter_set) { + $retval .= $messages['ok']; + } else { + $retval .= sprintf( + $messages['error'], + PMA_Util::getDocuLink('config', 'cfg_Servers_' . $doc_anchor) + ); + } + $retval .= '' . "\n"; + return $retval; } @@ -202,29 +375,32 @@ function PMA_printDiagMessageForParameter($parameter, $relation_parameter_set, $ * but added some stuff to check what will work * * @access protected - * @return array the relation parameters for the current user + * @return array the relation parameters for the current user */ -function PMA__getRelationsParam() +function PMA_checkRelationsParam() { - $cfgRelation = array(); - $cfgRelation['relwork'] = false; - $cfgRelation['displaywork'] = false; - $cfgRelation['bookmarkwork']= false; - $cfgRelation['pdfwork'] = false; - $cfgRelation['commwork'] = false; - $cfgRelation['mimework'] = false; - $cfgRelation['historywork'] = false; - $cfgRelation['recentwork'] = false; - $cfgRelation['uiprefswork'] = false; - $cfgRelation['trackingwork'] = false; - $cfgRelation['designerwork'] = false; + $cfgRelation = array(); + $cfgRelation['relwork'] = false; + $cfgRelation['displaywork'] = false; + $cfgRelation['bookmarkwork'] = false; + $cfgRelation['pdfwork'] = false; + $cfgRelation['commwork'] = false; + $cfgRelation['mimework'] = false; + $cfgRelation['historywork'] = false; + $cfgRelation['recentwork'] = false; + $cfgRelation['uiprefswork'] = false; + $cfgRelation['trackingwork'] = false; + $cfgRelation['designerwork'] = false; $cfgRelation['userconfigwork'] = false; - $cfgRelation['allworks'] = false; - $cfgRelation['user'] = null; - $cfgRelation['db'] = null; - - if ($GLOBALS['server'] == 0 || empty($GLOBALS['cfg']['Server']['pmadb']) - || ! PMA_DBI_select_db($GLOBALS['cfg']['Server']['pmadb'], $GLOBALS['controllink']) + $cfgRelation['menuswork'] = false; + $cfgRelation['navwork'] = false; + $cfgRelation['allworks'] = false; + $cfgRelation['user'] = null; + $cfgRelation['db'] = null; + + if ($GLOBALS['server'] == 0 + || empty($GLOBALS['cfg']['Server']['pmadb']) + || ! $GLOBALS['dbi']->selectDb($GLOBALS['cfg']['Server']['pmadb'], $GLOBALS['controllink']) ) { // No server selected -> no bookmark table // we return the array with the falses in it, @@ -242,8 +418,13 @@ function PMA__getRelationsParam() // I was thinking of checking if they have all required columns but I // fear it might be too slow - $tab_query = 'SHOW TABLES FROM ' . PMA_backquote($GLOBALS['cfg']['Server']['pmadb']); - $tab_rs = PMA_query_as_controluser($tab_query, false, PMA_DBI_QUERY_STORE); + $tab_query = 'SHOW TABLES FROM ' + . PMA_Util::backquote( + $GLOBALS['cfg']['Server']['pmadb'] + ); + $tab_rs = PMA_queryAsControlUser( + $tab_query, false, PMA_DatabaseInterface::QUERY_STORE + ); if (! $tab_rs) { // query failed ... ? @@ -251,7 +432,7 @@ function PMA__getRelationsParam() return $cfgRelation; } - while ($curr_table = @PMA_DBI_fetch_row($tab_rs)) { + while ($curr_table = @$GLOBALS['dbi']->fetchRow($tab_rs)) { if ($curr_table[0] == $GLOBALS['cfg']['Server']['bookmarktable']) { $cfgRelation['bookmark'] = $curr_table[0]; } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['relation']) { @@ -261,29 +442,35 @@ function PMA__getRelationsParam() } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['table_coords']) { $cfgRelation['table_coords'] = $curr_table[0]; } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['designer_coords']) { - $cfgRelation['designer_coords'] = $curr_table[0]; + $cfgRelation['designer_coords'] = $curr_table[0]; } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['column_info']) { - $cfgRelation['column_info'] = $curr_table[0]; + $cfgRelation['column_info'] = $curr_table[0]; } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['pdf_pages']) { $cfgRelation['pdf_pages'] = $curr_table[0]; } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['history']) { - $cfgRelation['history'] = $curr_table[0]; + $cfgRelation['history'] = $curr_table[0]; } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['recent']) { - $cfgRelation['recent'] = $curr_table[0]; + $cfgRelation['recent'] = $curr_table[0]; } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['table_uiprefs']) { - $cfgRelation['table_uiprefs'] = $curr_table[0]; + $cfgRelation['table_uiprefs'] = $curr_table[0]; } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['tracking']) { - $cfgRelation['tracking'] = $curr_table[0]; + $cfgRelation['tracking'] = $curr_table[0]; } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['userconfig']) { - $cfgRelation['userconfig'] = $curr_table[0]; + $cfgRelation['userconfig'] = $curr_table[0]; + } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['users']) { + $cfgRelation['users'] = $curr_table[0]; + } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['usergroups']) { + $cfgRelation['usergroups'] = $curr_table[0]; + } elseif ($curr_table[0] == $GLOBALS['cfg']['Server']['navigationhiding']) { + $cfgRelation['navigationhiding'] = $curr_table[0]; } } // end while - PMA_DBI_free_result($tab_rs); + $GLOBALS['dbi']->freeResult($tab_rs); if (isset($cfgRelation['relation'])) { $cfgRelation['relwork'] = true; if (isset($cfgRelation['table_info'])) { - $cfgRelation['displaywork'] = true; + $cfgRelation['displaywork'] = true; } } @@ -293,34 +480,7 @@ function PMA__getRelationsParam() if (isset($cfgRelation['column_info'])) { $cfgRelation['commwork'] = true; - - if ($GLOBALS['cfg']['Server']['verbose_check']) { - $mime_query = PMA_DBI_get_columns_sql($cfgRelation['db'], $cfgRelation['column_info']); - $mime_rs = PMA_query_as_controluser($mime_query, false); - - $mime_field_mimetype = false; - $mime_field_transformation = false; - $mime_field_transformation_options = false; - while ($curr_mime_field = @PMA_DBI_fetch_row($mime_rs)) { - if ($curr_mime_field[0] == 'mimetype') { - $mime_field_mimetype = true; - } elseif ($curr_mime_field[0] == 'transformation') { - $mime_field_transformation = true; - } elseif ($curr_mime_field[0] == 'transformation_options') { - $mime_field_transformation_options = true; - } - } - PMA_DBI_free_result($mime_rs); - - if ($mime_field_mimetype - && $mime_field_transformation - && $mime_field_transformation_options - ) { - $cfgRelation['mimework'] = true; - } - } else { - $cfgRelation['mimework'] = true; - } + $cfgRelation['mimework'] = true; } if (isset($cfgRelation['history'])) { @@ -353,12 +513,21 @@ function PMA__getRelationsParam() $cfgRelation['bookmarkwork'] = true; } + if (isset($cfgRelation['users']) && isset($cfgRelation['usergroups'])) { + $cfgRelation['menuswork'] = true; + } + + if (isset($cfgRelation['navigationhiding'])) { + $cfgRelation['navwork'] = true; + } + if ($cfgRelation['relwork'] && $cfgRelation['displaywork'] && $cfgRelation['pdfwork'] && $cfgRelation['commwork'] && $cfgRelation['mimework'] && $cfgRelation['historywork'] && $cfgRelation['recentwork'] && $cfgRelation['uiprefswork'] && $cfgRelation['trackingwork'] && $cfgRelation['userconfigwork'] && $cfgRelation['bookmarkwork'] && $cfgRelation['designerwork'] + && $cfgRelation['menuswork'] && $cfgRelation['navwork'] ) { $cfgRelation['allworks'] = true; } @@ -375,7 +544,7 @@ function PMA__getRelationsParam() * @param string $column the name of the column to check for * @param string $source the source for foreign key information * - * @return array db,table,column + * @return array db,table,column * * @access public */ @@ -390,19 +559,24 @@ function PMA_getForeigners($db, $table, $column = '', $source = 'both') `foreign_db`, `foreign_table`, `foreign_field` - FROM ' . PMA_backquote($cfgRelation['db']) . '.' . PMA_backquote($cfgRelation['relation']) . ' - WHERE `master_db` = \'' . PMA_sqlAddSlashes($db) . '\' - AND `master_table` = \'' . PMA_sqlAddSlashes($table) . '\' '; + FROM ' . PMA_Util::backquote($cfgRelation['db']) + . '.' . PMA_Util::backquote($cfgRelation['relation']) . ' + WHERE `master_db` = \'' . PMA_Util::sqlAddSlashes($db) . '\' + AND `master_table` = \'' . PMA_Util::sqlAddSlashes($table) . '\' '; if (strlen($column)) { - $rel_query .= ' AND `master_field` = \'' . PMA_sqlAddSlashes($column) . '\''; + $rel_query .= ' AND `master_field` = ' + . '\'' . PMA_Util::sqlAddSlashes($column) . '\''; } - $foreign = PMA_DBI_fetch_result($rel_query, 'master_field', null, $GLOBALS['controllink']); + $foreign = $GLOBALS['dbi']->fetchResult( + $rel_query, 'master_field', null, $GLOBALS['controllink'] + ); } if (($source == 'both' || $source == 'foreign') && strlen($table)) { + $show_create_table_query = 'SHOW CREATE TABLE ' - . PMA_backquote($db) . '.' . PMA_backquote($table); - $show_create_table = PMA_DBI_fetch_value($show_create_table_query, 0, 1); + . PMA_Util::backquote($db) . '.' . PMA_Util::backquote($table); + $show_create_table = $GLOBALS['dbi']->fetchValue($show_create_table_query, 0, 1); $analyzed_sql = PMA_SQP_analyze(PMA_SQP_parse($show_create_table)); foreach ($analyzed_sql[0]['foreign_keys'] as $one_key) { @@ -450,7 +624,9 @@ function PMA_getForeigners($db, $table, $column = '', $source = 'both') */ $is_information_schema = strtolower($db) == 'information_schema'; $is_data_dictionary = PMA_DRIZZLE && strtolower($db) == 'data_dictionary'; - if (($is_information_schema || $is_data_dictionary) && ($source == 'internal' || $source == 'both')) { + if (($is_information_schema || $is_data_dictionary) + && ($source == 'internal' || $source == 'both') + ) { if ($is_information_schema) { $relations_key = 'information_schema_relations'; include_once './libraries/information_schema_relations.lib.php'; @@ -478,7 +654,7 @@ function PMA_getForeigners($db, $table, $column = '', $source = 'both') * @param string $db the name of the db to check for * @param string $table the name of the table to check for * - * @return string field name + * @return string field name * * @access public */ @@ -492,11 +668,14 @@ function PMA_getDisplayField($db, $table) if ($cfgRelation['displaywork']) { $disp_query = ' SELECT `display_field` - FROM ' . PMA_backquote($cfgRelation['db']) . '.' . PMA_backquote($cfgRelation['table_info']) . ' - WHERE `db_name` = \'' . PMA_sqlAddSlashes($db) . '\' - AND `table_name` = \'' . PMA_sqlAddSlashes($table) . '\''; + FROM ' . PMA_Util::backquote($cfgRelation['db']) + . '.' . PMA_Util::backquote($cfgRelation['table_info']) . ' + WHERE `db_name` = \'' . PMA_Util::sqlAddSlashes($db) . '\' + AND `table_name` = \'' . PMA_Util::sqlAddSlashes($table) . '\''; - $row = PMA_DBI_fetch_single_row($disp_query, 'ASSOC', $GLOBALS['controllink']); + $row = $GLOBALS['dbi']->fetchSingleRow( + $disp_query, 'ASSOC', $GLOBALS['controllink'] + ); if (isset($row['display_field'])) { return $row['display_field']; } @@ -522,12 +701,12 @@ function PMA_getDisplayField($db, $table) } // end of the 'PMA_getDisplayField()' function /** - * Gets the comments for all rows of a table or the db itself + * Gets the comments for all columns of a table or the db itself * * @param string $db the name of the db to check for * @param string $table the name of the table to check for * - * @return array [field_name] = comment + * @return array [column_name] = comment * * @access public */ @@ -537,11 +716,11 @@ function PMA_getComments($db, $table = '') if ($table != '') { // MySQL native column comments - $fields = PMA_DBI_get_columns($db, $table, null, true); - if ($fields) { - foreach ($fields as $field) { - if (! empty($field['Comment'])) { - $comments[$field['Field']] = $field['Comment']; + $columns = $GLOBALS['dbi']->getColumns($db, $table, null, true); + if ($columns) { + foreach ($columns as $column) { + if (! empty($column['Comment'])) { + $comments[$column['Field']] = $column['Comment']; } } } @@ -557,7 +736,7 @@ function PMA_getComments($db, $table = '') * * @param string $db the name of the db to check for * - * @return string comment + * @return string comment * * @access public */ @@ -570,17 +749,20 @@ function PMA_getDbComment($db) // pmadb internal db comment $com_qry = " SELECT `comment` - FROM " . PMA_backquote($cfgRelation['db']) . "." . PMA_backquote($cfgRelation['column_info']) . " - WHERE db_name = '" . PMA_sqlAddSlashes($db) . "' + FROM " . PMA_Util::backquote($cfgRelation['db']) + . "." . PMA_Util::backquote($cfgRelation['column_info']) . " + WHERE db_name = '" . PMA_Util::sqlAddSlashes($db) . "' AND table_name = '' AND column_name = '(db_comment)'"; - $com_rs = PMA_query_as_controluser($com_qry, true, PMA_DBI_QUERY_STORE); + $com_rs = PMA_queryAsControlUser( + $com_qry, true, PMA_DatabaseInterface::QUERY_STORE + ); - if ($com_rs && PMA_DBI_num_rows($com_rs) > 0) { - $row = PMA_DBI_fetch_assoc($com_rs); + if ($com_rs && $GLOBALS['dbi']->numRows($com_rs) > 0) { + $row = $GLOBALS['dbi']->fetchAssoc($com_rs); $comment = $row['comment']; } - PMA_DBI_free_result($com_rs); + $GLOBALS['dbi']->freeResult($com_rs); } return $comment; @@ -591,7 +773,7 @@ function PMA_getDbComment($db) * * @access public * - * @return string comment + * @return string comment */ function PMA_getDbComments() { @@ -602,16 +784,19 @@ function PMA_getDbComments() // pmadb internal db comment $com_qry = " SELECT `db_name`, `comment` - FROM " . PMA_backquote($cfgRelation['db']) . "." . PMA_backquote($cfgRelation['column_info']) . " + FROM " . PMA_Util::backquote($cfgRelation['db']) + . "." . PMA_Util::backquote($cfgRelation['column_info']) . " WHERE `column_name` = '(db_comment)'"; - $com_rs = PMA_query_as_controluser($com_qry, true, PMA_DBI_QUERY_STORE); + $com_rs = PMA_queryAsControlUser( + $com_qry, true, PMA_DatabaseInterface::QUERY_STORE + ); - if ($com_rs && PMA_DBI_num_rows($com_rs) > 0) { - while ($row = PMA_DBI_fetch_assoc($com_rs)) { + if ($com_rs && $GLOBALS['dbi']->numRows($com_rs) > 0) { + while ($row = $GLOBALS['dbi']->fetchAssoc($com_rs)) { $comments[$row['db_name']] = $row['comment']; } } - PMA_DBI_free_result($com_rs); + $GLOBALS['dbi']->freeResult($com_rs); } return $comments; @@ -623,7 +808,7 @@ function PMA_getDbComments() * @param string $db the name of the db * @param string $comment the value of the column * - * @return boolean true, if comment-query was made. + * @return boolean true, if comment-query was made. * * @access public */ @@ -636,28 +821,28 @@ function PMA_setDbComment($db, $comment = '') } if (strlen($comment)) { - $upd_query = " - INSERT INTO - " . PMA_backquote($cfgRelation['db']) . "." . PMA_backquote($cfgRelation['column_info']) . " - (`db_name`, `table_name`, `column_name`, `comment`) - VALUES ( - '" . PMA_sqlAddSlashes($db) . "', - '', - '(db_comment)', - '" . PMA_sqlAddSlashes($comment) . "') - ON DUPLICATE KEY UPDATE - `comment` = '" . PMA_sqlAddSlashes($comment) . "'"; + $upd_query = 'INSERT INTO ' + . PMA_Util::backquote($cfgRelation['db']) . '.' + . PMA_Util::backquote($cfgRelation['column_info']) + . ' (`db_name`, `table_name`, `column_name`, `comment`)' + . ' VALUES (\'' + . PMA_Util::sqlAddSlashes($db) + . "', '', '(db_comment)', '" + . PMA_Util::sqlAddSlashes($comment) + . "') " + . ' ON DUPLICATE KEY UPDATE ' + . "`comment` = '" . PMA_Util::sqlAddSlashes($comment) . "'"; } else { - $upd_query = ' - DELETE FROM - ' . PMA_backquote($cfgRelation['db']) . '.' . PMA_backquote($cfgRelation['column_info']) . ' - WHERE `db_name` = \'' . PMA_sqlAddSlashes($db) . '\' + $upd_query = 'DELETE FROM ' + . PMA_Util::backquote($cfgRelation['db']) . '.' + . PMA_Util::backquote($cfgRelation['column_info']) + . ' WHERE `db_name` = \'' . PMA_Util::sqlAddSlashes($db) . '\' AND `table_name` = \'\' AND `column_name` = \'(db_comment)\''; } if (isset($upd_query)) { - return PMA_query_as_controluser($upd_query); + return PMA_queryAsControlUser($upd_query); } return false; @@ -671,13 +856,16 @@ function PMA_setDbComment($db, $comment = '') * @param string $username the username * @param string $sqlquery the sql query * - * @return nothing + * @return void * * @access public */ function PMA_setHistory($db, $table, $username, $sqlquery) { - if (strlen($sqlquery) > $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']) { + // Prevent to run this automatically on Footer class destroying in testsuite + if (defined('TESTSUITE') + || strlen($sqlquery) > $GLOBALS['cfg']['MaxCharactersInDisplayedSQL'] + ) { return; } @@ -708,20 +896,21 @@ function PMA_setHistory($db, $table, $username, $sqlquery) return; } - PMA_query_as_controluser( - 'INSERT INTO - ' . PMA_backquote($cfgRelation['db']) . '.' . PMA_backquote($cfgRelation['history']) . ' + PMA_queryAsControlUser( + 'INSERT INTO ' + . PMA_Util::backquote($cfgRelation['db']) . '.' + . PMA_Util::backquote($cfgRelation['history']) . ' (`username`, `db`, `table`, `timevalue`, `sqlquery`) VALUES - (\'' . PMA_sqlAddSlashes($username) . '\', - \'' . PMA_sqlAddSlashes($db) . '\', - \'' . PMA_sqlAddSlashes($table) . '\', + (\'' . PMA_Util::sqlAddSlashes($username) . '\', + \'' . PMA_Util::sqlAddSlashes($db) . '\', + \'' . PMA_Util::sqlAddSlashes($table) . '\', NOW(), - \'' . PMA_sqlAddSlashes($sqlquery) . '\')' + \'' . PMA_Util::sqlAddSlashes($sqlquery) . '\')' ); } // end of 'PMA_setHistory()' function @@ -730,7 +919,7 @@ function PMA_setHistory($db, $table, $username, $sqlquery) * * @param string $username the username * - * @return array list of history items + * @return array list of history items * * @access public */ @@ -738,6 +927,14 @@ function PMA_getHistory($username) { $cfgRelation = PMA_getRelationsParam(); + /** + * if db-based history is disabled but there exists a session-based + * history, use it + */ + if (! $GLOBALS['cfg']['QueryHistoryDB'] && isset($_SESSION['sql_history'])) { + return array_reverse($_SESSION['sql_history']); + } + if (! $cfgRelation['historywork']) { return false; } @@ -746,11 +943,12 @@ function PMA_getHistory($username) SELECT `db`, `table`, `sqlquery` - FROM ' . PMA_backquote($cfgRelation['db']) . '.' . PMA_backquote($cfgRelation['history']) . ' - WHERE `username` = \'' . PMA_sqlAddSlashes($username) . '\' + FROM ' . PMA_Util::backquote($cfgRelation['db']) + . '.' . PMA_Util::backquote($cfgRelation['history']) . ' + WHERE `username` = \'' . PMA_Util::sqlAddSlashes($username) . '\' ORDER BY `id` DESC'; - return PMA_DBI_fetch_result($hist_query, null, null, $GLOBALS['controllink']); + return $GLOBALS['dbi']->fetchResult($hist_query, null, null, $GLOBALS['controllink']); } // end of 'PMA_getHistory()' function /** @@ -761,7 +959,7 @@ function PMA_getHistory($username) * * @param string $username the username * - * @return nothing + * @return void * * @access public */ @@ -778,16 +976,18 @@ function PMA_purgeHistory($username) $search_query = ' SELECT `timevalue` - FROM ' . PMA_backquote($cfgRelation['db']) . '.' . PMA_backquote($cfgRelation['history']) . ' - WHERE `username` = \'' . PMA_sqlAddSlashes($username) . '\' + FROM ' . PMA_Util::backquote($cfgRelation['db']) + . '.' . PMA_Util::backquote($cfgRelation['history']) . ' + WHERE `username` = \'' . PMA_Util::sqlAddSlashes($username) . '\' ORDER BY `timevalue` DESC LIMIT ' . $GLOBALS['cfg']['QueryHistoryMax'] . ', 1'; - if ($max_time = PMA_DBI_fetch_value($search_query, 0, 0, $GLOBALS['controllink'])) { - PMA_query_as_controluser( - 'DELETE FROM - ' . PMA_backquote($cfgRelation['db']) . '.' . PMA_backquote($cfgRelation['history']) . ' - WHERE `username` = \'' . PMA_sqlAddSlashes($username) . '\' + if ($max_time = $GLOBALS['dbi']->fetchValue($search_query, 0, 0, $GLOBALS['controllink'])) { + PMA_queryAsControlUser( + 'DELETE FROM ' + . PMA_Util::backquote($cfgRelation['db']) . '.' + . PMA_Util::backquote($cfgRelation['history']) . ' + WHERE `username` = \'' . PMA_Util::sqlAddSlashes($username) . '\' AND `timevalue` <= \'' . $max_time . '\'' ); } @@ -800,11 +1000,11 @@ function PMA_purgeHistory($username) * @param string $data the current data of the dropdown * @param string $mode the needed mode * - * @return array the '; + $reloptions[] = $reloption . '>' + . $value . ' - ' . htmlspecialchars($key) . ''; } elseif ($mode == 'id-content') { - $reloptions[] = $reloption . '>' . htmlspecialchars($key) . ' - ' . $value . ''; + $reloptions[] = $reloption . '>' + . htmlspecialchars($key) . ' - ' . $value . ''; } elseif ($mode == 'id-only') { - $reloptions[] = $reloption . '>' . htmlspecialchars($key) . ''; + $reloptions[] = $reloption . '>' + . htmlspecialchars($key) . ''; } } // end foreach return $reloptions; -} // end of 'PMA__foreignDropdownBuild' function +} // end of 'PMA_buildForeignDropdown' function /** * Outputs dropdown with values of foreign fields @@ -865,13 +1070,13 @@ function PMA__foreignDropdownBuild($foreign, $data, $mode) * @param string $data the current data of the dropdown (field in row) * @param int $max maximum number of items in the dropdown * - * @return string the '; + $multi_values .= ' '; } // end while $multi_values .= ''; - $multi_values .= '
    ' . __('Uncheck All') . ''; + $multi_values .= '
    '; + $multi_values .= __('Uncheck All') . ''; return $multi_values; } /** - * prints out code for changing master + * returns HTML for changing master * * @param String $submitname - submit button name + * + * @return String HTML code */ -function PMA_replication_gui_changemaster($submitname) +function PMA_getHtmlForReplicationChangeMaster($submitname) +{ + $html = ''; + list($username_length, $hostname_length) + = PMA_replicationGetUsernameHostnameLength(); + + $html .= '
    '; + $html .= PMA_URL_getHiddenInputs('', ''); + $html .= '
    '; + $html .= ' ' . __('Slave configuration'); + $html .= ' - ' . __('Change or reconfigure master server') . ''; + $html .= __( + 'Make sure, you have unique server-id in your configuration file (my.cnf). ' + . 'If not, please add the following line into [mysqld] section:' + ); + $html .= '
    '; + $html .= '
    server-id=' . time() . '
    '; + + $html .= PMA_getHtmlForAddUserInputDiv( + array('text'=>__('User name:'), 'for'=>"text_username"), + array( + 'type'=>'text', + 'name'=>'username', + 'id'=>'text_username', + 'maxlength'=>$username_length, + 'title'=>__('User name'), + 'required'=>'required' + ) + ); + + $html .= PMA_getHtmlForAddUserInputDiv( + array('text'=>__('Password:'), 'for'=>"text_pma_pw"), + array( + 'type'=>'password', + 'name'=>'pma_pw', + 'id'=>'text_pma_pw', + 'title'=>__('Password'), + 'required'=>'required' + ) + ); + + $html .= PMA_getHtmlForAddUserInputDiv( + array('text'=>__('Host:'), 'for'=>"text_hostname"), + array( + 'type'=>'text', + 'name'=>'hostname', + 'id'=>'text_hostname', + 'maxlength'=>$hostname_length, + 'value'=>'', + 'required'=>'required' + ) + ); + + $html .= PMA_getHtmlForAddUserInputDiv( + array('text'=>__('Port:'), 'for'=>"text_port"), + array( + 'type'=>'number', + 'name'=>'text_port', + 'id'=>'text_port', + 'maxlength'=>6, + 'value'=>'3306', + 'required'=>'required' + ) + ); + + $html .= '
    '; + $html .= ' '; + $html .= '
    '; + + return $html; +} + +/** + * returns HTML code for Add user input div + * + * @param Array $label_array label tag elements + * @param Array $input_array input tag elements + * + * @return String HTML code + */ +function PMA_getHtmlForAddUserInputDiv($label_array, $input_array) { + $html = '
    '; + $html .= ' '; - list($username_length, $hostname_length) = PMA_replication_get_username_hostname_length(); - - echo '
    '; - echo PMA_generate_common_hidden_inputs('', ''); - echo '
    '; - echo ' ' . __('Slave configuration') . ' - ' . __('Change or reconfigure master server') . ''; - echo __('Make sure, you have unique server-id in your configuration file (my.cnf). If not, please add the following line into [mysqld] section:') . '
    '; - echo '
    server-id=' . time() . '
    '; - echo '
    '; - echo ' '; - echo ' '; - echo '
    '; - echo '
    '; - echo ' '; - echo ' '; - echo '
    '; - echo '
    '; - echo ' '; - echo ' '; - echo '
    '; - echo '
    '; - echo ' '; - echo ' '; - echo '
    '; - echo '
    '; - echo ' '; - echo '
    '; + $html .= ' $value) { + $html .= ' ' . $key . '="' . $value. '" '; + } + $html .= ' />'; + $html .= '
    '; + return $html; } /** - * This function prints out table with replication status. + * This function returns html code for table with replication status. * * @param string $type either master or slave - * @param boolean $hidden if true, then default style is set to hidden, default value false - * @param boolen $title if true, then title is displayed, default true + * @param boolean $hidden if true, then default style is set to hidden, + * default value false + * @param boolean $title if true, then title is displayed, default true + * + * @return String HTML code */ -function PMA_replication_print_status_table($type, $hidden = false, $title = true) +function PMA_getHtmlForReplicationStatusTable($type, $hidden = false, $title = true) { global ${"{$type}_variables"}; global ${"{$type}_variables_alerts"}; @@ -93,121 +484,157 @@ function PMA_replication_print_status_table($type, $hidden = false, $title = tru global ${"server_{$type}_replication"}; global ${"strReplicationStatus_{$type}"}; + $html = ''; + // TODO check the Masters server id? - // seems to default to '1' when queried via SHOW VARIABLES , but resulted in error on the master when slave connects - // [ERROR] Error reading packet from server: Misconfigured master - server id was not set ( server_errno=1236) - // [ERROR] Got fatal error 1236: 'Misconfigured master - server id was not set' from master when reading data from binary log + // seems to default to '1' when queried via SHOW VARIABLES , + // but resulted in error on the master when slave connects + // [ERROR] Error reading packet from server: Misconfigured master + // - server id was not set ( server_errno=1236) + // [ERROR] Got fatal error 1236: 'Misconfigured master + // - server id was not set' from master when reading data from binary log // - //$server_id = PMA_DBI_fetch_value("SHOW VARIABLES LIKE 'server_id'", 0, 1); + //$server_id = $GLOBALS['dbi']->fetchValue( + // "SHOW VARIABLES LIKE 'server_id'", 0, 1 + //); - echo '
    '; + $html .= '
    '; if ($title) { if ($type == 'master') { - echo '

    ' . __('Master status') . '

    '; + $html .= '

    '; + $html .= __('Master status') . '

    '; } else { - echo '

    ' . __('Slave status') . '

    '; + $html .= '

    '; + $html .= __('Slave status') . '

    '; } } else { - echo '
    '; + $html .= '
    '; } - echo ' '; - echo ' '; - echo ' '; - echo ' '; - echo ' '; - echo ' '; - echo ' '; - echo ' '; + $html .= '
    ' . __('Variable') . '' . __('Value') . '
    '; + $html .= ' '; + $html .= ' '; + $html .= ' '; + $html .= ' '; + $html .= ' '; + $html .= ' '; + $html .= ' '; $odd_row = true; foreach (${"{$type}_variables"} as $variable) { - echo ' '; - echo ' '; - echo ' '; + $html .= ' '; + $html .= ' '; - echo ' '; + $html .= ' '; + $html .= ' '; $odd_row = ! $odd_row; } - echo ' '; - echo '
    ' . __('Variable') . '' . __('Value') . '
    '; - echo $variable; - echo ' '; + $html .= '
    '; + $html .= $variable; + $html .= ' '; // TODO change to regexp or something, to allow for negative match if (isset(${"{$type}_variables_alerts"}[$variable]) && ${"{$type}_variables_alerts"}[$variable] == ${"server_{$type}_replication"}[0][$variable] ) { - echo ''; + $html .= ''; } elseif (isset(${"{$type}_variables_oks"}[$variable]) - && ${"{$type}_variables_oks"}[$variable] == ${"server_{$type}_replication"}[0][$variable] + && ${"{$type}_variables_oks"}[$variable] + == ${"server_{$type}_replication"}[0][$variable] ) { - echo ''; + $html .= ''; + } else { + $html .= ''; + } + // allow wrapping long table lists into multiple lines + static $variables_wrap = array( + 'Replicate_Do_DB', 'Replicate_Ignore_DB', + 'Replicate_Do_Table', 'Replicate_Ignore_Table', + 'Replicate_Wild_Do_Table', 'Replicate_Wild_Ignore_Table'); + if (in_array($variable, $variables_wrap)) { + $html .= str_replace( + ',', + ', ', + ${"server_{$type}_replication"}[0][$variable] + ); } else { - echo ''; + $html .= ${"server_{$type}_replication"}[0][$variable]; } - echo ${"server_{$type}_replication"}[0][$variable]; - echo ''; + $html .= ''; - echo '
    '; - echo '
    '; - echo '
    '; + $html .= ' '; + $html .= ' '; + $html .= '
    '; + $html .= '
    '; + return $html; } /** - * Prints table with slave users connected to this master + * returns html code for table with slave users connected to this master + * + * @param boolean $hidden - if true, then default style is set to hidden, + * - default value false * - * @param boolean $hidden - if true, then default style is set to hidden, default value false + * @return string */ -function PMA_replication_print_slaves_table($hidden = false) +function PMA_getHtmlForReplicationSlavesTable($hidden = false) { - + $html = ''; // Fetch data - $data = PMA_DBI_fetch_result('SHOW SLAVE HOSTS', null, null); - - echo '
    '; - echo '
    '; - echo ' '; - echo ' '; - echo ' '; - echo ' '; - echo ' '; - echo ' '; - echo ' '; - echo ' '; + $data = $GLOBALS['dbi']->fetchResult('SHOW SLAVE HOSTS', null, null); + + $html .= '
    '; + $html .= '
    '; + $html .= '
    ' . __('Server ID') . '' . __('Host') . '
    '; + $html .= ' '; + $html .= ' '; + $html .= ' '; + $html .= ' '; + $html .= ' '; + $html .= ' '; + $html .= ' '; $odd_row = true; foreach ($data as $slave) { - echo ' '; - echo ' '; - echo ' '; - echo ' '; + $html .= ' '; + $html .= ' '; + $html .= ' '; + $html .= ' '; $odd_row = ! $odd_row; } - echo ' '; - echo '
    ' . __('Server ID') . '' . __('Host') . '
    ' . $slave['Server_id'] . '' . $slave['Host'] . '
    ' . $slave['Server_id'] . '' . $slave['Host'] . '
    '; - echo '
    '; - PMA_Message::notice(__('Only slaves started with the --report-host=host_name option are visible in this list.'))->display(); - echo '
    '; - echo '
    '; + $html .= ' '; + $html .= ' '; + $html .= '
    '; + $html .= PMA_Message::notice( + __( + 'Only slaves started with the ' + . '--report-host=host_name option are visible in this list.' + ) + )->getDisplay(); + $html .= '
    '; + $html .= '
    '; + + return $html; } /** * get the correct username and hostname lengths for this MySQL server * - * @return array username length, hostname length + * @return array username length, hostname length */ -function PMA_replication_get_username_hostname_length() +function PMA_replicationGetUsernameHostnameLength() { - $fields_info = PMA_DBI_get_columns('mysql', 'user'); + $fields_info = $GLOBALS['dbi']->getColumns('mysql', 'user'); $username_length = 16; $hostname_length = 41; foreach ($fields_info as $val) { @@ -229,68 +656,62 @@ function PMA_replication_get_username_hostname_length() } /** - * Print code to add a replication slave user to the master + * returns html code to add a replication slave user to the master + * + * @return String HTML code */ -function PMA_replication_gui_master_addslaveuser() +function PMA_getHtmlForReplicationMasterAddSlaveuser() { + $html = ''; + list($username_length, $hostname_length) + = PMA_replicationGetUsernameHostnameLength(); - list($username_length, $hostname_length) = PMA_replication_get_username_hostname_length(); - - if (isset($GLOBALS['username']) && strlen($GLOBALS['username']) === 0) { + if (isset($_REQUEST['username']) && strlen($_REQUEST['username']) === 0) { $GLOBALS['pred_username'] = 'any'; } - echo '
    '; - echo '
    '; - echo PMA_generate_common_hidden_inputs('', ''); - echo '
    ' - . ''.__('Add slave replication user').'' - . '' - . '' - . '' - . '' - . '' - . '' - . '
    ' - . '' - . '' - . ' ' - . '' - . '' - . '
    ' + $html .= '
    '; + $html .= '' . __('Add slave replication user') . '' + . PMA_getHtmlForAddUserLoginForm($username_length) . '
    ' . '' . '' - . ' ' + . ' ' + . '' + . '
    ' + . '' + . '' + . ' ' + . '' + . '' + . '
    '; + + return $html; +} + +/** + * returns HTML for TableInfoForm + * + * @param int $hostname_length Selected hostname length + * + * @return String HTML code + */ +function PMA_getHtmlForTableInfoForm($hostname_length) +{ + $html = ' ' . ' ' + . '>' . __('Use text field:') . '' . ' ' . '
    ' . '' - . PMA_showHint(__('When Host table is used, this field is ignored and values stored in Host table are used instead.')) + . PMA_Util::showHint( + __( + 'When Host table is used, this field is ignored ' + . 'and values stored in Host table are used instead.' + ) + ) . '
    ' . '
    ' . '' . '' . ' ' . '' - . '' + . '' . '
    ' . '
    ' . '' . ' ' - . '' + . '' . '
    ' . '
    ' . '' . '' - . ' ' + . ' ' . '' . '' . '
    ' . '
    '; - echo '
    '; + return $html; +} + +/** + * handle control requests + * + * @return NULL + */ +function PMA_handleControlRequest() +{ + if (isset($_REQUEST['sr_take_action'])) { + $refresh = false; + $result = null; + $messageSuccess = null; + $messageError = null; + + if (isset($_REQUEST['slave_changemaster'])) { + $result = PMA_handleRequestForSlaveChangeMaster(); + } elseif (isset($_REQUEST['sr_slave_server_control'])) { + $result = PMA_handleRequestForSlaveServerControl(); + $refresh = true; + + switch ($_REQUEST['sr_slave_action']) { + case 'start': + $messageSuccess = __('Replication started successfully.'); + $messageError = __('Error starting replication.'); + break; + + case 'stop': + $messageSuccess = __('Replication stopped successfully.'); + $messageError = __('Error stopping replication.'); + break; + + case 'reset': + $messageSuccess = __('Replication resetting successfully.'); + $messageError = __('Error resetting replication.'); + break; + + default: + $messageSuccess = __('Success.'); + $messageError = __('Error.'); + break; + } + } elseif (isset($_REQUEST['sr_slave_skip_error'])) { + $result = PMA_handleRequestForSlaveSkipError(); + } + + if ($refresh) { + $response = PMA_Response::getInstance(); + if ($response->isAjax()) { + $response->isSuccess($result); + $response->addJSON( + 'message', + $result ? PMA_Message::success($messageSuccess) : PMA_Message::error($messageError) + ); + } else { + PMA_sendHeaderLocation( + $GLOBALS['cfg']['PmaAbsoluteUri'] . 'server_replication.php' + . PMA_URL_getCommon($GLOBALS['url_params'], '&') + ); + } + } + unset($refresh); + } +} +/** + * handle control requests for Slave Change Master + * + * @return boolean + */ +function PMA_handleRequestForSlaveChangeMaster() +{ + $_SESSION['replication']['m_username'] = $sr['username'] + = PMA_Util::sqlAddSlashes($_REQUEST['username']); + $_SESSION['replication']['m_password'] = $sr['pma_pw'] + = PMA_Util::sqlAddSlashes($_REQUEST['pma_pw']); + $_SESSION['replication']['m_hostname'] = $sr['hostname'] + = PMA_Util::sqlAddSlashes($_REQUEST['hostname']); + $_SESSION['replication']['m_port'] = $sr['port'] + = PMA_Util::sqlAddSlashes($_REQUEST['port']); + $_SESSION['replication']['m_correct'] = ''; + $_SESSION['replication']['sr_action_status'] = 'error'; + $_SESSION['replication']['sr_action_info'] = __('Unknown error'); + + // Attempt to connect to the new master server + $link_to_master = PMA_Replication_connectToMaster( + $sr['username'], $sr['pma_pw'], $sr['hostname'], $sr['port'] + ); + + if (! $link_to_master) { + $_SESSION['replication']['sr_action_status'] = 'error'; + $_SESSION['replication']['sr_action_info'] = sprintf( + __('Unable to connect to master %s.'), + htmlspecialchars($sr['hostname']) + ); + } else { + // Read the current master position + $position = PMA_Replication_Slave_binLogMaster($link_to_master); + + if (empty($position)) { + $_SESSION['replication']['sr_action_status'] = 'error'; + $_SESSION['replication']['sr_action_info'] + = __( + 'Unable to read master log position. ' + . 'Possible privilege problem on master.' + ); + } else { + $_SESSION['replication']['m_correct'] = true; + + if (! PMA_Replication_Slave_changeMaster( + $sr['username'], + $sr['pma_pw'], + $sr['hostname'], + $sr['port'], + $position, + true, + false + ) + ) { + $_SESSION['replication']['sr_action_status'] = 'error'; + $_SESSION['replication']['sr_action_info'] + = __('Unable to change master'); + } else { + $_SESSION['replication']['sr_action_status'] = 'success'; + $_SESSION['replication']['sr_action_info'] = sprintf( + __('Master server changed successfully to %s'), + htmlspecialchars($sr['hostname']) + ); + } + } + } + + return $_SESSION['replication']['sr_action_status'] === 'success'; +} + +/** + * handle control requests for Slave Server Control + * + * @return boolean + */ +function PMA_handleRequestForSlaveServerControl() +{ + if (empty($_REQUEST['sr_slave_control_parm'])) { + $_REQUEST['sr_slave_control_parm'] = null; + } + if ($_REQUEST['sr_slave_action'] == 'reset') { + $qStop = PMA_Replication_Slave_control("STOP"); + $qReset = $GLOBALS['dbi']->tryQuery("RESET SLAVE;"); + $qStart = PMA_Replication_Slave_control("START"); + + $result = ($qStop !== false && $qStop !== -1 && + $qReset !== false && $qReset !== -1 && + $qStart !== false && $qStart !== -1); + } else { + $qControl = PMA_Replication_Slave_control( + $_REQUEST['sr_slave_action'], + $_REQUEST['sr_slave_control_parm'] + ); + + $result = ($qControl !== false && $qControl !== -1); + } + + return $result; +} + +/** + * handle control requests for Slave Skip Error + * + * @return boolean + */ +function PMA_handleRequestForSlaveSkipError() +{ + $count = 1; + if (isset($_REQUEST['sr_skip_errors_count'])) { + $count = $_REQUEST['sr_skip_errors_count'] * 1; + } + + $qStop = PMA_Replication_Slave_control("STOP"); + $qSkip = $GLOBALS['dbi']->tryQuery("SET GLOBAL SQL_SLAVE_SKIP_COUNTER = ".$count.";"); + $qStart = PMA_Replication_Slave_control("START"); + + $result = ($qStop !== false && $qStop !== -1 && + $qSkip !== false && $qSkip !== -1 && + $qStart !== false && $qStart !== -1); + + return $result; } ?> diff --git a/phpMyAdmin/libraries/rte/rte_events.lib.php b/phpMyAdmin/libraries/rte/rte_events.lib.php index 52df014..7706597 100644 --- a/phpMyAdmin/libraries/rte/rte_events.lib.php +++ b/phpMyAdmin/libraries/rte/rte_events.lib.php @@ -11,6 +11,8 @@ /** * Sets required globals + * + * @return void */ function PMA_EVN_setGlobals() { @@ -45,6 +47,8 @@ function PMA_EVN_setGlobals() /** * Main function for the events functionality + * + * @return void */ function PMA_EVN_main() { @@ -60,10 +64,10 @@ function PMA_EVN_main() * Display a list of available events */ $columns = "`EVENT_NAME`, `EVENT_TYPE`, `STATUS`"; - $where = "EVENT_SCHEMA='" . PMA_sqlAddSlashes($db) . "'"; + $where = "EVENT_SCHEMA='" . PMA_Util::sqlAddSlashes($db) . "'"; $query = "SELECT $columns FROM `INFORMATION_SCHEMA`.`EVENTS` " . "WHERE $where ORDER BY `EVENT_NAME` ASC;"; - $items = PMA_DBI_fetch_result($query); + $items = $GLOBALS['dbi']->fetchResult($query); echo PMA_RTE_getList('event', $items); /** * Display a link for adding a new event, if @@ -75,6 +79,8 @@ function PMA_EVN_main() /** * Handles editor requests for adding or editing an item + * + * @return void */ function PMA_EVN_handleEditor() { @@ -91,36 +97,39 @@ function PMA_EVN_handleEditor() // Execute the created query if (! empty($_REQUEST['editor_process_edit'])) { // Backup the old trigger, in case something goes wrong - $create_item = PMA_DBI_get_definition( + $create_item = $GLOBALS['dbi']->getDefinition( $db, 'EVENT', $_REQUEST['item_original_name'] ); - $drop_item = "DROP EVENT " . PMA_backquote($_REQUEST['item_original_name']) . ";\n"; - $result = PMA_DBI_try_query($drop_item); + $drop_item = "DROP EVENT " + . PMA_Util::backquote($_REQUEST['item_original_name']) . ";\n"; + $result = $GLOBALS['dbi']->tryQuery($drop_item); if (! $result) { $errors[] = sprintf( __('The following query has failed: "%s"'), htmlspecialchars($drop_item) ) . '
    ' - . __('MySQL said: ') . PMA_DBI_getError(null); + . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); } else { - $result = PMA_DBI_try_query($item_query); + $result = $GLOBALS['dbi']->tryQuery($item_query); if (! $result) { $errors[] = sprintf( __('The following query has failed: "%s"'), htmlspecialchars($item_query) ) . '
    ' - . __('MySQL said: ') . PMA_DBI_getError(null); - // We dropped the old item, but were unable to create the new one - // Try to restore the backup query - $result = PMA_DBI_try_query($create_item); + . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); + // We dropped the old item, but were unable to create + // the new one. Try to restore the backup query + $result = $GLOBALS['dbi']->tryQuery($create_item); if (! $result) { - // OMG, this is really bad! We dropped the query, failed to create a new one + // OMG, this is really bad! We dropped the query, + // failed to create a new one // and now even the backup query does not execute! - // This should not happen, but we better handle this just in case. + // This should not happen, but we better handle + // this just in case. $errors[] = __( 'Sorry, we failed to restore the dropped event.' ) @@ -128,34 +137,42 @@ function PMA_EVN_handleEditor() . __('The backed up query was:') . "\"" . htmlspecialchars($create_item) . "\"" . '
    ' - . __('MySQL said: ') . PMA_DBI_getError(null); + . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); } } else { - $message = PMA_Message::success(__('Event %1$s has been modified.')); - $message->addParam(PMA_backquote($_REQUEST['item_name'])); + $message = PMA_Message::success( + __('Event %1$s has been modified.') + ); + $message->addParam( + PMA_Util::backquote($_REQUEST['item_name']) + ); $sql_query = $drop_item . $item_query; } } } else { // 'Add a new item' mode - $result = PMA_DBI_try_query($item_query); + $result = $GLOBALS['dbi']->tryQuery($item_query); if (! $result) { $errors[] = sprintf( __('The following query has failed: "%s"'), htmlspecialchars($item_query) ) . '

    ' - . __('MySQL said: ') . PMA_DBI_getError(null); + . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); } else { - $message = PMA_Message::success(__('Event %1$s has been created.')); - $message->addParam(PMA_backquote($_REQUEST['item_name'])); + $message = PMA_Message::success( + __('Event %1$s has been created.') + ); + $message->addParam( + PMA_Util::backquote($_REQUEST['item_name']) + ); $sql_query = $item_query; } } } if (count($errors)) { - $message = PMA_Message::error(__('One or more errors have occured while processing your request:')); + $message = PMA_Message::error(__('One or more errors have occurred while processing your request:')); $message->addString('
      '); foreach ($errors as $string) { $message->addString('
    • ' . $string . '
    • '); @@ -163,30 +180,39 @@ function PMA_EVN_handleEditor() $message->addString('
    '); } - $output = PMA_showMessage($message, $sql_query); + $output = PMA_Util::getMessage($message, $sql_query); if ($GLOBALS['is_ajax_request']) { - $extra_data = array(); + $response = PMA_Response::getInstance(); if ($message->isSuccess()) { $columns = "`EVENT_NAME`, `EVENT_TYPE`, `STATUS`"; - $where = "EVENT_SCHEMA='" . PMA_sqlAddSlashes($db) . "' " - . "AND EVENT_NAME='" . PMA_sqlAddSlashes($_REQUEST['item_name']) . "'"; - $query = "SELECT $columns FROM `INFORMATION_SCHEMA`.`EVENTS` WHERE $where;"; - $event = PMA_DBI_fetch_single_row($query); - $extra_data['name'] = htmlspecialchars(strtoupper($_REQUEST['item_name'])); - $extra_data['new_row'] = PMA_EVN_getRowForList($event); - $extra_data['insert'] = ! empty($event); - $response = $output; + $where = "EVENT_SCHEMA='" . PMA_Util::sqlAddSlashes($db) . "' " + . "AND EVENT_NAME='" + . PMA_Util::sqlAddSlashes($_REQUEST['item_name']) . "'"; + $query = "SELECT " . $columns + . " FROM `INFORMATION_SCHEMA`.`EVENTS` WHERE " . $where. ";"; + $event = $GLOBALS['dbi']->fetchSingleRow($query); + $response->addJSON( + 'name', + htmlspecialchars(strtoupper($_REQUEST['item_name'])) + ); + $response->addJSON('new_row', PMA_EVN_getRowForList($event)); + $response->addJSON('insert', ! empty($event)); + $response->addJSON('message', $output); } else { - $response = $message; + $response->isSuccess(false); + $response->addJSON('message', $message); } - PMA_ajaxResponse($response, $message->isSuccess(), $extra_data); + exit; } } /** * Display a form used to add/edit a trigger, if necessary */ - if (count($errors) || ( empty($_REQUEST['editor_process_add']) && empty($_REQUEST['editor_process_edit']) - && (! empty($_REQUEST['add_item']) || ! empty($_REQUEST['edit_item']) + if (count($errors) + || (empty($_REQUEST['editor_process_add']) + && empty($_REQUEST['editor_process_edit']) + && (! empty($_REQUEST['add_item']) + || ! empty($_REQUEST['edit_item']) || ! empty($_REQUEST['item_changetype']))) ) { // FIXME: this must be simpler than that $operation = ''; @@ -217,24 +243,27 @@ function PMA_EVN_handleEditor() // Show form $editor = PMA_EVN_getEditorForm($mode, $operation, $item); if ($GLOBALS['is_ajax_request']) { - $extra_data = array('title' => $title); - PMA_ajaxResponse($editor, true, $extra_data); + $response = PMA_Response::getInstance(); + $response->addJSON('message', $editor); + $response->addJSON('title', $title); } else { echo "\n\n

    $title

    \n\n$editor"; unset($_POST); - include './libraries/footer.inc.php'; } - // exit; + exit; } else { - $message = __('Error in processing request') . ' : '; + $message = __('Error in processing request:') . ' '; $message .= sprintf( PMA_RTE_getWord('not_found'), - htmlspecialchars(PMA_backquote($_REQUEST['item_name'])), - htmlspecialchars(PMA_backquote($db)) + htmlspecialchars(PMA_Util::backquote($_REQUEST['item_name'])), + htmlspecialchars(PMA_Util::backquote($db)) ); $message = PMA_message::error($message); if ($GLOBALS['is_ajax_request']) { - PMA_ajaxResponse($message, false); + $response = PMA_Response::getInstance(); + $response->isSuccess(false); + $response->addJSON('message', $message); + exit; } else { $message->display(); } @@ -245,7 +274,7 @@ function PMA_EVN_handleEditor() /** * This function will generate the values that are required to for the editor * - * @return array Data necessary to create the editor. + * @return array Data necessary to create the editor. */ function PMA_EVN_getDataFromRequest() { @@ -278,9 +307,9 @@ function PMA_EVN_getDataFromRequest() * This function will generate the values that are required to complete * the "Edit event" form given the name of a event. * - * @param string $name The name of the event. + * @param string $name The name of the event. * - * @return array Data necessary to create the editor. + * @return array Data necessary to create the editor. */ function PMA_EVN_getDataFromName($name) { @@ -290,10 +319,10 @@ function PMA_EVN_getDataFromName($name) $columns = "`EVENT_NAME`, `STATUS`, `EVENT_TYPE`, `EXECUTE_AT`, " . "`INTERVAL_VALUE`, `INTERVAL_FIELD`, `STARTS`, `ENDS`, " . "`EVENT_DEFINITION`, `ON_COMPLETION`, `DEFINER`, `EVENT_COMMENT`"; - $where = "EVENT_SCHEMA='" . PMA_sqlAddSlashes($db) . "' " - . "AND EVENT_NAME='" . PMA_sqlAddSlashes($name) . "'"; + $where = "EVENT_SCHEMA='" . PMA_Util::sqlAddSlashes($db) . "' " + . "AND EVENT_NAME='" . PMA_Util::sqlAddSlashes($name) . "'"; $query = "SELECT $columns FROM `INFORMATION_SCHEMA`.`EVENTS` WHERE $where;"; - $item = PMA_DBI_fetch_single_row($query); + $item = $GLOBALS['dbi']->fetchSingleRow($query); if (! $item) { return false; } @@ -324,16 +353,16 @@ function PMA_EVN_getDataFromName($name) /** * Displays a form used to add/edit an event * - * @param string $mode If the editor will be used edit an event + * @param string $mode If the editor will be used edit an event * or add a new one: 'edit' or 'add'. - * @param string $operation If the editor was previously invoked with + * @param string $operation If the editor was previously invoked with * JS turned off, this will hold the name of * the current operation - * @param array $item Data for the event returned by + * @param array $item Data for the event returned by * PMA_EVN_getDataFromRequest() or * PMA_EVN_getDataFromName() * - * @return string HTML code for the editor. + * @return string HTML code for the editor. */ function PMA_EVN_getEditorForm($mode, $operation, $item) { @@ -383,7 +412,7 @@ function PMA_EVN_getEditorForm($mode, $operation, $item) $retval .= "
    \n"; $retval .= "\n"; $retval .= $original_data; - $retval .= PMA_generate_common_hidden_inputs($db, $table) . "\n"; + $retval .= PMA_URL_getHiddenInputs($db, $table) . "\n"; $retval .= "
    \n"; $retval .= "" . __('Details') . "\n"; $retval .= "\n"; @@ -424,7 +453,8 @@ function PMA_EVN_getEditorForm($mode, $operation, $item) } else { $retval .= " \n"; $retval .= " {$item['item_type']}\n"; $retval .= " \n"; $retval .= " \n"; + $retval .= " \n"; $retval .= " \n"; + $retval .= " \n"; // Get a list of data types that are not yet supported. - $no_support_types = PMA_unsupportedDatatypes(); + $no_support_types = PMA_Util::unsupportedDatatypes(); for ($i=0; $i<$routine['item_num_params']; $i++) { // Each parameter if ($routine['item_type'] == 'PROCEDURE' && $routine['item_param_dir'][$i] == 'OUT' @@ -1409,7 +1619,9 @@ function PMA_RTN_getExecuteForm($routine) $retval .= "\n"; @@ -1448,18 +1661,23 @@ function PMA_RTN_getExecuteForm($routine) for ($j=0; $j<$tokens['len']; $j++) { if ($tokens[$j]['type'] != 'punct_listsep') { $tokens[$j]['data'] = htmlentities( - PMA_unquote($tokens[$j]['data']), + PMA_Util::unquote($tokens[$j]['data']), ENT_QUOTES ); - $retval .= "" - . "{$tokens[$j]['data']}
    \n"; + $retval .= "" + . $tokens[$j]['data'] . "
    \n"; } } - } else if (in_array(strtolower($routine['item_param_type'][$i]), $no_support_types)) { + } else if (in_array( + strtolower($routine['item_param_type'][$i]), $no_support_types + )) { $retval .= "\n"; } else { - $retval .= "\n"; + $retval .= "\n"; } $retval .= "\n"; $retval .= "\n"; diff --git a/phpMyAdmin/libraries/rte/rte_triggers.lib.php b/phpMyAdmin/libraries/rte/rte_triggers.lib.php index cc76685..e8157a4 100644 --- a/phpMyAdmin/libraries/rte/rte_triggers.lib.php +++ b/phpMyAdmin/libraries/rte/rte_triggers.lib.php @@ -11,6 +11,8 @@ /** * Sets required globals + * + * @return void */ function PMA_TRI_setGlobals() { @@ -26,6 +28,8 @@ function PMA_TRI_setGlobals() /** * Main function for the triggers functionality + * + * @return void */ function PMA_TRI_main() { @@ -40,7 +44,7 @@ function PMA_TRI_main() /** * Display a list of available triggers */ - $items = PMA_DBI_get_triggers($db, $table); + $items = $GLOBALS['dbi']->getTriggers($db, $table); echo PMA_RTE_getList('trigger', $items); /** * Display a link for adding a new trigger, @@ -51,6 +55,8 @@ function PMA_TRI_main() /** * Handles editor requests for adding or editing an item + * + * @return void */ function PMA_TRI_handleEditor() { @@ -70,30 +76,32 @@ function PMA_TRI_handleEditor() $trigger = PMA_TRI_getDataFromName($_REQUEST['item_original_name']); $create_item = $trigger['create']; $drop_item = $trigger['drop'] . ';'; - $result = PMA_DBI_try_query($drop_item); + $result = $GLOBALS['dbi']->tryQuery($drop_item); if (! $result) { $errors[] = sprintf( __('The following query has failed: "%s"'), htmlspecialchars($drop_item) ) . '
    ' - . __('MySQL said: ') . PMA_DBI_getError(null); + . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); } else { - $result = PMA_DBI_try_query($item_query); + $result = $GLOBALS['dbi']->tryQuery($item_query); if (! $result) { $errors[] = sprintf( __('The following query has failed: "%s"'), htmlspecialchars($item_query) ) . '
    ' - . __('MySQL said: ') . PMA_DBI_getError(null); - // We dropped the old item, but were unable to create the new one - // Try to restore the backup query - $result = PMA_DBI_try_query($create_item); + . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); + // We dropped the old item, but were unable to create the + // new one. Try to restore the backup query. + $result = $GLOBALS['dbi']->tryQuery($create_item); if (! $result) { - // OMG, this is really bad! We dropped the query, failed to create a new one + // OMG, this is really bad! We dropped the query, + // failed to create a new one // and now even the backup query does not execute! - // This should not happen, but we better handle this just in case. + // This should not happen, but we better handle + // this just in case. $errors[] = __( 'Sorry, we failed to restore the dropped trigger.' ) @@ -101,34 +109,42 @@ function PMA_TRI_handleEditor() . __('The backed up query was:') . "\"" . htmlspecialchars($create_item) . "\"" . '
    ' - . __('MySQL said: ') . PMA_DBI_getError(null); + . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); } } else { - $message = PMA_Message::success(__('Trigger %1$s has been modified.')); - $message->addParam(PMA_backquote($_REQUEST['item_name'])); + $message = PMA_Message::success( + __('Trigger %1$s has been modified.') + ); + $message->addParam( + PMA_Util::backquote($_REQUEST['item_name']) + ); $sql_query = $drop_item . $item_query; } } } else { // 'Add a new item' mode - $result = PMA_DBI_try_query($item_query); + $result = $GLOBALS['dbi']->tryQuery($item_query); if (! $result) { $errors[] = sprintf( __('The following query has failed: "%s"'), htmlspecialchars($item_query) ) . '

    ' - . __('MySQL said: ') . PMA_DBI_getError(null); + . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); } else { - $message = PMA_Message::success(__('Trigger %1$s has been created.')); - $message->addParam(PMA_backquote($_REQUEST['item_name'])); + $message = PMA_Message::success( + __('Trigger %1$s has been created.') + ); + $message->addParam( + PMA_Util::backquote($_REQUEST['item_name']) + ); $sql_query = $item_query; } } } if (count($errors)) { - $message = PMA_Message::error(__('One or more errors have occured while processing your request:')); + $message = PMA_Message::error(__('One or more errors have occurred while processing your request:')); $message->addString('
      '); foreach ($errors as $string) { $message->addString('
    • ' . $string . '
    • '); @@ -136,38 +152,48 @@ function PMA_TRI_handleEditor() $message->addString('
    '); } - $output = PMA_showMessage($message, $sql_query); + $output = PMA_Util::getMessage($message, $sql_query); if ($GLOBALS['is_ajax_request']) { - $extra_data = array(); + $response = PMA_Response::getInstance(); if ($message->isSuccess()) { - $items = PMA_DBI_get_triggers($db, $table, ''); + $items = $GLOBALS['dbi']->getTriggers($db, $table, ''); $trigger = false; foreach ($items as $value) { if ($value['name'] == $_REQUEST['item_name']) { $trigger = $value; } } - $extra_data['insert'] = false; - if (empty($table) || ($trigger !== false && $table == $trigger['table'])) { - $extra_data['insert'] = true; - $extra_data['new_row'] = PMA_TRI_getRowForList($trigger); - $extra_data['name'] = htmlspecialchars( - strtoupper($_REQUEST['item_name']) + $insert = false; + if (empty($table) + || ($trigger !== false && $table == $trigger['table']) + ) { + $insert = true; + $response->addJSON('new_row', PMA_TRI_getRowForList($trigger)); + $response->addJSON( + 'name', + htmlspecialchars( + strtoupper($_REQUEST['item_name']) + ) ); } - $response = $output; + $response->addJSON('insert', $insert); + $response->addJSON('message', $output); } else { - $response = $message; + $response->addJSON('message', $message); + $response->isSuccess(false); } - PMA_ajaxResponse($response, $message->isSuccess(), $extra_data); + exit; } } /** * Display a form used to add/edit a trigger, if necessary */ - if (count($errors) || ( empty($_REQUEST['editor_process_add']) && empty($_REQUEST['editor_process_edit']) - && (! empty($_REQUEST['add_item']) || ! empty($_REQUEST['edit_item']))) // FIXME: this must be simpler than that + if (count($errors) + || (empty($_REQUEST['editor_process_add']) + && empty($_REQUEST['editor_process_edit']) + && (! empty($_REQUEST['add_item']) + || ! empty($_REQUEST['edit_item']))) // FIXME: this must be simpler than that ) { // Get the data for the form (if any) if (! empty($_REQUEST['add_item'])) { @@ -192,24 +218,27 @@ function PMA_TRI_handleEditor() // Show form $editor = PMA_TRI_getEditorForm($mode, $item); if ($GLOBALS['is_ajax_request']) { - $extra_data = array('title' => $title); - PMA_ajaxResponse($editor, true, $extra_data); + $response = PMA_Response::getInstance(); + $response->addJSON('message', $editor); + $response->addJSON('title', $title); } else { echo "\n\n

    $title

    \n\n$editor"; unset($_POST); - include './libraries/footer.inc.php'; } - // exit; + exit; } else { - $message = __('Error in processing request') . ' : '; + $message = __('Error in processing request:') . ' '; $message .= sprintf( PMA_RTE_getWord('not_found'), - htmlspecialchars(PMA_backquote($_REQUEST['item_name'])), - htmlspecialchars(PMA_backquote($db)) + htmlspecialchars(PMA_Util::backquote($_REQUEST['item_name'])), + htmlspecialchars(PMA_Util::backquote($db)) ); $message = PMA_message::error($message); if ($GLOBALS['is_ajax_request']) { - PMA_ajaxResponse($message, false); + $response = PMA_Response::getInstance(); + $response->isSuccess(false); + $response->addJSON('message', $message); + exit; } else { $message->display(); } @@ -220,7 +249,7 @@ function PMA_TRI_handleEditor() /** * This function will generate the values that are required to for the editor * - * @return array Data necessary to create the editor. + * @return array Data necessary to create the editor. */ function PMA_TRI_getDataFromRequest() { @@ -242,16 +271,16 @@ function PMA_TRI_getDataFromRequest() * This function will generate the values that are required to complete * the "Edit trigger" form given the name of a trigger. * - * @param string $name The name of the trigger. + * @param string $name The name of the trigger. * - * @return array Data necessary to create the editor. + * @return array Data necessary to create the editor. */ function PMA_TRI_getDataFromName($name) { global $db, $table, $_REQUEST; $temp = array(); - $items = PMA_DBI_get_triggers($db, $table, ''); + $items = $GLOBALS['dbi']->getTriggers($db, $table, ''); foreach ($items as $value) { if ($value['name'] == $name) { $temp = $value; @@ -276,13 +305,12 @@ function PMA_TRI_getDataFromName($name) /** * Displays a form used to add/edit a trigger * - * @param string $mode If the editor will be used edit a trigger - * or add a new one: 'edit' or 'add'. - * @param array $item Data for the trigger returned by - * PMA_TRI_getDataFromRequest() or - * PMA_TRI_getDataFromName() + * @param string $mode If the editor will be used edit a trigger + * or add a new one: 'edit' or 'add'. + * @param array $item Data for the trigger returned by PMA_TRI_getDataFromRequest() + * or PMA_TRI_getDataFromName() * - * @return string HTML code for the editor. + * @return string HTML code for the editor. */ function PMA_TRI_getEditorForm($mode, $item) { @@ -296,7 +324,7 @@ function PMA_TRI_getEditorForm($mode, $item) 'item_definer' ); foreach ($need_escape as $key => $index) { - $item[$index] = htmlentities($item[$index], ENT_QUOTES); + $item[$index] = htmlentities($item[$index], ENT_QUOTES, 'UTF-8'); } $original_data = ''; if ($mode == 'edit') { @@ -304,9 +332,9 @@ function PMA_TRI_getEditorForm($mode, $item) . "type='hidden' value='{$item['item_original_name']}'/>\n"; } $query = "SELECT `TABLE_NAME` FROM `INFORMATION_SCHEMA`.`TABLES` "; - $query .= "WHERE `TABLE_SCHEMA`='" . PMA_sqlAddSlashes($db) . "' "; + $query .= "WHERE `TABLE_SCHEMA`='" . PMA_Util::sqlAddSlashes($db) . "' "; $query .= "AND `TABLE_TYPE`='BASE TABLE'"; - $tables = PMA_DBI_fetch_result($query); + $tables = $GLOBALS['dbi']->fetchResult($query); // Create the output $retval = ""; @@ -314,7 +342,7 @@ function PMA_TRI_getEditorForm($mode, $item) $retval .= "\n"; $retval .= "\n"; $retval .= $original_data; - $retval .= PMA_generate_common_hidden_inputs($db, $table) . "\n"; + $retval .= PMA_URL_getHiddenInputs($db, $table) . "\n"; $retval .= "
    \n"; $retval .= "" . __('Details') . "\n"; $retval .= "
    " . _pgettext('Start of recurring event', 'Start'); + $retval .= " \n"; $retval .= " \n"; - $retval .= " \n"; @@ -519,7 +551,7 @@ function PMA_EVN_getEditorForm($mode, $operation, $item) /** * Composes the query necessary to create an event from an HTTP request. * - * @return string The CREATE EVENT query. + * @return string The CREATE EVENT query. */ function PMA_EVN_getQueryFromRequest() { @@ -529,20 +561,22 @@ function PMA_EVN_getQueryFromRequest() if (! empty($_REQUEST['item_definer'])) { if (strpos($_REQUEST['item_definer'], '@') !== false) { $arr = explode('@', $_REQUEST['item_definer']); - $query .= 'DEFINER=' . PMA_backquote($arr[0]); - $query .= '@' . PMA_backquote($arr[1]) . ' '; + $query .= 'DEFINER=' . PMA_Util::backquote($arr[0]); + $query .= '@' . PMA_Util::backquote($arr[1]) . ' '; } else { $errors[] = __('The definer must be in the "username@hostname" format'); } } $query .= 'EVENT '; if (! empty($_REQUEST['item_name'])) { - $query .= PMA_backquote($_REQUEST['item_name']) . ' '; + $query .= PMA_Util::backquote($_REQUEST['item_name']) . ' '; } else { $errors[] = __('You must provide an event name'); } $query .= 'ON SCHEDULE '; - if (! empty($_REQUEST['item_type']) && in_array($_REQUEST['item_type'], $event_type)) { + if (! empty($_REQUEST['item_type']) + && in_array($_REQUEST['item_type'], $event_type) + ) { if ($_REQUEST['item_type'] == 'RECURRING') { if (! empty($_REQUEST['item_interval_value']) && !empty($_REQUEST['item_interval_field']) @@ -554,14 +588,17 @@ function PMA_EVN_getQueryFromRequest() $errors[] = __('You must provide a valid interval value for the event.'); } if (! empty($_REQUEST['item_starts'])) { - $query .= "STARTS '" . PMA_sqlAddSlashes($_REQUEST['item_starts']) . "' "; + $query .= "STARTS '" + . PMA_Util::sqlAddSlashes($_REQUEST['item_starts']) . "' "; } if (! empty($_REQUEST['item_ends'])) { - $query .= "ENDS '" . PMA_sqlAddSlashes($_REQUEST['item_ends']) . "' "; + $query .= "ENDS '" + . PMA_Util::sqlAddSlashes($_REQUEST['item_ends']) . "' "; } } else { if (! empty($_REQUEST['item_execute_at'])) { - $query .= "AT '" . PMA_sqlAddSlashes($_REQUEST['item_execute_at']) . "' "; + $query .= "AT '" + . PMA_Util::sqlAddSlashes($_REQUEST['item_execute_at']) . "' "; } else { $errors[] = __('You must provide a valid execution time for the event.'); } @@ -583,7 +620,7 @@ function PMA_EVN_getQueryFromRequest() } } if (! empty($_REQUEST['item_comment'])) { - $query .= "COMMENT '" . PMA_sqlAddslashes( + $query .= "COMMENT '" . PMA_Util::sqlAddslashes( $_REQUEST['item_comment'] ) . "' "; } diff --git a/phpMyAdmin/libraries/rte/rte_export.lib.php b/phpMyAdmin/libraries/rte/rte_export.lib.php index 53944c6..8fd9a7c 100644 --- a/phpMyAdmin/libraries/rte/rte_export.lib.php +++ b/phpMyAdmin/libraries/rte/rte_export.lib.php @@ -13,21 +13,25 @@ * This function is called from one of the other functions in this file * and it completes the handling of the export functionality. * - * @param string $item_name The name of the item that we are exporting - * @param string $export_data The SQL query to create the requested item + * @param string $item_name The name of the item that we are exporting + * @param string $export_data The SQL query to create the requested item + * + * @return void */ function PMA_RTE_handleExport($item_name, $export_data) { global $db; - $item_name = htmlspecialchars(PMA_backquote($_GET['item_name'])); + $item_name = htmlspecialchars(PMA_Util::backquote($_GET['item_name'])); if ($export_data !== false) { $export_data = ''; $title = sprintf(PMA_RTE_getWord('export'), $item_name); if ($GLOBALS['is_ajax_request'] == true) { - $extra_data = array('title' => $title); - PMA_ajaxResponse($export_data, true, $extra_data); + $response = PMA_Response::getInstance(); + $response->addJSON('message', $export_data); + $response->addJSON('title', $title); + exit; } else { echo "
    \n" . "$title\n" @@ -35,12 +39,15 @@ function PMA_RTE_handleExport($item_name, $export_data) . "
    \n"; } } else { - $_db = htmlspecialchars(PMA_backquote($db)); - $response = __('Error in Processing Request') . ' : ' + $_db = htmlspecialchars(PMA_Util::backquote($db)); + $message = __('Error in processing request:') . ' ' . sprintf(PMA_RTE_getWord('not_found'), $item_name, $_db); - $response = PMA_message::error($response); + $response = PMA_message::error($message); if ($GLOBALS['is_ajax_request'] == true) { - PMA_ajaxResponse($response, false); + $response = PMA_Response::getInstance(); + $response->isSuccess(false); + $response->addJSON('message', $message); + exit; } else { $response->display(); } @@ -50,6 +57,8 @@ function PMA_RTE_handleExport($item_name, $export_data) /** * If necessary, prepares event information and passes * it to PMA_RTE_handleExport() for the actual export. + * + * @return void */ function PMA_EVN_handleExport() { @@ -57,7 +66,7 @@ function PMA_EVN_handleExport() if (! empty($_GET['export_item']) && ! empty($_GET['item_name'])) { $item_name = $_GET['item_name']; - $export_data = PMA_DBI_get_definition($db, 'EVENT', $item_name); + $export_data = $GLOBALS['dbi']->getDefinition($db, 'EVENT', $item_name); PMA_RTE_handleExport($item_name, $export_data); } } // end PMA_EVN_handleExport() @@ -65,6 +74,8 @@ function PMA_EVN_handleExport() /** * If necessary, prepares routine information and passes * it to PMA_RTE_handleExport() for the actual export. + * + * @return void */ function PMA_RTN_handleExport() { @@ -75,10 +86,11 @@ function PMA_RTN_handleExport() && ! empty($_GET['item_type']) ) { if ($_GET['item_type'] == 'FUNCTION' || $_GET['item_type'] == 'PROCEDURE') { - $export_data = PMA_DBI_get_definition( + $export_data = $GLOBALS['dbi']->getDefinition( $db, $_GET['item_type'], - $_GET['item_name']); + $_GET['item_name'] + ); PMA_RTE_handleExport($_GET['item_name'], $export_data); } } @@ -87,6 +99,8 @@ function PMA_RTN_handleExport() /** * If necessary, prepares trigger information and passes * it to PMA_RTE_handleExport() for the actual export. + * + * @return void */ function PMA_TRI_handleExport() { @@ -94,7 +108,7 @@ function PMA_TRI_handleExport() if (! empty($_GET['export_item']) && ! empty($_GET['item_name'])) { $item_name = $_GET['item_name']; - $triggers = PMA_DBI_get_triggers($db, $table, ''); + $triggers = $GLOBALS['dbi']->getTriggers($db, $table, ''); $export_data = false; foreach ($triggers as $trigger) { if ($trigger['name'] === $item_name) { diff --git a/phpMyAdmin/libraries/rte/rte_footer.lib.php b/phpMyAdmin/libraries/rte/rte_footer.lib.php index 2691d4b..752f2f3 100644 --- a/phpMyAdmin/libraries/rte/rte_footer.lib.php +++ b/phpMyAdmin/libraries/rte/rte_footer.lib.php @@ -12,11 +12,11 @@ /** * Creates a fieldset for adding a new item, if the user has the privileges. * - * @param string $docu String used to create a link to the MySQL docs - * @param string $priv Privilege to check for adding a new item - * @param string $name MySQL name of the item + * @param string $docu String used to create a link to the MySQL docs + * @param string $priv Privilege to check for adding a new item + * @param string $name MySQL name of the item * - * @return string An HTML snippet with the link to add a new item + * @return string An HTML snippet with the link to add a new item */ function PMA_RTE_getFooterLinks($docu, $priv, $name) { @@ -26,19 +26,19 @@ function PMA_RTE_getFooterLinks($docu, $priv, $name) $retval = ""; $retval .= "\n"; $retval .= "
    \n"; - $retval .= " " . __('New'). "\n"; + $retval .= "" . _pgettext('Create new procedure', 'New') . "\n"; $retval .= " \n"; $retval .= "
    \n"; $retval .= "\n\n"; @@ -49,7 +49,7 @@ function PMA_RTE_getFooterLinks($docu, $priv, $name) /** * Creates a fieldset for adding a new routine, if the user has the privileges. * - * @return string HTML code with containing the fotter fieldset + * @return string HTML code with containing the fotter fieldset */ function PMA_RTN_getFooterLinks() { @@ -59,7 +59,7 @@ function PMA_RTN_getFooterLinks() /** * Creates a fieldset for adding a new trigger, if the user has the privileges. * - * @return string HTML code with containing the fotter fieldset + * @return string HTML code with containing the fotter fieldset */ function PMA_TRI_getFooterLinks() { @@ -69,7 +69,7 @@ function PMA_TRI_getFooterLinks() /** * Creates a fieldset for adding a new event, if the user has the privileges. * - * @return string HTML code with containing the fotter fieldset + * @return string HTML code with containing the fotter fieldset */ function PMA_EVN_getFooterLinks() { @@ -80,7 +80,7 @@ function PMA_EVN_getFooterLinks() * a form for toggling the state of the event scheduler */ // Init options for the event scheduler toggle functionality - $es_state = PMA_DBI_fetch_value( + $es_state = $GLOBALS['dbi']->fetchValue( "SHOW GLOBAL VARIABLES LIKE 'event_scheduler'", 0, 1 @@ -109,7 +109,7 @@ function PMA_EVN_getFooterLinks() $retval .= " \n"; $retval .= "
    \n"; // show the toggle button - $retval .= PMA_toggleButton( + $retval .= PMA_Util::toggleButton( "sql.php?$url_query&goto=db_events.php" . urlencode("?db=$db"), 'sql_query', $options, diff --git a/phpMyAdmin/libraries/rte/rte_list.lib.php b/phpMyAdmin/libraries/rte/rte_list.lib.php index e0bf2e9..7cc0c1c 100644 --- a/phpMyAdmin/libraries/rte/rte_list.lib.php +++ b/phpMyAdmin/libraries/rte/rte_list.lib.php @@ -13,10 +13,10 @@ * Creates a list of items containing the relevant * information and some action links. * - * @param string $type One of ['routine'|'trigger'|'event'] - * @param array $items An array of items + * @param string $type One of ['routine'|'trigger'|'event'] + * @param array $items An array of items * - * @return string HTML code of the list of items + * @return string HTML code of the list of items */ function PMA_RTE_getList($type, $items) { @@ -38,7 +38,7 @@ function PMA_RTE_getList($type, $items) $retval .= "
    \n"; $retval .= " \n"; $retval .= " " . PMA_RTE_getWord('title') . "\n"; - $retval .= " " . PMA_showMySQLDocu('SQL-Syntax', PMA_RTE_getWord('docu')) . "\n"; + $retval .= " " . PMA_Util::showMySQLDocu(PMA_RTE_getWord('docu')) . "\n"; $retval .= " \n"; $retval .= "
    \n"; $retval .= " " . PMA_RTE_getWord('nothing') . "\n"; @@ -46,12 +46,18 @@ function PMA_RTE_getList($type, $items) $retval .= " \n"; $retval .= " \n"; $retval .= " \n"; + // th cells with a colspan need corresponding td cells, according to W3C switch ($type) { case 'routine': $retval .= " \n"; $retval .= " \n"; $retval .= " \n"; $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; // see comment above + for ($i = 0; $i < 7; $i++) { + $retval .= " \n"; + } break; case 'trigger': $retval .= " \n"; @@ -61,12 +67,22 @@ function PMA_RTE_getList($type, $items) $retval .= " \n"; $retval .= " \n"; $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; // see comment above + for ($i = 0; $i < (empty($table) ? 7 : 6); $i++) { + $retval .= " \n"; + } break; case 'event': $retval .= " \n"; $retval .= " \n"; $retval .= " \n"; $retval .= " \n"; + $retval .= " \n"; + $retval .= " \n"; // see comment above + for ($i = 0; $i < 6; $i++) { + $retval .= " \n"; + } break; default: break; @@ -76,7 +92,7 @@ function PMA_RTE_getList($type, $items) $ct = 0; foreach ($items as $item) { $rowclass = ($ct % 2 == 0) ? 'odd' : 'even'; - if ($GLOBALS['is_ajax_request']) { + if ($GLOBALS['is_ajax_request'] && empty($_REQUEST['ajax_page_request'])) { $rowclass .= ' ajaxInsert hide'; } // Get each row from the correct function @@ -105,37 +121,42 @@ function PMA_RTE_getList($type, $items) /** * Creates the contents for a row in the list of routines * - * @param array $routine An array of routine data - * @param string $rowclass Empty or one of ['even'|'odd'] + * @param array $routine An array of routine data + * @param string $rowclass Empty or one of ['even'|'odd'] * - * @return string HTML code of a row for the list of routines + * @return string HTML code of a row for the list of routines */ function PMA_RTN_getRowForList($routine, $rowclass = '') { global $ajax_class, $url_query, $db, $titles; - $sql_drop = sprintf('DROP %s IF EXISTS %s', - $routine['ROUTINE_TYPE'], - PMA_backquote($routine['SPECIFIC_NAME'])); + $sql_drop = sprintf( + 'DROP %s IF EXISTS %s', + $routine['ROUTINE_TYPE'], + PMA_Util::backquote($routine['SPECIFIC_NAME']) + ); $type_link = "item_type={$routine['ROUTINE_TYPE']}"; $retval = " \n"; $retval .= " \n"; $retval .= " \n"; $retval .= " \n"; $retval .= " \n"; $retval .= " \n"; $retval .= " \n"; $retval .= " \n"; @@ -212,10 +240,10 @@ function PMA_RTN_getRowForList($routine, $rowclass = '') /** * Creates the contents for a row in the list of triggers * - * @param array $trigger An array of routine data - * @param string $rowclass Empty or one of ['even'|'odd'] + * @param array $trigger An array of routine data + * @param string $rowclass Empty or one of ['even'|'odd'] * - * @return string HTML code of a cell for the list of triggers + * @return string HTML code of a cell for the list of triggers */ function PMA_TRI_getRowForList($trigger, $rowclass = '') { @@ -223,25 +251,27 @@ function PMA_TRI_getRowForList($trigger, $rowclass = '') $retval = " \n"; $retval .= " \n"; if (empty($table)) { $retval .= " \n"; } $retval .= " \n"; $retval .= " \n"; $retval .= " \n"; $retval .= " \n"; $retval .= " \n"; $retval .= " \n"; - $retval .= " \n"; $retval .= " \n"; $retval .= " \n"; @@ -745,16 +841,16 @@ function PMA_RTN_getParameterRow($routine = array(), $index = null, $class = '') /** * Displays a form used to add/edit a routine * - * @param string $mode If the editor will be used edit a routine - * or add a new one: 'edit' or 'add'. - * @param string $operation If the editor was previously invoked with - * JS turned off, this will hold the name of - * the current operation - * @param array $routine Data for the routine returned by - * PMA_RTN_getDataFromRequest() or - * PMA_RTN_getDataFromName() + * @param string $mode If the editor will be used edit a routine + * or add a new one: 'edit' or 'add'. + * @param string $operation If the editor was previously invoked with + * JS turned off, this will hold the name of + * the current operation + * @param array $routine Data for the routine returned by + * PMA_RTN_getDataFromRequest() or + * PMA_RTN_getDataFromName() * - * @return string HTML code for the editor. + * @return string HTML code for the editor. */ function PMA_RTN_getEditorForm($mode, $operation, $routine) { @@ -792,7 +888,9 @@ function PMA_RTN_getEditorForm($mode, $operation, $routine) $routine['item_type'] = 'PROCEDURE'; $routine['item_type_toggle'] = 'FUNCTION'; } - } else if ($operation == 'add' || ($routine['item_num_params'] == 0 && $mode == 'add' && ! $errors)) { + } else if ($operation == 'add' + || ($routine['item_num_params'] == 0 && $mode == 'add' && ! $errors) + ) { $routine['item_param_dir'][] = ''; $routine['item_param_name'][] = ''; $routine['item_param_type'][] = ''; @@ -840,7 +938,7 @@ function PMA_RTN_getEditorForm($mode, $operation, $routine) $retval .= "\n"; $retval .= "\n"; $retval .= $original_routine; - $retval .= PMA_generate_common_hidden_inputs($db) . "\n"; + $retval .= PMA_URL_getHiddenInputs($db) . "\n"; $retval .= "
    \n"; $retval .= "" . __('Details') . "\n"; $retval .= "
    " . __('Name') . "" . __('Action') . "" . __('Type') . "" . __('Returns') . "
    " . __('Name') . "" . __('Action') . "" . __('Time') . "" . __('Event') . "
    " . __('Name') . "" . __('Status') . "" . __('Action') . "" . __('Type') . "
    \n"; - $retval .= " " . htmlspecialchars($sql_drop) . "\n"; + $retval .= " " + . htmlspecialchars($sql_drop) . "\n"; $retval .= " \n"; - $retval .= " " . htmlspecialchars($routine['SPECIFIC_NAME']) . "\n"; + $retval .= " " + . htmlspecialchars($routine['SPECIFIC_NAME']) . "\n"; $retval .= " \n"; $retval .= " \n"; if ($routine['ROUTINE_DEFINITION'] !== null - && PMA_currentUserHasPrivilege('ALTER ROUTINE', $db) - && PMA_currentUserHasPrivilege('CREATE ROUTINE', $db) + && PMA_Util::currentUserHasPrivilege('ALTER ROUTINE', $db) + && PMA_Util::currentUserHasPrivilege('CREATE ROUTINE', $db) ) { $retval .= ' ' . $titles['Edit'] . "\n"; } else { @@ -143,56 +164,62 @@ function PMA_RTN_getRowForList($routine, $rowclass = '') } $retval .= " \n"; - if ($routine['ROUTINE_DEFINITION'] !== null - && PMA_currentUserHasPrivilege('EXECUTE', $db) - ) { - // Check if he routine has any input parameters. If it does, - // we will show a dialog to get values for these parameters, - // otherwise we can execute it directly. - $routine_details = PMA_RTN_getDataFromName( - $routine['SPECIFIC_NAME'], - $routine['ROUTINE_TYPE'], - false - ); - if ($routine !== false) { - $execute_action = 'execute_routine'; - for ($i=0; $i<$routine_details['item_num_params']; $i++) { - if ($routine_details['item_type'] == 'PROCEDURE' - && $routine_details['item_param_dir'][$i] == 'OUT' - ) { - continue; - } - $execute_action = 'execute_dialog'; - break; + + // There is a problem with PMA_Util::currentUserHasPrivilege(): + // it does not detect all kinds of privileges, for example + // a direct privilege on a specific routine. So, at this point, + // we show the Execute link, hoping that the user has the correct rights. + // Also, information_schema might be hiding the ROUTINE_DEFINITION + // but a routine with no input parameters can be nonetheless executed. + + // Check if he routine has any input parameters. If it does, + // we will show a dialog to get values for these parameters, + // otherwise we can execute it directly. + $routine_details = PMA_RTN_getDataFromName( + $routine['SPECIFIC_NAME'], + $routine['ROUTINE_TYPE'], + false + ); + if ($routine !== false) { + $execute_action = 'execute_routine'; + for ($i=0; $i<$routine_details['item_num_params']; $i++) { + if ($routine_details['item_type'] == 'PROCEDURE' + && $routine_details['item_param_dir'][$i] == 'OUT' + ) { + continue; } - $retval .= ' ' . $titles['Execute'] . "\n"; + $execute_action = 'execute_dialog'; + break; } - } else { - $retval .= " {$titles['NoExecute']}\n"; + $retval .= ' ' . $titles['Execute'] . "\n"; } + $retval .= " \n"; $retval .= ' ' . $titles['Export'] . "\n"; $retval .= " \n"; - if (PMA_currentUserHasPrivilege('ALTER ROUTINE', $db)) { + if (PMA_Util::currentUserHasPrivilege('ALTER ROUTINE', $db)) { $retval .= ' ' . $titles['Drop'] . "\n"; } else { $retval .= " {$titles['NoDrop']}\n"; @@ -202,7 +229,8 @@ function PMA_RTN_getRowForList($routine, $rowclass = '') $retval .= " {$routine['ROUTINE_TYPE']}\n"; $retval .= " \n"; - $retval .= " " . htmlspecialchars($routine['DTD_IDENTIFIER']) . "\n"; + $retval .= " " + . htmlspecialchars($routine['DTD_IDENTIFIER']) . "\n"; $retval .= "
    \n"; - $retval .= " " . htmlspecialchars($trigger['drop']) . "\n"; + $retval .= " " + . htmlspecialchars($trigger['drop']) . "\n"; $retval .= " \n"; $retval .= " " . htmlspecialchars($trigger['name']) . "\n"; $retval .= " \n"; $retval .= " \n"; - $retval .= " " . $trigger['table'] . "\n"; $retval .= " \n"; - if (PMA_currentUserHasPrivilege('TRIGGER', $db, $table)) { + if (PMA_Util::currentUserHasPrivilege('TRIGGER', $db, $table)) { $retval .= ' ' . $titles['Edit'] . "\n"; } else { $retval .= " {$titles['NoEdit']}\n"; @@ -252,16 +282,19 @@ function PMA_TRI_getRowForList($trigger, $rowclass = '') . ' href="db_triggers.php?' . $url_query . '&export_item=1' - . '&item_name=' . urlencode($trigger['name']) + . '&item_name=' + . urlencode($trigger['name']) . '">' . $titles['Export'] . "\n"; $retval .= " \n"; - if (PMA_currentUserHasPrivilege('TRIGGER', $db)) { + if (PMA_Util::currentUserHasPrivilege('TRIGGER', $db)) { $retval .= ' ' . $titles['Drop'] . "\n"; } else { $retval .= " {$titles['NoDrop']}\n"; @@ -281,10 +314,10 @@ function PMA_TRI_getRowForList($trigger, $rowclass = '') /** * Creates the contents for a row in the list of events * - * @param array $event An array of routine data - * @param string $rowclass Empty or one of ['even'|'odd'] + * @param array $event An array of routine data + * @param string $rowclass Empty or one of ['even'|'odd'] * - * @return string HTML code of a cell for the list of events + * @return string HTML code of a cell for the list of events */ function PMA_EVN_getRowForList($event, $rowclass = '') { @@ -292,26 +325,29 @@ function PMA_EVN_getRowForList($event, $rowclass = '') $sql_drop = sprintf( 'DROP EVENT IF EXISTS %s', - PMA_backquote($event['EVENT_NAME']) + PMA_Util::backquote($event['EVENT_NAME']) ); $retval = "
    \n"; - $retval .= " " . htmlspecialchars($sql_drop) . "\n"; + $retval .= " " + . htmlspecialchars($sql_drop) . "\n"; $retval .= " \n"; - $retval .= " " . htmlspecialchars($event['EVENT_NAME']) . "\n"; + $retval .= " " + . htmlspecialchars($event['EVENT_NAME']) . "\n"; $retval .= " \n"; $retval .= " \n"; $retval .= " {$event['STATUS']}\n"; $retval .= " \n"; - if (PMA_currentUserHasPrivilege('EVENT', $db)) { + if (PMA_Util::currentUserHasPrivilege('EVENT', $db)) { $retval .= ' ' . $titles['Edit'] . "\n"; } else { $retval .= " {$titles['NoEdit']}\n"; @@ -322,16 +358,18 @@ function PMA_EVN_getRowForList($event, $rowclass = '') . ' href="db_events.php?' . $url_query . '&export_item=1' - . '&item_name=' . urlencode($event['EVENT_NAME']) + . '&item_name=' + . urlencode($event['EVENT_NAME']) . '">' . $titles['Export'] . "\n"; $retval .= " \n"; - if (PMA_currentUserHasPrivilege('EVENT', $db)) { + if (PMA_Util::currentUserHasPrivilege('EVENT', $db)) { $retval .= ' ' . $titles['Drop'] . "\n"; } else { $retval .= " {$titles['NoDrop']}\n"; diff --git a/phpMyAdmin/libraries/rte/rte_main.inc.php b/phpMyAdmin/libraries/rte/rte_main.inc.php index bdb43b8..9abb9a3 100644 --- a/phpMyAdmin/libraries/rte/rte_main.inc.php +++ b/phpMyAdmin/libraries/rte/rte_main.inc.php @@ -22,9 +22,8 @@ /** * Displays the header and tabs */ - if (! empty($table) && in_array($table, PMA_DBI_get_tables($db))) { - include_once './libraries/tbl_common.php'; - include_once './libraries/tbl_links.inc.php'; + if (! empty($table) && in_array($table, $GLOBALS['dbi']->getTables($db))) { + include_once './libraries/tbl_common.inc.php'; } else { $table = ''; include_once './libraries/db_common.inc.php'; @@ -37,9 +36,9 @@ * create the missing $url_query variable */ if (strlen($db)) { - PMA_DBI_select_db($db); + $GLOBALS['dbi']->selectDb($db); if (! isset($url_query)) { - $url_query = PMA_generate_common_url($db, $table); + $url_query = PMA_URL_getCommon($db, $table); } } } @@ -48,26 +47,28 @@ * Generate the conditional classes that will * be used to attach jQuery events to links */ -$ajax_class = array('add' => '', - 'edit' => '', - 'exec' => '', - 'drop' => '', - 'export' => ''); -if ($GLOBALS['cfg']['AjaxEnable']) { - $ajax_class = array('add' => 'class="ajax_add_anchor"', - 'edit' => 'class="ajax_edit_anchor"', - 'exec' => 'class="ajax_exec_anchor"', - 'drop' => 'class="ajax_drop_anchor"', - 'export' => 'class="ajax_export_anchor"'); -} +$ajax_class = array( + 'add' => '', + 'edit' => '', + 'exec' => '', + 'drop' => '', + 'export' => '' +); +$ajax_class = array( + 'add' => 'class="ajax add_anchor"', + 'edit' => 'class="ajax edit_anchor"', + 'exec' => 'class="ajax exec_anchor"', + 'drop' => 'class="ajax drop_anchor"', + 'export' => 'class="ajax export_anchor"' +); /** * Create labels for the list */ -$titles = PMA_buildActionTitles(); +$titles = PMA_Util::buildActionTitles(); /** - * Keep a list of errors that occured while + * Keep a list of errors that occurred while * processing an 'Add' or 'Edit' operation. */ $errors = array(); @@ -78,7 +79,11 @@ */ switch ($_PMA_RTE) { case 'RTN': - PMA_RTN_main(); + $type = null; + if (isset($_REQUEST['type'])) { + $type = $_REQUEST['type']; + } + PMA_RTN_main($type); break; case 'TRI': PMA_TRI_main(); @@ -88,11 +93,4 @@ break; } -/** - * Display the footer, if necessary - */ -if ($GLOBALS['is_ajax_request'] != true) { - include './libraries/footer.inc.php'; -} - ?> diff --git a/phpMyAdmin/libraries/rte/rte_routines.lib.php b/phpMyAdmin/libraries/rte/rte_routines.lib.php index 9b02db2..0f8f75a 100644 --- a/phpMyAdmin/libraries/rte/rte_routines.lib.php +++ b/phpMyAdmin/libraries/rte/rte_routines.lib.php @@ -11,6 +11,8 @@ /** * Sets required globals + * + * @return void */ function PMA_RTN_setGlobals() { @@ -30,8 +32,14 @@ function PMA_RTN_setGlobals() /** * Main function for the routines functionality + * + * @param string $type 'FUNCTION' for functions, + * 'PROCEDURE' for procedures, + * null for both + * + * @return void */ -function PMA_RTN_main() +function PMA_RTN_main($type) { global $db; @@ -47,8 +55,11 @@ function PMA_RTN_main() */ $columns = "`SPECIFIC_NAME`, `ROUTINE_NAME`, `ROUTINE_TYPE`, "; $columns .= "`DTD_IDENTIFIER`, `ROUTINE_DEFINITION`"; - $where = "ROUTINE_SCHEMA='" . PMA_sqlAddSlashes($db) . "'"; - $items = PMA_DBI_fetch_result( + $where = "ROUTINE_SCHEMA='" . PMA_Util::sqlAddSlashes($db) . "'"; + if (PMA_isValid($type, array('FUNCTION','PROCEDURE'))) { + $where .= " AND `ROUTINE_TYPE`='" . $type . "'"; + } + $items = $GLOBALS['dbi']->fetchResult( "SELECT $columns FROM `INFORMATION_SCHEMA`.`ROUTINES` WHERE $where;" ); echo PMA_RTE_getList('routine', $items); @@ -61,11 +72,13 @@ function PMA_RTN_main() */ if ($GLOBALS['cfg']['Server']['extension'] === 'mysql') { trigger_error( - __('You are using PHP\'s deprecated \'mysql\' extension, ' - . 'which is not capable of handling multi queries. ' - . 'The execution of some stored routines may fail! ' - . 'Please use the improved \'mysqli\' extension to ' - . 'avoid any problems.'), + __( + 'You are using PHP\'s deprecated \'mysql\' extension, ' + . 'which is not capable of handling multi queries. ' + . '[strong]The execution of some stored routines may fail![/strong] ' + . 'Please use the improved \'mysqli\' extension to ' + . 'avoid any problems.' + ), E_USER_WARNING ); } @@ -76,9 +89,9 @@ function PMA_RTN_main() * as returned by PMA_RTN_parseAllParameters() and returns an array containing * the information about this parameter. * - * @param string $value A string containing one parameter of a routine + * @param string $value A string containing one parameter of a routine * - * @return array Parsed information about the input parameter + * @return array Parsed information about the input parameter */ function PMA_RTN_parseOneParameter($value) { @@ -98,7 +111,9 @@ function PMA_RTN_parseOneParameter($value) if ($parsed_param[$pos]['type'] == 'alpha_identifier' || $parsed_param[$pos]['type'] == 'quote_backtick' ) { - $retval[1] = PMA_unQuote($parsed_param[$pos]['data']); + $retval[1] = PMA_Util::unQuote( + $parsed_param[$pos]['data'] + ); $pos++; } $depth = 0; @@ -106,20 +121,30 @@ function PMA_RTN_parseOneParameter($value) $param_opts = array(); for ($i=$pos; $i<$parsed_param['len']; $i++) { if (($parsed_param[$i]['type'] == 'alpha_columnType' - || $parsed_param[$i]['type'] == 'alpha_functionName') && $depth == 0 // "CHAR" seems to be mistaken for a function by the parser + || $parsed_param[$i]['type'] == 'alpha_functionName') && $depth == 0 ) { $retval[2] = strtoupper($parsed_param[$i]['data']); - } else if ($parsed_param[$i]['type'] == 'punct_bracket_open_round' && $depth == 0) { + } else if ($parsed_param[$i]['type'] == 'punct_bracket_open_round' + && $depth == 0 + ) { $depth = 1; - } else if ($parsed_param[$i]['type'] == 'punct_bracket_close_round' && $depth == 1) { + } else if ($parsed_param[$i]['type'] == 'punct_bracket_close_round' + && $depth == 1 + ) { $depth = 0; } else if ($depth == 1) { $param_length .= $parsed_param[$i]['data']; - } else if ($parsed_param[$i]['type'] == 'alpha_reservedWord' && strtoupper($parsed_param[$i]['data']) == 'CHARSET' && $depth == 0) { - if ($parsed_param[$i+1]['type'] == 'alpha_charset' || $parsed_param[$i+1]['type'] == 'alpha_identifier') { + } else if ($parsed_param[$i]['type'] == 'alpha_reservedWord' + && strtoupper($parsed_param[$i]['data']) == 'CHARSET' && $depth == 0 + ) { + if ($parsed_param[$i+1]['type'] == 'alpha_charset' + || $parsed_param[$i+1]['type'] == 'alpha_identifier' + ) { $param_opts[] = strtolower($parsed_param[$i+1]['data']); } - } else if ($parsed_param[$i]['type'] == 'alpha_columnAttrib' && $depth == 0) { + } else if ($parsed_param[$i]['type'] == 'alpha_columnAttrib' + && $depth == 0 + ) { $param_opts[] = strtoupper($parsed_param[$i]['data']); } } @@ -135,10 +160,10 @@ function PMA_RTN_parseOneParameter($value) * SHOW CREATE [PROCEDURE | FUNCTION] query and extracts * information about the routine's parameters. * - * @param array $parsed_query Parsed query, returned by by PMA_SQP_parse() - * @param string $routine_type Routine type: 'PROCEDURE' or 'FUNCTION' + * @param array $parsed_query Parsed query, returned by by PMA_SQP_parse() + * @param string $routine_type Routine type: 'PROCEDURE' or 'FUNCTION' * - * @return array Information about the parameteres of a routine. + * @return array Information about the parameteres of a routine. */ function PMA_RTN_parseAllParameters($parsed_query, $routine_type) { @@ -151,14 +176,20 @@ function PMA_RTN_parseAllParameters($parsed_query, $routine_type) $fetching = false; $depth = 0; for ($i=0; $i<$parsed_query['len']; $i++) { - if ($parsed_query[$i]['type'] == 'alpha_reservedWord' && $parsed_query[$i]['data'] == $routine_type) { + if ($parsed_query[$i]['type'] == 'alpha_reservedWord' + && $parsed_query[$i]['data'] == $routine_type + ) { $fetching = true; - } else if ($fetching == true && $parsed_query[$i]['type'] == 'punct_bracket_open_round') { + } else if ($fetching == true + && $parsed_query[$i]['type'] == 'punct_bracket_open_round' + ) { $depth++; if ($depth > 1) { $buffer .= $parsed_query[$i]['data'] . ' '; } - } else if ($fetching == true && $parsed_query[$i]['type'] == 'punct_bracket_close_round') { + } else if ($fetching == true + && $parsed_query[$i]['type'] == 'punct_bracket_close_round' + ) { $depth--; if ($depth > 0) { $buffer .= $parsed_query[$i]['data'] . ' '; @@ -201,21 +232,30 @@ function PMA_RTN_parseAllParameters($parsed_query, $routine_type) * SHOW CREATE [PROCEDURE | FUNCTION] query and extracts * information about the routine's definer. * - * @param array $parsed_query Parsed query, returned by PMA_SQP_parse() + * @param array $parsed_query Parsed query, returned by PMA_SQP_parse() * - * @return string The definer of a routine. + * @return string The definer of a routine. */ function PMA_RTN_parseRoutineDefiner($parsed_query) { $retval = ''; $fetching = false; for ($i=0; $i<$parsed_query['len']; $i++) { - if ($parsed_query[$i]['type'] == 'alpha_reservedWord' && $parsed_query[$i]['data'] == 'DEFINER') { + if ($parsed_query[$i]['type'] == 'alpha_reservedWord' + && $parsed_query[$i]['data'] == 'DEFINER' + ) { $fetching = true; - } else if ($fetching == true && ($parsed_query[$i]['type'] != 'quote_backtick' && substr($parsed_query[$i]['type'], 0, 5) != 'punct')) { + } else if ($fetching == true + && $parsed_query[$i]['type'] != 'quote_backtick' + && substr($parsed_query[$i]['type'], 0, 5) != 'punct' + ) { break; - } else if ($fetching == true && $parsed_query[$i]['type'] == 'quote_backtick') { - $retval .= PMA_unQuote($parsed_query[$i]['data']); + } else if ($fetching == true + && $parsed_query[$i]['type'] == 'quote_backtick' + ) { + $retval .= PMA_Util::unQuote( + $parsed_query[$i]['data'] + ); } else if ($fetching == true && $parsed_query[$i]['type'] == 'punct_user') { $retval .= $parsed_query[$i]['data']; } @@ -225,6 +265,8 @@ function PMA_RTN_parseRoutineDefiner($parsed_query) /** * Handles editor requests for adding or editing an item + * + * @return void */ function PMA_RTN_handleEditor() { @@ -241,72 +283,102 @@ function PMA_RTN_handleEditor() if (! count($errors)) { // set by PMA_RTN_getQueryFromRequest() // Execute the created query if (! empty($_REQUEST['editor_process_edit'])) { - if (! in_array($_REQUEST['item_original_type'], array('PROCEDURE', 'FUNCTION'))) { - $errors[] = sprintf(__('Invalid routine type: "%s"'), htmlspecialchars($_REQUEST['item_original_type'])); + $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 = PMA_DBI_get_definition($db, $_REQUEST['item_original_type'], $_REQUEST['item_original_name']); - $drop_routine = "DROP {$_REQUEST['item_original_type']} " . PMA_backquote($_REQUEST['item_original_name']) . ";\n"; - $result = PMA_DBI_try_query($drop_routine); + $create_routine = $GLOBALS['dbi']->getDefinition( + $db, $_REQUEST['item_original_type'], + $_REQUEST['item_original_name'] + ); + $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) ) . '
    ' - . __('MySQL said: ') . PMA_DBI_getError(null); + . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); } else { - $result = PMA_DBI_try_query($routine_query); + $result = $GLOBALS['dbi']->tryQuery($routine_query); if (! $result) { $errors[] = sprintf( __('The following query has failed: "%s"'), htmlspecialchars($routine_query) ) . '
    ' - . __('MySQL said: ') . PMA_DBI_getError(null); - // We dropped the old routine, but were unable to create the new one + . __('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 = PMA_DBI_try_query($create_routine); + $result = $GLOBALS['dbi']->tryQuery($create_routine); if (! $result) { - // OMG, this is really bad! We dropped the query, failed to create a new one + // OMG, this is really bad! We dropped the query, + // failed to create a new one // and now even the backup query does not execute! - // This should not happen, but we better handle this just in case. + // This should not happen, but we better handle + // this just in case. $errors[] = __( - 'Sorry, we failed to restore the dropped routine.' + 'Sorry, we failed to restore' + . ' the dropped routine.' ) . '
    ' . __('The backed up query was:') . "\"" . htmlspecialchars($create_routine) . "\"" . '
    ' - . __('MySQL said: ') . PMA_DBI_getError(null); + . __('MySQL said: ') + . $GLOBALS['dbi']->getError(null); } } else { - $message = PMA_Message::success(__('Routine %1$s has been modified.')); - $message->addParam(PMA_backquote($_REQUEST['item_name'])); + $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 = PMA_DBI_try_query($routine_query); + $result = $GLOBALS['dbi']->tryQuery($routine_query); if (! $result) { $errors[] = sprintf( __('The following query has failed: "%s"'), htmlspecialchars($routine_query) ) . '

    ' - . __('MySQL said: ') . PMA_DBI_getError(null); + . __('MySQL said: ') . $GLOBALS['dbi']->getError(null); } else { - $message = PMA_Message::success(__('Routine %1$s has been created.')); - $message->addParam(PMA_backquote($_REQUEST['item_name'])); + $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 occured while processing your request:')); + $message = PMA_Message::error( + __( + 'One or more errors have occurred while' + . ' processing your request:' + ) + ); $message->addString('
      '); foreach ($errors as $string) { $message->addString('
    • ' . $string . '
    • '); @@ -314,33 +386,46 @@ function PMA_RTN_handleEditor() $message->addString('
    '); } - $output = PMA_showMessage($message, $sql_query); + $output = PMA_Util::getMessage($message, $sql_query); if ($GLOBALS['is_ajax_request']) { - $extra_data = array(); + $response = PMA_Response::getInstance(); if ($message->isSuccess()) { - $columns = "`SPECIFIC_NAME`, `ROUTINE_NAME`, `ROUTINE_TYPE`, `DTD_IDENTIFIER`, `ROUTINE_DEFINITION`"; - $where = "ROUTINE_SCHEMA='" . PMA_sqlAddSlashes($db) . "' " - . "AND ROUTINE_NAME='" . PMA_sqlAddSlashes($_REQUEST['item_name']) . "'" - . "AND ROUTINE_TYPE='" . PMA_sqlAddSlashes($_REQUEST['item_type']) . "'"; - $routine = PMA_DBI_fetch_single_row("SELECT $columns FROM `INFORMATION_SCHEMA`.`ROUTINES` WHERE $where;"); - $extra_data['name'] = htmlspecialchars(strtoupper($_REQUEST['item_name'])); - $extra_data['new_row'] = PMA_RTN_getRowForList($routine); - $extra_data['insert'] = ! empty($routine); - $response = $output; + $columns = "`SPECIFIC_NAME`, `ROUTINE_NAME`, `ROUTINE_TYPE`," + . " `DTD_IDENTIFIER`, `ROUTINE_DEFINITION`"; + $where = "ROUTINE_SCHEMA='" . PMA_Util::sqlAddSlashes($db) . "' " + . "AND ROUTINE_NAME='" + . PMA_Util::sqlAddSlashes($_REQUEST['item_name']) . "'" + . "AND ROUTINE_TYPE='" + . PMA_Util::sqlAddSlashes($_REQUEST['item_type']) . "'"; + $routine = $GLOBALS['dbi']->fetchSingleRow( + "SELECT $columns FROM `INFORMATION_SCHEMA`.`ROUTINES`" + . " WHERE $where;" + ); + $response->addJSON( + 'name', htmlspecialchars(strtoupper($_REQUEST['item_name'])) + ); + $response->addJSON('new_row', PMA_RTN_getRowForList($routine)); + $response->addJSON('insert', ! empty($routine)); + $response->addJSON('message', $output); } else { - $response = $message; + $response->isSuccess(false); + $response->addJSON('message', $output); } - PMA_ajaxResponse($response, $message->isSuccess(), $extra_data); + exit; } } /** * Display a form used to add/edit a routine, if necessary */ - if (count($errors) || ( empty($_REQUEST['editor_process_add']) && empty($_REQUEST['editor_process_edit']) + // FIXME: this must be simpler than that + if (count($errors) + || ( empty($_REQUEST['editor_process_add']) + && empty($_REQUEST['editor_process_edit']) && (! empty($_REQUEST['add_item']) || ! empty($_REQUEST['edit_item']) - || ! empty($_REQUEST['routine_addparameter']) || ! empty($_REQUEST['routine_removeparameter']) - || ! empty($_REQUEST['routine_changetype']))) // FIXME: this must be simpler than that + || ! empty($_REQUEST['routine_addparameter']) + || ! empty($_REQUEST['routine_removeparameter']) + || ! empty($_REQUEST['routine_changetype']))) ) { // Handle requests to add/remove parameters and changing routine type // This is necessary when JS is disabled @@ -359,8 +444,12 @@ function PMA_RTN_handleEditor() $mode = 'add'; } else if (! empty($_REQUEST['edit_item'])) { $title = __("Edit routine"); - if (! $operation && ! empty($_REQUEST['item_name']) && empty($_REQUEST['editor_process_edit'])) { - $routine = PMA_RTN_getDataFromName($_REQUEST['item_name'], $_REQUEST['item_type']); + if (! $operation && ! empty($_REQUEST['item_name']) + && empty($_REQUEST['editor_process_edit']) + ) { + $routine = PMA_RTN_getDataFromName( + $_REQUEST['item_name'], $_REQUEST['item_type'] + ); if ($routine !== false) { $routine['item_original_name'] = $routine['item_name']; $routine['item_original_type'] = $routine['item_type']; @@ -374,25 +463,27 @@ function PMA_RTN_handleEditor() // Show form $editor = PMA_RTN_getEditorForm($mode, $operation, $routine); if ($GLOBALS['is_ajax_request']) { - $template = PMA_RTN_getParameterRow(); - $extra_data = array('title' => $title, - 'param_template' => $template, - 'type' => $routine['item_type']); - PMA_ajaxResponse($editor, true, $extra_data); + $response = PMA_Response::getInstance(); + $response->addJSON('message', $editor); + $response->addJSON('title', $title); + $response->addJSON('param_template', PMA_RTN_getParameterRow()); + $response->addJSON('type', $routine['item_type']); + } else { + echo "\n\n

    $title

    \n\n$editor"; } - echo "\n\n

    $title

    \n\n$editor"; - include './libraries/footer.inc.php'; - // exit; + exit; } else { - $message = __('Error in processing request') . ' : '; + $message = __('Error in processing request:') . ' '; $message .= sprintf( PMA_RTE_getWord('not_found'), - htmlspecialchars(PMA_backquote($_REQUEST['item_name'])), - htmlspecialchars(PMA_backquote($db)) + htmlspecialchars(PMA_Util::backquote($_REQUEST['item_name'])), + htmlspecialchars(PMA_Util::backquote($db)) ); $message = PMA_message::error($message); if ($GLOBALS['is_ajax_request']) { - PMA_ajaxResponse($message, false); + $response->isSuccess(false); + $response->addJSON('message', $message); + exit; } else { $message->display(); } @@ -406,7 +497,7 @@ function PMA_RTN_handleEditor() * the 'Add another parameter', 'Remove last parameter' and * 'Change routine type' functionalities when JS is disabled. * - * @return array Data necessary to create the routine editor. + * @return array Data necessary to create the routine editor. */ function PMA_RTN_getDataFromRequest() { @@ -466,7 +557,7 @@ function PMA_RTN_getDataFromRequest() $retval['item_param_name'] = $_REQUEST['item_param_name']; $retval['item_param_type'] = $_REQUEST['item_param_type']; foreach ($retval['item_param_type'] as $key => $value) { - if (! in_array($value, PMA_getSupportedDatatypes(), true)) { + if (! in_array($value, PMA_Util::getSupportedDatatypes(), true)) { $retval['item_param_type'][$key] = ''; } } @@ -483,7 +574,7 @@ function PMA_RTN_getDataFromRequest() } $retval['item_returntype'] = ''; if (isset($_REQUEST['item_returntype']) - && in_array($_REQUEST['item_returntype'], PMA_getSupportedDatatypes()) + && in_array($_REQUEST['item_returntype'], PMA_Util::getSupportedDatatypes()) ) { $retval['item_returntype'] = $_REQUEST['item_returntype']; } @@ -517,12 +608,12 @@ function PMA_RTN_getDataFromRequest() * This function will generate the values that are required to complete * the "Edit routine" form given the name of a routine. * - * @param string $name The name of the routine. - * @param string $type Type of routine (ROUTINE|PROCEDURE) - * @param bool $all Whether to return all data or just - * the info about parameters. + * @param string $name The name of the routine. + * @param string $type Type of routine (ROUTINE|PROCEDURE) + * @param bool $all Whether to return all data or just + * the info about parameters. * - * @return array Data necessary to create the routine editor. + * @return array Data necessary to create the routine editor. */ function PMA_RTN_getDataFromName($name, $type, $all = true) { @@ -534,12 +625,12 @@ function PMA_RTN_getDataFromName($name, $type, $all = true) $fields = "SPECIFIC_NAME, ROUTINE_TYPE, DTD_IDENTIFIER, " . "ROUTINE_DEFINITION, IS_DETERMINISTIC, SQL_DATA_ACCESS, " . "ROUTINE_COMMENT, SECURITY_TYPE"; - $where = "ROUTINE_SCHEMA='" . PMA_sqlAddSlashes($db) . "' " - . "AND SPECIFIC_NAME='" . PMA_sqlAddSlashes($name) . "'" - . "AND ROUTINE_TYPE='" . PMA_sqlAddSlashes($type) . "'"; + $where = "ROUTINE_SCHEMA='" . PMA_Util::sqlAddSlashes($db) . "' " + . "AND SPECIFIC_NAME='" . PMA_Util::sqlAddSlashes($name) . "'" + . "AND ROUTINE_TYPE='" . PMA_Util::sqlAddSlashes($type) . "'"; $query = "SELECT $fields FROM INFORMATION_SCHEMA.ROUTINES WHERE $where;"; - $routine = PMA_DBI_fetch_single_row($query); + $routine = $GLOBALS['dbi']->fetchSingleRow($query); if (! $routine) { return false; @@ -549,7 +640,7 @@ function PMA_RTN_getDataFromName($name, $type, $all = true) $retval['item_name'] = $routine['SPECIFIC_NAME']; $retval['item_type'] = $routine['ROUTINE_TYPE']; $parsed_query = PMA_SQP_parse( - PMA_DBI_get_definition( + $GLOBALS['dbi']->getDefinition( $db, $routine['ROUTINE_TYPE'], $routine['SPECIFIC_NAME'] @@ -589,7 +680,9 @@ function PMA_RTN_getDataFromName($name, $type, $all = true) && strtoupper($parsed_query[$i]['data']) == 'RETURNS' ) { $fetching = true; - } else if ($fetching == true && $parsed_query[$i]['type'] == 'alpha_reservedWord') { + } else if ($fetching == true + && $parsed_query[$i]['type'] == 'alpha_reservedWord' + ) { // We will not be looking for options such as UNSIGNED // or ZEROFILL because there is no way that a numeric // field's DTD_IDENTIFIER can be longer than 64 @@ -616,8 +709,8 @@ function PMA_RTN_getDataFromName($name, $type, $all = true) $retval['item_returnopts_num'] = $returnparam[4]; $retval['item_returnopts_text'] = $returnparam[4]; } - $retval['item_definer'] = PMA_RTN_parseRoutineDefiner($parsed_query); - $retval['item_definition'] = $routine['ROUTINE_DEFINITION']; + $retval['item_definer'] = PMA_RTN_parseRoutineDefiner($parsed_query); + $retval['item_definition'] = $routine['ROUTINE_DEFINITION']; $retval['item_isdeterministic'] = ''; if ($routine['IS_DETERMINISTIC'] == 'YES') { $retval['item_isdeterministic'] = " checked='checked'"; @@ -639,15 +732,15 @@ function PMA_RTN_getDataFromName($name, $type, $all = true) /** * Creates one row for the parameter table used in the routine editor. * - * @param array $routine Data for the routine returned by - * PMA_RTN_getDataFromRequest() or - * PMA_RTN_getDataFromName() - * @param mixed $index Either a numeric index of the row being processed - * or NULL to create a template row for AJAX request - * @param string $class Class used to hide the direction column, if the - * row is for a stored function. + * @param array $routine Data for the routine returned by + * PMA_RTN_getDataFromRequest() or + * PMA_RTN_getDataFromName() + * @param mixed $index Either a numeric index of the row being processed + * or NULL to create a template row for AJAX request + * @param string $class Class used to hide the direction column, if the + * row is for a stored function. * - * @return string HTML code of one row of parameter table for the editor. + * @return string HTML code of one row of parameter table for the editor. */ function PMA_RTN_getParameterRow($routine = array(), $index = null, $class = '') { @@ -692,19 +785,22 @@ function PMA_RTN_getParameterRow($routine = array(), $index = null, $class = '') } $retval .= " \n"; $retval .= "
    \n"; - $retval .= " \n"; $retval .= " \n"; $retval .= "
    \n"; @@ -853,17 +951,20 @@ function PMA_RTN_getEditorForm($mode, $operation, $routine) $retval .= " \n"; $retval .= " \n"; $retval .= "\n"; @@ -873,7 +974,8 @@ function PMA_RTN_getEditorForm($mode, $operation, $routine) // parameter handling start $retval .= "
    " . __('Type') . "\n"; if ($GLOBALS['is_ajax_request']) { - $retval .= " \n"; + $retval .= " \n"; } else { - $retval .= " \n"; - $retval .= "
    \n"; - $retval .= " {$routine['item_type']}\n"; - $retval .= "
    \n"; - $retval .= " \n"; + $retval .= "\n" + . "
    \n" + . $routine['item_type'] . "\n" + . "
    \n" + . "\n"; } $retval .= "
    \n"; $retval .= " \n"; - $retval .= " \n"; + $retval .= " \n"; $retval .= " \n"; $retval .= " \n"; $retval .= " \n"; @@ -889,7 +991,7 @@ function PMA_RTN_getEditorForm($mode, $operation, $routine) $retval .= "\n"; $retval .= " \n"; $retval .= " \n"; $retval .= "\n"; $retval .= "\n"; @@ -944,7 +1047,8 @@ function PMA_RTN_getEditorForm($mode, $operation, $routine) $retval .= "\n"; $retval .= "\n"; $retval .= " \n"; - $retval .= " \n"; + $retval .= " \n"; $retval .= "\n"; $retval .= "\n"; $retval .= " \n"; @@ -954,8 +1058,10 @@ function PMA_RTN_getEditorForm($mode, $operation, $routine) $retval .= "\n"; $retval .= " \n"; $retval .= " \n"; $retval .= "\n"; $retval .= "\n"; @@ -996,20 +1102,21 @@ function PMA_RTN_getEditorForm($mode, $operation, $routine) /** * Composes the query necessary to create a routine from an HTTP request. * - * @return string The CREATE [ROUTINE | PROCEDURE] query. + * @return string The CREATE [ROUTINE | PROCEDURE] query. */ function PMA_RTN_getQueryFromRequest() { - global $_REQUEST, $cfg, $errors, $param_sqldataaccess, $param_directions; + global $_REQUEST, $errors, $param_sqldataaccess, $param_directions, $PMA_Types; - $_REQUEST['item_type'] = isset($_REQUEST['item_type']) ? $_REQUEST['item_type'] : ''; + $_REQUEST['item_type'] = isset($_REQUEST['item_type']) + ? $_REQUEST['item_type'] : ''; $query = 'CREATE '; if (! empty($_REQUEST['item_definer'])) { if (strpos($_REQUEST['item_definer'], '@') !== false) { $arr = explode('@', $_REQUEST['item_definer']); - $query .= 'DEFINER=' . PMA_backquote($arr[0]); - $query .= '@' . PMA_backquote($arr[1]) . ' '; + $query .= 'DEFINER=' . PMA_Util::backquote($arr[0]); + $query .= '@' . PMA_Util::backquote($arr[1]) . ' '; } else { $errors[] = __('The definer must be in the "username@hostname" format'); } @@ -1019,10 +1126,13 @@ function PMA_RTN_getQueryFromRequest() ) { $query .= $_REQUEST['item_type'] . ' '; } else { - $errors[] = sprintf(__('Invalid routine type: "%s"'), htmlspecialchars($_REQUEST['item_type'])); + $errors[] = sprintf( + __('Invalid routine type: "%s"'), + htmlspecialchars($_REQUEST['item_type']) + ); } if (! empty($_REQUEST['item_name'])) { - $query .= PMA_backquote($_REQUEST['item_name']); + $query .= PMA_Util::backquote($_REQUEST['item_name']); } else { $errors[] = __('You must provide a routine name'); } @@ -1030,6 +1140,7 @@ function PMA_RTN_getQueryFromRequest() $warned_about_dir = false; $warned_about_name = false; $warned_about_length = false; + if ( ! empty($_REQUEST['item_param_name']) && ! empty($_REQUEST['item_param_type']) && ! empty($_REQUEST['item_param_length']) @@ -1037,16 +1148,24 @@ function PMA_RTN_getQueryFromRequest() && is_array($_REQUEST['item_param_type']) && is_array($_REQUEST['item_param_length']) ) { - for ($i=0; $igetTypeClass($item_param_type[$i]) == 'CHAR') { + $params .= ' CHARSET ' + . strtolower($_REQUEST['item_param_opts_text'][$i]); } } if (! empty($_REQUEST['item_param_opts_num'][$i])) { - if (in_array($_REQUEST['item_param_type'][$i], $cfg['ColumnTypes']['NUMERIC'])) { - $params .= ' ' . strtoupper($_REQUEST['item_param_opts_num'][$i]); + if ($PMA_Types->getTypeClass($item_param_type[$i]) == 'NUMBER') { + $params .= ' ' + . strtoupper($_REQUEST['item_param_opts_num'][$i]); } } - if ($i != count($_REQUEST['item_param_name'])-1) { + if ($i != (count($item_param_name) - 1)) { $params .= ", "; } } else if (! $warned_about_name) { $warned_about_name = true; - $errors[] = __('You must provide a name and a type for each routine parameter.'); + $errors[] = __( + 'You must provide a name and a type for each routine parameter.' + ); break; } } } $query .= "(" . $params . ") "; if ($_REQUEST['item_type'] == 'FUNCTION') { - if (! empty($_REQUEST['item_returntype']) && in_array($_REQUEST['item_returntype'], PMA_getSupportedDatatypes())) { - $query .= "RETURNS {$_REQUEST['item_returntype']}"; + $item_returntype = isset($_REQUEST['item_returntype']) + ? $_REQUEST['item_returntype'] + : null; + + if (! empty($item_returntype) + && in_array( + $item_returntype, PMA_Util::getSupportedDatatypes() + ) + ) { + $query .= "RETURNS " . $item_returntype; } else { $errors[] = __('You must provide a valid return type for the routine.'); } if (! empty($_REQUEST['item_returnlength']) - && !preg_match('@^(DATE|DATETIME|TIME|TINYBLOB|TINYTEXT|BLOB|TEXT|MEDIUMBLOB|MEDIUMTEXT|LONGBLOB|LONGTEXT|SERIAL|BOOLEAN)$@i', - $_REQUEST['item_returntype']) + && !preg_match( + '@^(DATE|DATETIME|TIME|TINYBLOB|TINYTEXT|BLOB|TEXT|' + . 'MEDIUMBLOB|MEDIUMTEXT|LONGBLOB|LONGTEXT|SERIAL|BOOLEAN)$@i', + $item_returntype + ) ) { $query .= "(" . $_REQUEST['item_returnlength'] . ")"; - } else if (empty($_REQUEST['item_returnlength']) && preg_match('@^(ENUM|SET|VARCHAR|VARBINARY)$@i', $_REQUEST['item_returntype'])) { + } else if (empty($_REQUEST['item_returnlength']) + && preg_match( + '@^(ENUM|SET|VARCHAR|VARBINARY)$@i', $item_returntype + ) + ) { if (! $warned_about_length) { $warned_about_length = true; - $errors[] = __('You must provide length/values for routine parameters of type ENUM, SET, VARCHAR and VARBINARY.'); + $errors[] = __( + 'You must provide length/values for routine parameters' + . ' of type ENUM, SET, VARCHAR and VARBINARY.' + ); } } if (! empty($_REQUEST['item_returnopts_text'])) { - if (in_array($_REQUEST['item_returntype'], $cfg['ColumnTypes']['STRING'])) { - $query .= ' CHARSET ' . strtolower($_REQUEST['item_returnopts_text']); + if ($PMA_Types->getTypeClass($item_returntype) == 'CHAR') { + $query .= ' CHARSET ' + . strtolower($_REQUEST['item_returnopts_text']); } } if (! empty($_REQUEST['item_returnopts_num'])) { - if (in_array($_REQUEST['item_returntype'], $cfg['ColumnTypes']['NUMERIC'])) { + if ($PMA_Types->getTypeClass($item_returntype) == 'NUMBER') { $query .= ' ' . strtoupper($_REQUEST['item_returnopts_num']); } } $query .= ' '; } if (! empty($_REQUEST['item_comment'])) { - $query .= "COMMENT '" . PMA_sqlAddslashes($_REQUEST['item_comment']) . "' "; + $query .= "COMMENT '" . PMA_Util::sqlAddslashes($_REQUEST['item_comment']) + . "' "; } if (isset($_REQUEST['item_isdeterministic'])) { $query .= 'DETERMINISTIC '; } else { $query .= 'NOT DETERMINISTIC '; } - if (! empty($_REQUEST['item_sqldataaccess']) && in_array($_REQUEST['item_sqldataaccess'], $param_sqldataaccess)) { + if (! empty($_REQUEST['item_sqldataaccess']) + && in_array($_REQUEST['item_sqldataaccess'], $param_sqldataaccess) + ) { $query .= $_REQUEST['item_sqldataaccess'] . ' '; } if (! empty($_REQUEST['item_securitytype'])) { - if ($_REQUEST['item_securitytype'] == 'DEFINER' || $_REQUEST['item_securitytype'] == 'INVOKER') { + if ($_REQUEST['item_securitytype'] == 'DEFINER' + || $_REQUEST['item_securitytype'] == 'INVOKER' + ) { $query .= 'SQL SECURITY ' . $_REQUEST['item_securitytype'] . ' '; } } @@ -1142,32 +1301,42 @@ function PMA_RTN_getQueryFromRequest() /** * Handles requests for executing a routine + * + * @return void */ function PMA_RTN_handleExecute() { - global $_GET, $_POST, $_REQUEST, $GLOBALS, $db, $cfg; + global $_GET, $_POST, $_REQUEST, $GLOBALS, $db; /** * Handle all user requests other than the default of listing routines */ if (! empty($_REQUEST['execute_routine']) && ! empty($_REQUEST['item_name'])) { // Build the queries - $routine = PMA_RTN_getDataFromName($_REQUEST['item_name'], $_REQUEST['item_type'], false); + $routine = PMA_RTN_getDataFromName( + $_REQUEST['item_name'], $_REQUEST['item_type'], false + ); if ($routine !== false) { $queries = array(); $end_query = array(); $args = array(); + $all_functions = $GLOBALS['PMA_Types']->getAllFunctions(); for ($i=0; $i<$routine['item_num_params']; $i++) { if (isset($_REQUEST['params'][$routine['item_param_name'][$i]])) { $value = $_REQUEST['params'][$routine['item_param_name'][$i]]; if (is_array($value)) { // is SET type $value = implode(',', $value); } - $value = PMA_sqlAddSlashes($value); + $value = PMA_Util::sqlAddSlashes($value); if (! empty($_REQUEST['funcs'][$routine['item_param_name'][$i]]) - && in_array($_REQUEST['funcs'][$routine['item_param_name'][$i]], $cfg['Functions']) + && in_array( + $_REQUEST['funcs'][$routine['item_param_name'][$i]], + $all_functions + ) ) { - $queries[] = "SET @p$i={$_REQUEST['funcs'][$routine['item_param_name'][$i]]}('$value');\n"; + $queries[] = "SET @p$i=" + . $_REQUEST['funcs'][$routine['item_param_name'][$i]] + . "('$value');\n"; } else { $queries[] = "SET @p$i='$value';\n"; } @@ -1179,49 +1348,108 @@ function PMA_RTN_handleExecute() if ($routine['item_param_dir'][$i] == 'OUT' || $routine['item_param_dir'][$i] == 'INOUT' ) { - $end_query[] = "@p$i AS " . PMA_backquote($routine['item_param_name'][$i]); + $end_query[] = "@p$i AS " + . PMA_Util::backquote($routine['item_param_name'][$i]); } } } if ($routine['item_type'] == 'PROCEDURE') { - $queries[] = "CALL " . PMA_backquote($routine['item_name']) + $queries[] = "CALL " . PMA_Util::backquote($routine['item_name']) . "(" . implode(', ', $args) . ");\n"; if (count($end_query)) { $queries[] = "SELECT " . implode(', ', $end_query) . ";\n"; } } else { - $queries[] = "SELECT " . PMA_backquote($routine['item_name']) + $queries[] = "SELECT " . PMA_Util::backquote($routine['item_name']) . "(" . implode(', ', $args) . ") " - . "AS " . PMA_backquote($routine['item_name']) . ";\n"; + . "AS " . PMA_Util::backquote($routine['item_name']) + . ";\n"; } - // Execute the queries - $affected = 0; - $result = null; + + // Get all the queries as one SQL statement + $multiple_query = implode("", $queries); + $outcome = true; - foreach ($queries as $query) { - $resource = PMA_DBI_try_query($query); - if ($resource === false) { - $outcome = false; - break; - } - while (true) { - if (! PMA_DBI_more_results()) { - break; - } - PMA_DBI_next_result(); - } - if (substr($query, 0, 6) == 'SELECT') { - $result = $resource; - } else if (substr($query, 0, 4) == 'CALL') { - $result = $resource ? $resource : $result; - $affected = PMA_DBI_affected_rows() - PMA_DBI_num_rows($resource); - } + $affected = 0; + + // Execute query + if (! $GLOBALS['dbi']->tryMultiQuery($multiple_query)) { + $outcome = false; } + // Generate output if ($outcome) { + + // Pass the SQL queries through the "pretty printer" + $output = PMA_Util::formatSql(implode($queries, "\n")); + + // Display results + $output .= "
    "; + $output .= sprintf( + __('Execution results of routine %s'), + PMA_Util::backquote(htmlspecialchars($routine['item_name'])) + ); + $output .= ""; + + $num_of_rusults_set_to_display = 0; + + do { + + $result = $GLOBALS['dbi']->storeResult(); + $num_rows = $GLOBALS['dbi']->numRows($result); + + if (($result !== false) && ($num_rows > 0)) { + + $output .= "
    " . __('Direction') . "" + . __('Direction') . "" . __('Name') . "" . __('Type') . "" . __('Length/Values') . "
     \n"; - $retval .= " \n"; $retval .= " \n"; $retval .= "
    " . __('Is deterministic') . "
    " . __('Definer') . "
    " . __('Security type') . "
    "; + foreach ($GLOBALS['dbi']->getFieldsMeta($result) + as $key => $field) { + $output .= ""; + } + $output .= ""; + + $color_class = 'odd'; + + while ($row = $GLOBALS['dbi']->fetchAssoc($result)) { + $output .= ""; + foreach ($row as $key => $value) { + if ($value === null) { + $value = 'NULL'; + } else { + $value = htmlspecialchars($value); + } + $output .= ""; + } + $output .= ""; + $color_class = ($color_class == 'odd') ? 'even' : 'odd'; + } + + $output .= "
    "; + $output .= htmlspecialchars($field->name); + $output .= "
    " + . $value . "
    "; + $num_of_rusults_set_to_display++; + $affected = $num_rows; + + } + + if (! $GLOBALS['dbi']->moreResults()) { + break; + } + + $output .= "
    "; + + $GLOBALS['dbi']->freeResult($result); + + } while ($GLOBALS['dbi']->nextResult()); + + $output .= "
    "; + $message = __('Your SQL query has been executed successfully'); if ($routine['item_type'] == 'PROCEDURE') { $message .= '
    '; + + // TODO : message need to be modified according to the + // output from the routine $message .= sprintf( _ngettext( '%d row affected by the last statement inside the procedure', @@ -1232,59 +1460,33 @@ function PMA_RTN_handleExecute() ); } $message = PMA_message::success($message); - // Pass the SQL queries through the "pretty printer" - $output = ''; - $output .= PMA_SQP_formatHtml(PMA_SQP_parse(implode($queries))); - $output .= ''; - // Display results - if ($result) { - $output .= "
    "; - $output .= sprintf( - __('Execution results of routine %s'), - PMA_backquote(htmlspecialchars($routine['item_name'])) + + if ($num_of_rusults_set_to_display == 0) { + $notice = __( + 'MySQL returned an empty result set (i.e. zero rows).' ); - $output .= ""; - $output .= ""; - foreach (PMA_DBI_get_fields_meta($result) as $key => $field) { - $output .= ""; - } - $output .= ""; - // Stored routines can only ever return ONE ROW. - $data = PMA_DBI_fetch_single_row($result); - foreach ($data as $key => $value) { - if ($value === null) { - $value = 'NULL'; - } else { - $value = htmlspecialchars($value); - } - $output .= ""; - } - $output .= "
    "; - $output .= htmlspecialchars($field->name); - $output .= "
    " . $value . "
    "; - } else { - $notice = __('MySQL returned an empty result set (i.e. zero rows).'); $output .= PMA_message::notice($notice)->getDisplay(); } + } else { $output = ''; $message = PMA_message::error( sprintf( __('The following query has failed: "%s"'), - htmlspecialchars($query) + htmlspecialchars($multiple_query) ) . '

    ' - . __('MySQL said: ') . PMA_DBI_getError(null) + . __('MySQL said: ') . $GLOBALS['dbi']->getError(null) ); } + // Print/send output if ($GLOBALS['is_ajax_request']) { - $extra_data = array('dialog' => false); - PMA_ajaxResponse( - $message->getDisplay() . $output, - $message->isSuccess(), - $extra_data - ); + $response = PMA_Response::getInstance(); + $response->isSuccess($message->isSuccess()); + $response->addJSON('message', $message->getDisplay() . $output); + $response->addJSON('dialog', false); + exit; } else { echo $message->getDisplay() . $output; if ($message->isError()) { @@ -1296,15 +1498,18 @@ function PMA_RTN_handleExecute() // Now deliberately fall through to displaying the routines list } } else { - $message = __('Error in processing request') . ' : '; + $message = __('Error in processing request:') . ' '; $message .= sprintf( PMA_RTE_getWord('not_found'), - htmlspecialchars(PMA_backquote($_REQUEST['item_name'])), - htmlspecialchars(PMA_backquote($db)) + htmlspecialchars(PMA_Util::backquote($_REQUEST['item_name'])), + htmlspecialchars(PMA_Util::backquote($db)) ); $message = PMA_message::error($message); if ($GLOBALS['is_ajax_request']) { - PMA_ajaxResponse($message, $message->isSuccess()); + $response = PMA_Response::getInstance(); + $response->isSuccess(false); + $response->addJSON('message', $message); + exit; } else { echo $message->getDisplay(); unset($_POST); @@ -1314,32 +1519,37 @@ function PMA_RTN_handleExecute() /** * Display the execute form for a routine. */ - $routine = PMA_RTN_getDataFromName($_GET['item_name'], $_GET['item_type'], true); + $routine = PMA_RTN_getDataFromName( + $_GET['item_name'], $_GET['item_type'], true + ); if ($routine !== false) { $form = PMA_RTN_getExecuteForm($routine); if ($GLOBALS['is_ajax_request'] == true) { - $extra_data = array(); - $extra_data['dialog'] = true; - $extra_data['title'] = __("Execute routine") . " "; - $extra_data['title'] .= PMA_backquote( + $title = __("Execute routine") . " " . PMA_Util::backquote( htmlentities($_GET['item_name'], ENT_QUOTES) ); - PMA_ajaxResponse($form, true, $extra_data); + $response = PMA_Response::getInstance(); + $response->addJSON('message', $form); + $response->addJSON('title', $title); + $response->addJSON('dialog', true); } else { echo "\n\n

    " . __("Execute routine") . "

    \n\n"; echo $form; - include './libraries/footer.inc.php'; - // exit; } + exit; } else if (($GLOBALS['is_ajax_request'] == true)) { - $message = __('Error in processing request') . ' : '; + $message = __('Error in processing request:') . ' '; $message .= sprintf( PMA_RTE_getWord('not_found'), - htmlspecialchars(PMA_backquote($_REQUEST['item_name'])), - htmlspecialchars(PMA_backquote($db)) + htmlspecialchars(PMA_Util::backquote($_REQUEST['item_name'])), + htmlspecialchars(PMA_Util::backquote($db)) ); $message = PMA_message::error($message); - PMA_ajaxResponse($message, false); + + $response = PMA_Response::getInstance(); + $response->isSuccess(false); + $response->addJSON('message', $message); + exit; } } } @@ -1347,10 +1557,10 @@ function PMA_RTN_handleExecute() /** * Creates the HTML code that shows the routine execution dialog. * - * @param array $routine Data for the routine returned by - * PMA_RTN_getDataFromName() + * @param array $routine Data for the routine returned by + * PMA_RTN_getDataFromName() * - * @return string HTML code for the routine execution dialog. + * @return string HTML code for the routine execution dialog. */ function PMA_RTN_getExecuteForm($routine) { @@ -1373,7 +1583,7 @@ function PMA_RTN_getExecuteForm($routine) $retval .= " value='{$routine['item_name']}' />\n"; $retval .= "\n"; $retval .= "
    \n"; if (stristr($routine['item_param_type'][$i], 'enum') || stristr($routine['item_param_type'][$i], 'set') - || in_array(strtolower($routine['item_param_type'][$i]), $no_support_types) + || in_array( + strtolower($routine['item_param_type'][$i]), $no_support_types + ) ) { $retval .= "--\n"; } else { @@ -1421,8 +1633,9 @@ function PMA_RTN_getExecuteForm($routine) 'Default' => '', 'first_timestamp' => false ); - $retval .= ""; + $retval .= PMA_Util::getFunctionsForField($field, false); $retval .= ""; } $retval .= "
    \n"; @@ -401,7 +429,7 @@ function PMA_TRI_getEditorForm($mode, $item) /** * Composes the query necessary to create a trigger from an HTTP request. * - * @return string The CREATE TRIGGER query. + * @return string The CREATE TRIGGER query. */ function PMA_TRI_getQueryFromRequest() { @@ -411,31 +439,37 @@ function PMA_TRI_getQueryFromRequest() if (! empty($_REQUEST['item_definer'])) { if (strpos($_REQUEST['item_definer'], '@') !== false) { $arr = explode('@', $_REQUEST['item_definer']); - $query .= 'DEFINER=' . PMA_backquote($arr[0]); - $query .= '@' . PMA_backquote($arr[1]) . ' '; + $query .= 'DEFINER=' . PMA_Util::backquote($arr[0]); + $query .= '@' . PMA_Util::backquote($arr[1]) . ' '; } else { $errors[] = __('The definer must be in the "username@hostname" format'); } } $query .= 'TRIGGER '; if (! empty($_REQUEST['item_name'])) { - $query .= PMA_backquote($_REQUEST['item_name']) . ' '; + $query .= PMA_Util::backquote($_REQUEST['item_name']) . ' '; } else { $errors[] = __('You must provide a trigger name'); } - if (! empty($_REQUEST['item_timing']) && in_array($_REQUEST['item_timing'], $action_timings)) { + if (! empty($_REQUEST['item_timing']) + && in_array($_REQUEST['item_timing'], $action_timings) + ) { $query .= $_REQUEST['item_timing'] . ' '; } else { $errors[] = __('You must provide a valid timing for the trigger'); } - if (! empty($_REQUEST['item_event']) && in_array($_REQUEST['item_event'], $event_manipulations)) { + if (! empty($_REQUEST['item_event']) + && in_array($_REQUEST['item_event'], $event_manipulations) + ) { $query .= $_REQUEST['item_event'] . ' '; } else { $errors[] = __('You must provide a valid event for the trigger'); } $query .= 'ON '; - if (! empty($_REQUEST['item_table']) && in_array($_REQUEST['item_table'], PMA_DBI_get_tables($db))) { - $query .= PMA_backQuote($_REQUEST['item_table']); + if (! empty($_REQUEST['item_table']) + && in_array($_REQUEST['item_table'], $GLOBALS['dbi']->getTables($db)) + ) { + $query .= PMA_Util::backquote($_REQUEST['item_table']); } else { $errors[] = __('You must provide a valid table name'); } diff --git a/phpMyAdmin/libraries/rte/rte_words.lib.php b/phpMyAdmin/libraries/rte/rte_words.lib.php index e046ac2..85210bf 100644 --- a/phpMyAdmin/libraries/rte/rte_words.lib.php +++ b/phpMyAdmin/libraries/rte/rte_words.lib.php @@ -1,12 +1,21 @@ '; } +/** + * Callback function for replacing [doc@anchor] links in bb code. + * + * @param array $found Array of preg matches + * + * @return string Replaced string + */ +function PMA_replaceDocLink($found) +{ + $anchor = $found[1]; + if (strncmp('faq', $anchor, 3) == 0) { + $page = 'faq'; + } else if (strncmp('cfg', $anchor, 3) == 0) { + $page = 'cfg'; + } else { + /* Guess */ + $page = 'setup'; + } + $link = PMA_Util::getDocuLink($page, $anchor); + return ''; +} + /** * Sanitizes $message, taking into account our special codes * for formatting. @@ -82,40 +108,34 @@ function PMA_replaceBBLink($found) * @param string $message the message * @param boolean $escape whether to escape html in result * @param boolean $safe whether string is safe (can keep < and > chars) - * @return string the sanitized message + * + * @return string the sanitized message */ function PMA_sanitize($message, $escape = false, $safe = false) { if (!$safe) { $message = strtr($message, array('<' => '<', '>' => '>')); } + /* Interpret bb code */ $replace_pairs = array( - '[i]' => '', // deprecated by em - '[/i]' => '', // deprecated by em '[em]' => '', '[/em]' => '', - '[b]' => '', // deprecated by strong - '[/b]' => '', // deprecated by strong '[strong]' => '', '[/strong]' => '', - '[tt]' => '', // deprecated by CODE or KBD - '[/tt]' => '', // deprecated by CODE or KBD '[code]' => '', '[/code]' => '', '[kbd]' => '', '[/kbd]' => '', '[br]' => '
    ', '[/a]' => '
    ', - '[sup]' => '', - '[/sup]' => '', + '[/doc]' => '', + '[sup]' => '', + '[/sup]' => '', + // used in common.inc.php: + '[conferr]' => ' -
    -
    > - 20) { - include './libraries/tbl_links.inc.php'; -} // end if (count($fields) > 20) +$hidden_titles = PMA_getHiddenTitlesArray(); -/** - * Displays indexes - */ - -if (! $tbl_is_view && ! $db_is_information_schema && 'ARCHIVE' != $tbl_type) { - PMA_generate_slider_effect('indexes', __('Indexes')); - /** - * Display indexes - */ - echo PMA_Index::getView($table, $db); - ?> -
    - - '); - ?> - - - -
    -
    - - '; - if (empty($showtable)) { - $showtable = PMA_Table::sGetStatusInfo($GLOBALS['db'], $GLOBALS['table'], null, true); - } - - $nonisam = false; - $is_innodb = (isset($showtable['Type']) && $showtable['Type'] == 'InnoDB'); - if (isset($showtable['Type']) && !preg_match('@ISAM|HEAP@i', $showtable['Type'])) { - $nonisam = true; - } - - // Gets some sizes - - $mergetable = PMA_Table::isMerge($GLOBALS['db'], $GLOBALS['table']); - - // this is to display for example 261.2 MiB instead of 268k KiB - $max_digits = 3; - $decimals = 1; - list($data_size, $data_unit) = PMA_formatByteDown($showtable['Data_length'], $max_digits, $decimals); - if ($mergetable == false) { - list($index_size, $index_unit) = PMA_formatByteDown($showtable['Index_length'], $max_digits, $decimals); - } - // InnoDB returns a huge value in Data_free, do not use it - if (! $is_innodb && isset($showtable['Data_free']) && $showtable['Data_free'] > 0) { - list($free_size, $free_unit) = PMA_formatByteDown($showtable['Data_free'], $max_digits, $decimals); - list($effect_size, $effect_unit) = PMA_formatByteDown($showtable['Data_length'] + $showtable['Index_length'] - $showtable['Data_free'], $max_digits, $decimals); - } else { - list($effect_size, $effect_unit) = PMA_formatByteDown($showtable['Data_length'] + $showtable['Index_length'], $max_digits, $decimals); - } - list($tot_size, $tot_unit) = PMA_formatByteDown($showtable['Data_length'] + $showtable['Index_length'], $max_digits, $decimals); - if ($table_info_num_rows > 0) { - list($avg_size, $avg_unit) = PMA_formatByteDown(($showtable['Data_length'] + $showtable['Index_length']) / $showtable['Rows'], 6, 1); - } - - // Displays them - $odd_row = false; - ?> - -
    - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - -
    - - - - - - - - - - - - - - - - - - - - - - - - - 0) { - ?> - - - - - 0 && $mergetable == false) { - ?> - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ' . $tbl_collation . ''; - ?>
    ø
    ø
    -
    - - - - ' . "\n"; - -/** - * Displays the footer - */ -require './libraries/footer.inc.php'; +//display table structure +require_once 'libraries/display_structure.inc.php'; ?> diff --git a/phpMyAdmin/tbl_tracking.php b/phpMyAdmin/tbl_tracking.php index 2370370..2abd935 100644 --- a/phpMyAdmin/tbl_tracking.php +++ b/phpMyAdmin/tbl_tracking.php @@ -1,6 +1,7 @@ = $filter_ts_from && $timestamp <= $filter_ts_to && - ( in_array('*', $filter_users) || in_array($entry['username'], $filter_users) ) ) { - $tmp_entries[] = array( 'id' => $id, - 'timestamp' => $timestamp, - 'username' => $entry['username'], - 'statement' => $entry['statement'] - ); - } - $id++; - } - return($tmp_entries); - } - - $entries = array(); - // Filtering data definition statements - if ($_REQUEST['logtype'] == 'schema' || $_REQUEST['logtype'] == 'schema_and_data') { - $entries = array_merge($entries, PMA_filter_tracking($data['ddlog'], $filter_ts_from, $filter_ts_to, $filter_users)); - } - - // Filtering data manipulation statements - if ($_REQUEST['logtype'] == 'data' || $_REQUEST['logtype'] == 'schema_and_data') { - $entries = array_merge($entries, PMA_filter_tracking($data['dmlog'], $filter_ts_from, $filter_ts_to, $filter_users)); - } - - // Sort it - foreach ($entries as $key => $row) { - $ids[$key] = $row['id']; - $timestamps[$key] = $row['timestamp']; - $usernames[$key] = $row['username']; - $statements[$key] = $row['statement']; - } - - array_multisort($timestamps, SORT_ASC, $ids, SORT_ASC, $usernames, SORT_ASC, $statements, SORT_ASC, $entries); - + $entries = PMA_getEntries($data, $filter_ts_from, $filter_ts_to, $filter_users); } // Export as file download -if (isset($_REQUEST['report_export']) && $_REQUEST['export_type'] == 'sqldumpfile') { - @ini_set('url_rewriter.tags', ''); - - $dump = "# " . sprintf(__('Tracking report for table `%s`'), htmlspecialchars($_REQUEST['table'])) . "\n" . - "# " . date('Y-m-d H:i:s') . "\n"; - foreach ($entries as $entry) { - $dump .= $entry['statement']; - } - $filename = 'log_' . htmlspecialchars($_REQUEST['table']) . '.sql'; - PMA_download_header($filename, 'text/x-sql', strlen($dump)); - - echo $dump; - exit(); +if (isset($_REQUEST['report_export']) + && $_REQUEST['export_type'] == 'sqldumpfile' +) { + PMA_exportAsFileDownload($entries); } - -/** - * Gets tables informations - */ - -/** - * Displays top menu links - */ -require_once './libraries/tbl_links.inc.php'; -echo '
    '; +$html = '
    '; /** * Actions @@ -135,635 +71,83 @@ function PMA_filter_tracking($data, $filter_ts_from, $filter_ts_to, $filter_user // Create tracking version if (isset($_REQUEST['submit_create_version'])) { - $tracking_set = ''; - - if ($_REQUEST['alter_table'] == true) { - $tracking_set .= 'ALTER TABLE,'; - } - if ($_REQUEST['rename_table'] == true) { - $tracking_set .= 'RENAME TABLE,'; - } - if ($_REQUEST['create_table'] == true) { - $tracking_set .= 'CREATE TABLE,'; - } - if ($_REQUEST['drop_table'] == true) { - $tracking_set .= 'DROP TABLE,'; - } - if ($_REQUEST['create_index'] == true) { - $tracking_set .= 'CREATE INDEX,'; - } - if ($_REQUEST['drop_index'] == true) { - $tracking_set .= 'DROP INDEX,'; - } - if ($_REQUEST['insert'] == true) { - $tracking_set .= 'INSERT,'; - } - if ($_REQUEST['update'] == true) { - $tracking_set .= 'UPDATE,'; - } - if ($_REQUEST['delete'] == true) { - $tracking_set .= 'DELETE,'; - } - if ($_REQUEST['truncate'] == true) { - $tracking_set .= 'TRUNCATE,'; - } - $tracking_set = rtrim($tracking_set, ','); - - if (PMA_Tracker::createVersion( - $GLOBALS['db'], - $GLOBALS['table'], - $_REQUEST['version'], - $tracking_set, - PMA_Table::isView($GLOBALS['db'], $GLOBALS['table'])) - ) { - $msg = PMA_Message::success(sprintf(__('Version %s is created, tracking for %s.%s is activated.'), htmlspecialchars($_REQUEST['version']), htmlspecialchars($GLOBALS['db']), htmlspecialchars($GLOBALS['table']))); - $msg->display(); - } + PMA_createTrackingVersion(); } // Deactivate tracking if (isset($_REQUEST['submit_deactivate_now'])) { - if (PMA_Tracker::deactivateTracking($GLOBALS['db'], $GLOBALS['table'], $_REQUEST['version'])) { - $msg = PMA_Message::success(sprintf(__('Tracking for %s.%s , version %s is deactivated.'), htmlspecialchars($GLOBALS['db']), htmlspecialchars($GLOBALS['table']), htmlspecialchars($_REQUEST['version']))); - $msg->display(); - } + PMA_deactivateTracking(); } // Activate tracking if (isset($_REQUEST['submit_activate_now'])) { - if (PMA_Tracker::activateTracking($GLOBALS['db'], $GLOBALS['table'], $_REQUEST['version'])) { - $msg = PMA_Message::success(sprintf(__('Tracking for %s.%s , version %s is activated.'), htmlspecialchars($GLOBALS['db']), htmlspecialchars($GLOBALS['table']), htmlspecialchars($_REQUEST['version']))); - $msg->display(); - } + PMA_activateTracking(); } // Export as SQL execution if (isset($_REQUEST['report_export']) && $_REQUEST['export_type'] == 'execution') { - foreach ($entries as $entry) { - $sql_result = PMA_DBI_query( "/*NOTRACK*/\n" . $entry['statement'] ); - } - $msg = PMA_Message::success(__('SQL statements executed.')); - $msg->display(); + $sql_result = PMA_exportAsSQLExecution($entries); } // Export as SQL dump if (isset($_REQUEST['report_export']) && $_REQUEST['export_type'] == 'sqldump') { - $new_query = "# " . __('You can execute the dump by creating and using a temporary database. Please ensure that you have the privileges to do so.') . "\n" . - "# " . __('Comment out these two lines if you do not need them.') . "\n" . - "\n" . - "CREATE database IF NOT EXISTS pma_temp_db; \n" . - "USE pma_temp_db; \n" . - "\n"; - - foreach ($entries as $entry) { - $new_query .= $entry['statement']; - } - $msg = PMA_Message::success(__('SQL statements exported. Please copy the dump or execute it.')); - $msg->display(); - - $db_temp = $db; - $table_temp = $table; - - $db = $table = ''; - include_once './libraries/sql_query_form.lib.php'; - - PMA_sqlQueryForm($new_query, 'sql'); - - $db = $db_temp; - $table = $table_temp; + PMA_exportAsSQLDump($entries); } /* * Schema snapshot */ if (isset($_REQUEST['snapshot'])) { -?> -

    []

    - -

    - - - - - - - - - - - - - - $field) { -?> - - ' . htmlspecialchars($field['Field']) . '' . "\n"; - } else { - echo '' . "\n"; - } - ?> - - - - - - - - - -
    ' . htmlspecialchars($field['Field']) . 'NULL'; - } else { - echo '' . _pgettext('None for default', 'None') . ''; - } - } ?>
    - - 0) { -?> -

    - - - - - - - - - - - - - - - $index) { - if ($index['Non_unique'] == 0) { - $str_unique = __('Yes'); - } else { - $str_unique = __('No'); - } - if ($index['Packed'] != '') { - $str_packed = __('Yes'); - } else { - $str_packed = __('No'); - } -?> - - - - - - - - - - - - - -
    - -


    -display(); - } - } - - if (isset($_REQUEST['delete_dmlog'])) { - - // Delete dmlog row data - $delete_id = $_REQUEST['delete_dmlog']; - - // Only in case of valable id - if ($delete_id == (int)$delete_id) { - unset($data['dmlog'][$delete_id]); - - if (PMA_Tracker::changeTrackingData($_REQUEST['db'], $_REQUEST['table'], $_REQUEST['version'], 'DML', $data['dmlog'])) - $msg = PMA_Message::success(__('Tracking data manipulation successfully deleted')); - else - $msg = PMA_Message::rawError(__('Query error')); - $msg->display(); - } - } +if (isset($_REQUEST['report']) + && (isset($_REQUEST['delete_ddlog']) || isset($_REQUEST['delete_dmlog'])) +) { + PMA_deleteTrackingReportRows($data); } if (isset($_REQUEST['report']) || isset($_REQUEST['report_export'])) { - ?> -

    []

    - -
    -
    - -
    - ' . - '' . - '' . - '' . - ''; - $str2 = ''; - $str3 = ''; - $str4 = ''; - $str5 = ''; - - printf(__('Show %s with dates from %s to %s by user %s %s'), $str1, $str2, $str3, $str4, $str5); - - // Prepare delete link content here - $drop_image_or_text = ''; - if (true == $GLOBALS['cfg']['PropertiesIconic']) { - $drop_image_or_text .= PMA_getImage('b_drop.png', __('Delete tracking data row from report')); - } - if ('both' === $GLOBALS['cfg']['PropertiesIconic'] || false === $GLOBALS['cfg']['PropertiesIconic']) { - $drop_image_or_text .= __('Delete'); - } - - /* - * First, list tracked data definition statements - */ - $i = 1; - if (count($data['ddlog']) == 0 && count($data['dmlog']) == 0) { - $msg = PMA_Message::notice(__('No data')); - $msg->display(); - } - - if ($selection_schema || $selection_both && count($data['ddlog']) > 0) { - ?> - - - - - - - - - - - - $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']) { - $statement = substr($entry['statement'], 0, $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']) . '[...]'; - } else { - $statement = PMA_formatSql(PMA_SQP_parse($entry['statement'])); - } - $timestamp = strtotime($entry['date']); - - if ($timestamp >= $filter_ts_from && $timestamp <= $filter_ts_to && - ( in_array('*', $filter_users) || in_array($entry['username'], $filter_users) ) ) { - ?> - - - - - - - - - -
    #
    - 0) { - ?> - - - - - - - - - - - - $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']) { - $statement = substr($entry['statement'], 0, $GLOBALS['cfg']['MaxCharactersInDisplayedSQL']) . '[...]'; - } else { - $statement = PMA_formatSql(PMA_SQP_parse($entry['statement'])); - } - $timestamp = strtotime($entry['date']); - - if ($timestamp >= $filter_ts_from && $timestamp <= $filter_ts_to && - ( in_array('*', $filter_users) || in_array($entry['username'], $filter_users) ) ) { - ?> - - - - - - - - - -
    #
    - -
    -
    - ' . - '' . - '' . - '' . - ''; - - $str_export2 = ''; - ?> -
    -
    - - - - - " . sprintf(__('Export as %s'), $str_export1) . $str_export2 . "
    "; - ?> -
    -


    \n"; + $html .= PMA_getHtmlForTrackingReport( + $url_query, $data, $url_params, $selection_schema, $selection_data, + $selection_both, $filter_ts_to, $filter_ts_from, $filter_users + ); } // end of report /* * List selectable tables */ - -$sql_query = " SELECT DISTINCT db_name, table_name FROM " . - PMA_backquote($GLOBALS['cfg']['Server']['pmadb']) . "." . - PMA_backquote($GLOBALS['cfg']['Server']['tracking']) . - " WHERE db_name = '" . PMA_sqlAddSlashes($GLOBALS['db']) . "' " . - " ORDER BY db_name, table_name"; - -$sql_result = PMA_query_as_controluser($sql_query); - -if (PMA_DBI_num_rows($sql_result) > 0) { -?> -
    - - -
    -numRows($selectable_tables_sql_result) > 0) { + $html .= PMA_getHtmlForSelectableTables( + $selectable_tables_sql_result, $url_query + ); } -?> -
    -'; /* * List versions of current table */ - -$sql_query = " SELECT * FROM " . - PMA_backquote($GLOBALS['cfg']['Server']['pmadb']) . "." . - PMA_backquote($GLOBALS['cfg']['Server']['tracking']) . - " WHERE db_name = '" . PMA_sqlAddSlashes($_REQUEST['db']) . "' ". - " AND table_name = '" . PMA_sqlAddSlashes($_REQUEST['table']) ."' ". - " ORDER BY version DESC "; - -$sql_result = PMA_query_as_controluser($sql_query); - -$last_version = 0; -$maxversion = PMA_DBI_fetch_array($sql_result); -$last_version = $maxversion['version']; - +$sql_result = PMA_getListOfVersionsOfTable(); +$last_version = PMA_getTableLastVersionNumber($sql_result); if ($last_version > 0) { -?> - - - - - - - - - - - - - - - - - - - - - - - - - -
    - | -
    - -
    -
    -
    - - - -
    -
    -
    - - -
    -
    -
    - - - -
    -
    -
    - - -
    -
    - -
    - - - -

    - ALTER TABLE
    - RENAME TABLE
    - CREATE TABLE
    - DROP TABLE
    -
    - CREATE INDEX
    - DROP INDEX
    -

    - INSERT
    - UPDATE
    - DELETE
    - TRUNCATE
    +$html .= PMA_getHtmlForDataDefinitionAndManipulationStatements( + $url_query, $last_version +); -
    -
    - -
    -
    -
    +$html .= '
    '; -
    +$response = PMA_Response::getInstance(); +$response->addHTML($html); - diff --git a/phpMyAdmin/tbl_zoom_select.php b/phpMyAdmin/tbl_zoom_select.php index d85ad77..7f4ceea 100644 --- a/phpMyAdmin/tbl_zoom_select.php +++ b/phpMyAdmin/tbl_zoom_select.php @@ -5,37 +5,33 @@ * * display table zoom search form, create SQL queries from form data * + * @package PhpMyAdmin */ /** * Gets some core libraries */ require_once './libraries/common.inc.php'; -require_once './libraries/mysql_charsets.lib.php'; -require_once './libraries/tbl_select.lib.php'; -require_once './libraries/relation.lib.php'; +require_once './libraries/mysql_charsets.inc.php'; +require_once './libraries/TableSearch.class.php'; require_once './libraries/tbl_info.inc.php'; -$GLOBALS['js_include'][] = 'makegrid.js'; -$GLOBALS['js_include'][] = 'sql.js'; -$GLOBALS['js_include'][] = 'functions.js'; -$GLOBALS['js_include'][] = 'date.js'; -/* < IE 9 doesn't support canvas natively */ -if (PMA_USR_BROWSER_AGENT == 'IE' && PMA_USR_BROWSER_VER < 9) { - $GLOBALS['js_include'][] = 'canvg/flashcanvas.js'; -} - -$GLOBALS['js_include'][] = 'jqplot/jquery.jqplot.js'; -$GLOBALS['js_include'][] = 'jqplot/plugins/jqplot.canvasTextRenderer.js'; -$GLOBALS['js_include'][] = 'jqplot/plugins/jqplot.canvasAxisLabelRenderer.js'; -$GLOBALS['js_include'][] = 'jqplot/plugins/jqplot.dateAxisRenderer.js'; -$GLOBALS['js_include'][] = 'jqplot/plugins/jqplot.highlighter.js'; -$GLOBALS['js_include'][] = 'jqplot/plugins/jqplot.cursor.js'; -$GLOBALS['js_include'][] = 'canvg/canvg.js'; -$GLOBALS['js_include'][] = 'jquery/jquery-ui-1.8.16.custom.js'; -$GLOBALS['js_include'][] = 'jquery/timepicker.js'; -$GLOBALS['js_include'][] = 'tbl_zoom_plot_jqplot.js'; - +$response = PMA_Response::getInstance(); +$header = $response->getHeader(); +$scripts = $header->getScripts(); +$scripts->addFile('makegrid.js'); +$scripts->addFile('sql.js'); +$scripts->addFile('jqplot/jquery.jqplot.js'); +$scripts->addFile('jqplot/plugins/jqplot.canvasTextRenderer.js'); +$scripts->addFile('jqplot/plugins/jqplot.canvasAxisLabelRenderer.js'); +$scripts->addFile('jqplot/plugins/jqplot.dateAxisRenderer.js'); +$scripts->addFile('jqplot/plugins/jqplot.highlighter.js'); +$scripts->addFile('jqplot/plugins/jqplot.cursor.js'); +$scripts->addFile('canvg/canvg.js'); +$scripts->addFile('jquery/jquery-ui-timepicker-addon.js'); +$scripts->addFile('tbl_zoom_plot_jqplot.js'); + +$table_search = new PMA_TableSearch($db, $table, "zoom"); /** * Handle AJAX request for data row on point select @@ -46,435 +42,122 @@ $extra_data = array(); $row_info_query = 'SELECT * FROM `' . $_REQUEST['db'] . '`.`' . $_REQUEST['table'] . '` WHERE ' . $_REQUEST['where_clause']; - $result = PMA_DBI_query($row_info_query . ";", null, PMA_DBI_QUERY_STORE); - $fields_meta = PMA_DBI_get_fields_meta($result); - while ($row = PMA_DBI_fetch_assoc($result)) { + $result = $GLOBALS['dbi']->query( + $row_info_query . ";", null, PMA_DatabaseInterface::QUERY_STORE + ); + $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result); + while ($row = $GLOBALS['dbi']->fetchAssoc($result)) { // for bit fields we need to convert them to printable form $i = 0; foreach ($row as $col => $val) { if ($fields_meta[$i]->type == 'bit') { - $row[$col] = PMA_printable_bit_value($val, $fields_meta[$i]->length); + $row[$col] = PMA_Util::printableBitValue( + $val, $fields_meta[$i]->length + ); } $i++; } $extra_data['row_info'] = $row; } - PMA_ajaxResponse(null, true, $extra_data); + PMA_Response::getInstance()->addJSON($extra_data); + exit; } -$titles['Browse'] = PMA_getIcon('b_browse.png', __('Browse foreign values')); /** - * Not selection yet required -> displays the selection form + * Handle AJAX request for changing field information + * (value,collation,operators,field values) in input form + * @var post_params Object containing parameters for the POST request */ +if (isset($_REQUEST['change_tbl_info']) && $_REQUEST['change_tbl_info'] == true) { + $response = PMA_Response::getInstance(); + $field = $_REQUEST['field']; + if ($field == 'pma_null') { + $response->addJSON('field_type', ''); + $response->addJSON('field_collation', ''); + $response->addJSON('field_operators', ''); + $response->addJSON('field_value', ''); + exit; + } + $key = array_search($field, $table_search->getColumnNames()); + $properties = $table_search->getColumnProperties($_REQUEST['it'], $key); + $response->addJSON('field_type', $properties['type']); + $response->addJSON('field_collation', $properties['collation']); + $response->addJSON('field_operators', $properties['func']); + $response->addJSON('field_value', $properties['value']); + exit; +} + // Gets some core libraries -require_once './libraries/tbl_common.php'; +require_once './libraries/tbl_common.inc.php'; $url_query .= '&goto=tbl_select.php&back=tbl_select.php'; -/** - * Gets tables informations - */ +// Gets tables informations require_once './libraries/tbl_info.inc.php'; -/** - * Displays top menu links - */ -require_once './libraries/tbl_links.inc.php'; - if (! isset($goto)) { $goto = $GLOBALS['cfg']['DefaultTabTable']; } // Defines the url to return to in case of error in the next sql statement -$err_url = $goto . '?' . PMA_generate_common_url($db, $table); - -// Gets the list and number of fields - -list($fields_list, $fields_type, $fields_collation, $fields_null) = PMA_tbl_getFields($db, $table); -$fields_cnt = count($fields_list); - -// retrieve keys into foreign fields, if any -// check also foreigners even if relwork is FALSE (to get -// foreign keys from innodb) -$foreigners = PMA_getForeigners($db, $table); -$flag = 1; -$tbl_fields_type = $tbl_fields_collation = $tbl_fields_null = array(); -if (! isset($zoom_submit) && ! isset($inputs)) { - $dataLabel = PMA_getDisplayField($db, $table); -} -?> -
    -
    - -
    > - - - - - -
    - - - - - -"; - } - ?> - - - - - - - - - - - - - - -
    "; - echo __("Additional search criteria"); - echo "
    - - - - - -
    - - -
    - - - - - - - '; -?> -
    -
    -
    -
    -
    - - -
    -
    -
    - -addHTML($table_search->getSecondaryTabs()); +$response->addHTML($table_search->getSelectionForm($goto, $dataLabel)); /* * Handle the input criteria and generate the query result * Form for displaying query results */ -if (isset($zoom_submit) && $inputs[0] != 'pma_null' && $inputs[1] != 'pma_null' && $inputs[0] != $inputs[1]) { - - /* - * Query generation part - */ - $w = $data = array(); - $sql_query = 'SELECT *'; - - //Add the table - $sql_query .= ' FROM ' . PMA_backquote($table); - for ($i = 0; $i < 4; $i++) { - if ($inputs[$i] == 'pma_null') { - continue; - } - $tmp = array(); - // The where clause - $charsets = array(); - $cnt_func = count($zoomFunc[$i]); - $func_type = $zoomFunc[$i]; - list($charsets[$i]) = explode('_', $collations[$i]); - $unaryFlag = (isset($GLOBALS['cfg']['UnaryOperators'][$func_type]) - && $GLOBALS['cfg']['UnaryOperators'][$func_type] == 1) - ? true - : false; - $whereClause = PMA_tbl_search_getWhereClause( - $fields[$i], $inputs[$i], $types[$i], - $collations[$i], $func_type, $unaryFlag - ); - if ($whereClause) { - $w[] = $whereClause; - } - } // end for - if ($w) { - $sql_query .= ' WHERE ' . implode(' AND ', $w); - } - $sql_query .= ' LIMIT ' . $maxPlotLimit; - - /* - * Query execution part - */ - $result = PMA_DBI_query($sql_query . ";", null, PMA_DBI_QUERY_STORE); - $fields_meta = PMA_DBI_get_fields_meta($result); - while ($row = PMA_DBI_fetch_assoc($result)) { - //Need a row with indexes as 0,1,2 for the PMA_getUniqueCondition hence using a temporary array +if (isset($_POST['zoom_submit']) + && $_POST['criteriaColumnNames'][0] != 'pma_null' + && $_POST['criteriaColumnNames'][1] != 'pma_null' + && $_POST['criteriaColumnNames'][0] != $_POST['criteriaColumnNames'][1] +) { + //Query generation part + $sql_query = $table_search->buildSqlQuery(); + $sql_query .= ' LIMIT ' . $_POST['maxPlotLimit']; + + //Query execution part + $result = $GLOBALS['dbi']->query( + $sql_query . ";", null, PMA_DatabaseInterface::QUERY_STORE + ); + $fields_meta = $GLOBALS['dbi']->getFieldsMeta($result); + while ($row = $GLOBALS['dbi']->fetchAssoc($result)) { + //Need a row with indexes as 0,1,2 for the getUniqueCondition + // hence using a temporary array $tmpRow = array(); foreach ($row as $val) { $tmpRow[] = $val; } //Get unique conditon on each row (will be needed for row update) - $uniqueCondition = PMA_getUniqueCondition($result, $fields_cnt, $fields_meta, $tmpRow, true); - + $uniqueCondition = PMA_Util::getUniqueCondition( + $result, count($table_search->getColumnNames()), $fields_meta, $tmpRow, + true + ); //Append it to row array as where_clause $row['where_clause'] = $uniqueCondition[0]; - if ($dataLabel == $inputs[0] || $dataLabel == $inputs[1]) { - $data[] = array( - $inputs[0] => $row[$inputs[0]], - $inputs[1] => $row[$inputs[1]], - 'where_clause' => $uniqueCondition[0] - ); - } elseif ($dataLabel) { - $data[] = array( - $inputs[0] => $row[$inputs[0]], - $inputs[1] => $row[$inputs[1]], - $dataLabel => $row[$dataLabel], - 'where_clause' => $uniqueCondition[0] - ); - } else { - $data[] = array( - $inputs[0] => $row[$inputs[0]], - $inputs[1] => $row[$inputs[1]], - $dataLabel => '', - 'where_clause' => $uniqueCondition[0] - ); - } - } - /* - * Form for displaying point data and also the scatter plot - */ - ?> -
    > - - - -
    - -
    - -
    -
    - -
    - -
    - -
    - - - - addHTML($table_search->getZoomResultsForm($goto, $data)); } -require './libraries/footer.inc.php'; ?> diff --git a/phpMyAdmin/themes.php b/phpMyAdmin/themes.php index e0347bd..aed65f9 100644 --- a/phpMyAdmin/themes.php +++ b/phpMyAdmin/themes.php @@ -1,6 +1,7 @@ getFooter()->setMinimal(); +$header = $response->getHeader(); +$header->setBodyId('bodythemes'); +$header->setTitle('phpMyAdmin - ' . __('Theme')); +$header->disableMenu(); -/* Theme Select */ -$path_to_themes = $cfg['ThemePath'] . '/'; +$hash = '#pma_' . preg_replace('/([0-9]*)\.([0-9]*)\..*/', '\1_\2', PMA_VERSION); +$url = PMA_linkURL('http://www.phpmyadmin.net/home_page/themes.php') . $hash; +$output = '

    phpMyAdmin - ' . __('Theme') . '

    '; +$output .= '

    '; +$output .= ''; +$output .= __('Get more themes!'); +$output .= ''; +$output .= '

    '; +$output .= $_SESSION['PMA_Theme_Manager']->getPrintPreviews(); -/* set language and charset */ -require './libraries/header_http.inc.php'; +$response->addHTML($output); -/* HTML header */ -$page_title = 'phpMyAdmin - ' . __('Theme'); -require './libraries/header_meta_style.inc.php'; -require './libraries/header_scripts.inc.php'; ?> - - - -

    phpMyAdmin -

    -

    -printPreviews(); -?> - - diff --git a/phpMyAdmin/themes/original/css/theme_right.css.php b/phpMyAdmin/themes/original/css/common.css.php similarity index 63% rename from phpMyAdmin/themes/original/css/theme_right.css.php rename to phpMyAdmin/themes/original/css/common.css.php index 43dd9ca..d009947 100644 --- a/phpMyAdmin/themes/original/css/theme_right.css.php +++ b/phpMyAdmin/themes/original/css/common.css.php @@ -1,38 +1,50 @@ /******************************************************************************/ + /* general tags */ html { - font-size: get('fontsize') ? $GLOBALS['PMA_Config']->get('fontsize') : ( - isset($_COOKIE['pma_fontsize']) ? $_COOKIE['pma_fontsize'] : '82%'));?>; + font-size: getFontSize(); ?> } -input, select, textarea { +input, +select, +textarea { font-size: 1em; } + body { font-family: ; padding: 0; - margin: 0 0.5em 0 0; + margin: 0; + margin-: 240px; color: ; background: ; } +body#loginform { + margin: 0; +} + +#page_content { + margin: 0 .5em; +} + textarea, tt, pre, code { font-family: ; @@ -123,6 +135,11 @@ background-color: ; } +.some-margin { + margin: .5em; + margin-top: 1em; +} + /* buttons in some browsers (eg. Konqueror) are block elements, this breaks design */ button { @@ -155,6 +172,38 @@ margin-: 1em; } +table.nospacing { + border-spacing: 0; +} + +table.nopadding tr th, table.nopadding tr td { + padding: 0; +} + +th.left, td.left { + text-align: left; +} + +th.center, td.center { + text-align: center; +} + +th.right, td.right { + text-align: right; +} + +tr.vtop, th.vtop, td.vtop { + vertical-align: top; +} + +tr.vmiddle, th.vmiddle, td.vmiddle { + vertical-align: middle; +} + +tr.vbottom, th.vbottom, td.vbottom { + vertical-align: bottom; +} + .paddingtop { padding-top: 1em; } @@ -234,8 +283,7 @@ /* hovered items */ .odd:hover, .even:hover, -.hover, -.structure_actions_dropdown { +.hover { background: ; color: ; } @@ -320,83 +368,20 @@ border: 1px dashed #000000; } -/* MySQL Parser */ -.syntax { - font-size: 80%; -} - -.syntax a { +/* Doc links in SQL */ +.cm-sql-doc { text-decoration: none; - border-bottom:1px dotted black; -} - -.syntax_comment { - padding-left: 4pt; - padding-right: 4pt; -} - -.syntax_digit { -} - -.syntax_digit_hex { -} - -.syntax_digit_integer { -} - -.syntax_digit_float { -} - -.syntax_punct { -} - -.syntax_alpha { -} - -.syntax_alpha_columnType { - text-transform: uppercase; -} - -.syntax_alpha_columnAttrib { - text-transform: uppercase; -} - -.syntax_alpha_reservedWord { - text-transform: uppercase; - font-weight: bold; -} - -.syntax_alpha_functionName { - text-transform: uppercase; -} - -.syntax_alpha_identifier { -} - -.syntax_alpha_charset { -} - -.syntax_alpha_variable { -} - -.syntax_quote { - white-space: pre; -} - -.syntax_quote_backtick { + border-bottom: 1px dotted #000; + color: inherit !important; } /* leave some space between icons and text */ -.icon, img.footnotemarker { +.icon { vertical-align: middle; margin-right: 0.3em; margin-left: 0.3em; } -img.footnotemarker { - display: none; -} - /* no extra space in table cells */ td .icon { margin: 0; @@ -408,6 +393,10 @@ } /* message boxes: error, confirmation */ +#pma_errors, #pma_demo { + padding: 0 0.5em; +} + .success h1, .notice h1, div.error h1 { @@ -419,22 +408,17 @@ div.success, div.notice, -div.error, -div.footnotes { +div.error { margin: 0.3em 0 0 0; border: 2px solid; - background-repeat: no-repeat; background-position: 10px 50%; padding: 0.1em 0.1em 0.1em 36px; background-position: 99% 50%; - padding: 10px 5% 10px 10px; + padding: 0.1em 46px 0.1em 0.1em; - - padding: 0.3em; - } .success { @@ -444,41 +428,18 @@ h1.success, div.success { border-color: #00FF00; - - background-image: url(getImgPath(); ?>s_success.png); - background-repeat: no-repeat; - - background-position: 5px 50%; - padding: 0.2em 0.2em 0.2em 25px; - - background-position: 97% 50%; - padding: 0.2em 25px 0.2em 0.2em; - - } .success h1 { border-color: #00FF00; } -.notice, .footnotes { +.notice { color: #000000; background-color: #FFFFDD; } h1.notice, -div.notice, -div.footnotes { +div.notice { border-color: #FFD700; - - background-image: url(getImgPath(); ?>s_notice.png); - background-repeat: no-repeat; - - background-position: 5px 50%; - padding: 0.2em 0.2em 0.2em 25px; - - background-position: 97% 50%; - padding: 0.2em 25px 0.2em 0.2em; - - } .notice h1 { border-color: #FFD700; @@ -492,17 +453,6 @@ h1.error, div.error { border-color: #ff0000; - - background-image: url(getImgPath(); ?>s_error.png); - background-repeat: no-repeat; - - background-position: 5px 50%; - padding: 0.2em 0.2em 0.2em 25px; - - background-position: 97% 50%; - padding: 0.2em 25px 0.2em 0.2em; - - } div.error h1 { border-color: #ff0000; @@ -518,8 +468,7 @@ border-left: 0.1em solid #FF0000; border-right: 0.1em solid #FF0000; font-weight: bold; - - background-image: url(getImgPath(); ?>s_really.png); + background-image: url(getImgPath('s_really.png');?>); background-repeat: no-repeat; background-position: 5px 50%; @@ -528,7 +477,6 @@ background-position: 97% 50%; padding: 0.2em 25px 0.2em 0.2em; - } /* end messageboxes */ @@ -613,17 +561,18 @@ /** * login form */ -body.loginform h1, -body.loginform a.logo { +body#loginform h1, +body#loginform a.logo { display: block; text-align: center; } -body.loginform { +body#loginform { + margin-top: 1em; text-align: center; } -body.loginform div.container { +body#loginform div.container { text-align: ; width: 30em; margin: 0 auto; @@ -680,45 +629,6 @@ white-space: nowrap; } -ul#topmenu ul a { - margin: 0; - padding-bottom: 2px; -} - -ul#topmenu .submenu { - position: relative; - display: none; -} -ul#topmenu .shown { - display: block; -} - -ul#topmenu ul { - margin: 0; - padding: 0; - position: absolute; - list-style-type: none; - display: none; - border: 1px #666 solid; - z-index: 2; -} - -ul#topmenu ul.only { - left: 0; -} - -ul#topmenu ul.notonly { - right: 0; -} - -ul#topmenu li:hover ul, ul#topmenu .submenuhover ul { - display: block; -} - -ul#topmenu ul li { - width: 100%; -} - ul#topmenu2 a { display: block; margin: 0.1em; @@ -726,11 +636,6 @@ white-space: nowrap; } -/* disabled tabs */ -ul#topmenu span.tab { - color: #666666; -} - fieldset.caution a { color: #FF0000; } @@ -739,16 +644,6 @@ background-color: #FF0000; } - -/* active tab */ -ul#topmenu a.tabactive, ul#topmenu2 a.tabactive { - color: black; -} - -ul#topmenu ul { - background: ; -} - #topmenu { margin-top: 0.5em; padding: 0.1em 0.3em 0.1em 0.3em; @@ -813,13 +708,6 @@ ul#topmenu > li.active { border-bottom: 1pt solid ; } - -/* disabled tabs */ -ul#topmenu span.tab, -a.error { - cursor: url(getImgPath(); ?>error.ico), default; -} - /* end topmenu */ /* zoom search */ @@ -869,6 +757,7 @@ margin-top: 0.5em; margin-bottom: 0.5em; margin-: 0.5em; + min-width: 16em; } /* END table stats */ @@ -886,7 +775,7 @@ /* Heading */ #topmenucontainer { background: white; - padding-right: 1em; + padding-: 1em; width: 100%; } @@ -900,13 +789,24 @@ #serverinfo .item { white-space: nowrap; - float: +} + +#goto_pagetop { + position: fixed; + padding: .1em .3em; + top: 0; + : 0; + z-index: 900; + background: white; } #span_table_comment { - font-weight: normal; - font-style: italic; - white-space: nowrap; + font-weight: bold; + font-style: italic; + white-space: nowrap; + margin-left: 10px; + color: #D6D6D6; + text-shadow: none; } #serverinfo img { @@ -996,6 +896,14 @@ #fieldset_user_global_rights fieldset { float: ; } + +#fieldset_user_group_rights fieldset { + float: ; +} + +#fieldset_user_global_rights legend input { + margin-: 2em; +} /* END user privileges */ @@ -1023,10 +931,6 @@ white-space: nowrap; } -.jsfeature { - display: none; /* Made visible with js */ -} - /* Also used for the variables page */ fieldset#tableFilter { margin-bottom:1em; @@ -1136,36 +1040,72 @@ /* end serverstatus */ /* server variables */ +#serverVariables { + min-width: 30em; +} +#serverVariables .var-row > div { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + line-height: 2em; +} -a.editLink { +#serverVariables .var-header { + font-weight: bold; + color: ; + background: ; +} +#serverVariables .var-header .var-value { + text-align: ; +} +#serverVariables .var-row { + padding: 0.5em; + min-height: 18px; +} +#serverVariables .var-name { + width: 45%; float: ; - font-family:sans-serif; + font-weight: bold; +} +#serverVariables .var-name.session { + font-weight: normal; + font-style: italic; +} +#serverVariables .var-value { + width: 50%; + float: ; + text-align: ; } -table.serverVariableEditTable { - border:0; - margin:0; - padding:0; - width:100%; +/* server variables editor */ +#serverVariables .editLink { + padding-: 1em; + float: ; + font-family: sans-serif; } -table.serverVariableEditTable td { - border:0; - margin:0; - padding:0; +#serverVariables .serverVariableEditor { + width: 100%; + overflow: hidden; } -table.serverVariableEditTable td:first-child { - white-space:nowrap; - vertical-align:middle; +#serverVariables .serverVariableEditor input { + width: 100%; + margin: 0 0.5em; + box-sizing: border-box; + -ms-box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + height: 2.2em; } - -table.serverVariableEditTable input { - width:95%; +#serverVariables .serverVariableEditor div { + display: block; + overflow: hidden; + padding-: 1em; } - -table#serverVariables td { - height:18px; +#serverVariables .serverVariableEditor a { + float: ; + margin: 0 0.5em; + line-height: 2em; } - /* end server variables */ /* querywindow */ @@ -1190,9 +1130,37 @@ /* profiling */ div#profilingchart { - width:550px; - height:370px; - float:left; + width: 550px; + height: 370px; + float: left; +} + +#profilingchart .jqplot-highlighter-tooltip{ + top: auto !important; + left: 11px; + bottom:24px; +} + +#profilesummarytable th.header, #profiletable th.header{ + cursor: pointer; +} + +#profilesummarytable th.header .sorticon, #profiletable th.header .sorticon{ + width: 16px; + height: 16px; + background-repeat: no-repeat; + background-position: right center; + display: inline-block; + vertical-align: middle; + float: right; +} + +#profilesummarytable th.headerSortUp .sorticon, #profiletable th.headerSortUp .sorticon{ + background-image: url(getImgPath('s_desc.png');?>); +} + +#profilesummarytable th.headerSortDown .sorticon, #profiletable th.headerSortDown .sorticon{ + background-image: url(getImgPath('s_asc.png');?>); } /* END profiling */ @@ -1220,19 +1188,19 @@ width: 100%; /* height: 100%; */ } -textarea#sql_query_edit{ - height:7em; +textarea#sql_query_edit { + height: 7em; width: 95%; - display:block; + display: block; } div#queryboxcontainer div#bookmarkoptions { - margin-top: 0.5em; + margin-top: .5em; } /* end querybox */ /* main page */ #maincontainer { - background-image: url(getImgPath(); ?>logo_right.png); + background-image: url(getImgPath('logo_right.png');?>); background-position: bottom; background-repeat: no-repeat; } @@ -1253,143 +1221,82 @@ } /* END main page */ - - /* iconic view for ul items */ -li#li_create_database { - list-style-image: url(getImgPath(); ?>b_newdb.png); -} -li#li_select_lang { - list-style-image: url(getImgPath(); ?>s_lang.png); +li.no_bullets { + list-style-type:none !important; + margin-left: -25px !important; //align with other list items which have bullets } -li#li_select_mysql_collation { - list-style-image: url(getImgPath(); ?>s_asci.png); -} +/* END iconic view for ul items */ -li#li_select_theme{ - list-style-image: url(getImgPath(); ?>s_theme.png); +#body_browse_foreigners { + background: ; + margin: .5em .5em 0 .5em; } -li#li_user_info{ - /* list-style-image: url(getImgPath(); ?>s_rights.png); */ +#bodyquerywindow { + background: ; } -li#li_mysql_status{ - list-style-image: url(getImgPath(); ?>s_status.png); +#bodythemes { + width: 500px; + margin: auto; + text-align: center; } -li#li_mysql_variables{ - list-style-image: url(getImgPath(); ?>s_vars.png); +#bodythemes img { + border: .1em solid #000; } -li#li_mysql_processes{ - list-style-image: url(getImgPath(); ?>s_process.png); +#bodythemes a:hover img { + border: .1em solid red; } -li#li_mysql_collations{ - list-style-image: url(getImgPath(); ?>s_asci.png); +#fieldset_select_fields { + float: ; } -li#li_mysql_engines{ - list-style-image: url(getImgPath(); ?>b_engine.png); +#selflink { + clear: both; + display: block; + margin-top: 1em; + margin-bottom: 1em; + width: 98%; + margin-left: 1%; + border-top: .1em solid silver; + text-align: ; } -li#li_mysql_binlogs { - list-style-image: url(getImgPath(); ?>s_tbl.png); +#table_innodb_bufferpool_usage, +#table_innodb_bufferpool_activity { + float: ; } -li#li_mysql_databases { - list-style-image: url(getImgPath(); ?>s_db.png); +#div_mysql_charset_collations table { + float: ; } -li#li_export { - list-style-image: url(getImgPath(); ?>b_export.png); +.operations_half_width { + width: 48%; + float: ; } - -li#li_import { - list-style-image: url(getImgPath(); ?>b_import.png); -} - -li#li_change_password { - list-style-image: url(getImgPath(); ?>s_passwd.png); -} - -li#li_log_out { - list-style-image: url(getImgPath(); ?>s_loggoff.png); -} - -li#li_mysql_privilegs{ - list-style-image: url(getImgPath(); ?>s_rights.png); -} - -li#li_switch_dbstats { - list-style-image: url(getImgPath(); ?>b_dbstatistics.png); -} - -li#li_flush_privileges { - list-style-image: url(getImgPath(); ?>s_reload.png); -} - -li#li_user_preferences { - list-style-image: url(getImgPath(); ?>b_tblops.png); -} -/* END iconic view for ul items */ - - - -#body_browse_foreigners { - background: ; - margin: 0.5em 0.5em 0 0.5em; -} - -#bodyquerywindow { - background: ; -} - -#bodythemes { - width: 500px; - margin: auto; - text-align: center; -} - -#bodythemes img { - border: 0.1em solid black; -} - -#bodythemes a:hover img { - border: 0.1em solid red; -} - -#fieldset_select_fields { - float: ; -} - -#selflink { - clear: both; - display: block; - margin-top: 1em; - margin-bottom: 1em; - width: 100%; - border-top: 0.1em solid silver; - text-align: ; -} - -#table_innodb_bufferpool_usage, -#table_innodb_bufferpool_activity { - float: ; +.operations_half_width input[type=text], +.operations_half_width input[type=password], +.operations_half_width input[type=number], +.operations_half_width select { + width: 95%; } - -#div_mysql_charset_collations table { - float: ; +.operations_half_width input[type=text].halfWidth, +.operations_half_width input[type=password].halfWidth, +.operations_half_width input[type=number].halfWidth, +.operations_half_width select.halfWidth { + width: 40%; } - -.operations_half_width { - width: 48%; - float: ; +.operations_half_width ul { + list-style-type: none; + padding: 0; } - .operations_full_width { width: 100%; clear: both; @@ -1412,16 +1319,27 @@ position: absolute; } -code.sql, div.sqlvalidate { +code.sql, +div.sqlvalidate { display: block; padding: 0.3em; margin-top: 0; margin-bottom: 0; + max-height: 10em; + overflow: auto; +} + +#result_query div.sqlOuter, +div.sqlvalidate { border: solid 1px; border-top: 0; border-bottom: 0; - max-height: 10em; - overflow: auto; + background: ; +} + +#PMA_slidingMessage code.sql { + border: solid 1px; + border-top: 0; background: ; } @@ -1464,10 +1382,6 @@ display: none; } -#li_select_server { - list-style-image: url(getImgPath(); ?>s_host.png); -} - #list_server { list-style-image: none; } @@ -1475,31 +1389,67 @@ /** * Progress bar styles */ +div.upload_progress +{ + width: 400px; + margin: 3em auto; + text-align: center; +} + div.upload_progress_bar_outer { - border: 1px solid black; + border: 1px solid #000; width: 202px; + position: relative; + margin: 0 auto 1em; + color: ; } div.upload_progress_bar_inner { - background-color: ; + background-color: ; width: 0; height: 12px; margin: 1px; + overflow: hidden; + color: ; + position: relative; +} + +div.upload_progress_bar_outer div.percentage +{ + position: absolute; + top: 0; + left: 0; + width: 202px; +} + +div.upload_progress_bar_inner div.percentage +{ + top: -1px; + left: -1px; +} + +div#statustext { + margin-top: .5em; } table#serverconnection_src_remote, table#serverconnection_trg_remote, table#serverconnection_src_local, table#serverconnection_trg_local { - float:left; + float: left; } /** * Validation error message styles */ -.invalid_value -{background:#F00;} +input[type=text].invalid_value, +input[type=password].invalid_value, +input[type=number].invalid_value, +input[type=date].invalid_value, +.invalid_value { + background: #FFCCCC; +} /** * Ajax notification styling @@ -1519,7 +1469,7 @@ display: block; left: 0; right: 0; - background-image: url(getImgPath(); ?>ajax_clock_small.gif); + background-image: url(getImgPath('ajax_clock_small.gif');?>); background-repeat: no-repeat; background-position: 2%; } @@ -1566,7 +1516,7 @@ } .format_specific_options { - border: 1px solid #999999; + border: 1px solid #999; margin: 7px 0; padding: 3px; } @@ -1578,7 +1528,8 @@ /** * Export styles only */ -select#db_select, select#table_select { +select#db_select, +select#table_select { width: 400px; } @@ -1587,7 +1538,7 @@ } .export_sub_options h4 { - border-bottom: 1px #999999 solid; + border-bottom: 1px #999 solid; } .export_sub_options li.subgroup { @@ -1599,7 +1550,8 @@ margin-bottom: 0; } -#quick_or_custom, #output_quick_export { +#quick_or_custom, +#output_quick_export { display: none; } /** @@ -1619,44 +1571,6 @@ margin: 5px 0 5px 0; } -/** - * GIS data editor styles - */ -a.close_gis_editor { - float: right; -} - -#gis_editor { - display: none; - position: fixed; - _position: absolute; /* hack for IE */ - z-index: 1001; - overflow-y: auto; - overflow-x: hidden; -} - -#gis_data { - min-height: 230px; -} - -#gis_data_textarea { - height: 6em; -} - -#gis_data_editor { - background: #D0DCE0; - padding: 15px; - min-height: 500px; -} - -#gis_data_editor .choice { - display: none; -} - -#gis_data_editor input[type="text"] { - width: 75px; -} - #popup_background { display: none; position: fixed; @@ -1671,102 +1585,31 @@ } /** - * ENUM/SET editor styles + * Create table styles */ -p.enum_notice { - margin: 5px 2px; - font-size: 80%; -} - -fieldset.enum_editor_no_js { - width: 40em; - padding: 1em; -} - -hr.enum_editor_no_js { - background-color: #aaa; -} - -#enum_editor p { - font-style:italic; -} - -#enum_editor .values, #enum_editor .add, .enum_editor_no_js #values { - width: 100%; -} - -#enum_editor .add td { - vertical-align: middle; - width: 50%; - padding: 0 1em; -} - -#enum_editor .values td.drop { - width: 2em; - cursor: pointer; - vertical-align: middle; -} - -#enum_editor .values input { - margin: 0.1em 0; - padding-right: 2.5em; - width: 100%; -} - -#enum_editor .values img { - width: 2em; +#create_table_form table.table-name td { vertical-align: middle; } -#enum_editor input.add_value { - margin: 1em 0; -} - -#enum_editor_output textarea, -.enum_editor_no_js input { - width: 100%; - float: right; - margin: 1em 0 0 0; -} - -#enum_editor_no_js { - width: 100%; -} - -.enum_editor_no_js input.submit { - margin: 1em 0; -} - -/** - * ENUM/SET editor integration for the routines editor - */ -.enum_hint { - position: relative; -} - -.enum_hint a { - position: absolute; - left: 81%; - bottom: 0.35em; -} - /** * Table structure styles */ -.structure_actions_dropdown { - position: absolute; - padding: 3px; - display: none; - z-index: 100; +#fieldsForm ul.table-structure-actions { + margin: 0; + padding: 0; + list-style: none; } - -.structure_actions_dropdown a { - display: block; +#fieldsForm ul.table-structure-actions li { + float: ; + margin-: 0.5em; /* same as padding of "table td" */ +} +#fieldsForm ul.table-structure-actions .submenu li { + padding: 0.3em; + margin: 0.1em; } -td.more_opts { - display: none; - white-space: nowrap; +.margin#change_column_dialog { + margin: 0 .5em; } /** @@ -1783,7 +1626,7 @@ #index_frm .slider { width: 10em; - margin: 0.6em; + margin: .6em; float: ; } @@ -1811,12 +1654,26 @@ width: 100%; } -iframe.IE_hack { - z-index: 1; - position: absolute; - display: none; - border: 0; - filter: alpha(opacity=0); +#move_columns_dialog div { + padding: 1em; +} + +#move_columns_dialog ul { + list-style: none; + margin: 0; + padding: 0; +} + +#move_columns_dialog li { + background: ; + border: 1px solid #aaa; + color: ; + font-weight: bold; + margin: .4em; + padding: .2em; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; } /* config forms */ @@ -1871,7 +1728,7 @@ .config-form fieldset .errors { /* form error list */ margin: 0 -2px 1em -2px; - padding: 0.5em 1.5em; + padding: .5em 1.5em; background: #FBEAD9; border: 0 #C83838 solid; border-width: 1px 0; @@ -1881,7 +1738,7 @@ } .config-form fieldset .inline_errors { /* field error list */ - margin: 0.3em 0.3em 0.3em 0; + margin: .3em .3em .3em 0; padding: 0; list-style: none; color: #9A0000; @@ -1889,14 +1746,15 @@ } .config-form fieldset th { - padding: 0.3em 0.3em 0.3em 0.5em; + padding: .3em .3em .3em .5em; text-align: left; vertical-align: top; width: 40%; background: transparent; } -.config-form fieldset .doc, .config-form fieldset .disabled-notice { +.config-form fieldset .doc, +.config-form fieldset .disabled-notice { margin-left: 1em; } @@ -1908,8 +1766,8 @@ } .config-form fieldset td { - padding-top: 0.3em; - padding-bottom: 0.3em; + padding-top: .3em; + padding-bottom: .3em; vertical-align: top; } @@ -1921,7 +1779,8 @@ color: #444; } -.config-form fieldset th, .config-form fieldset td { +.config-form fieldset th, +.config-form fieldset td { border-top: 1px solid; } @@ -1930,14 +1789,16 @@ } fieldset .group-header + tr th { - padding-top: 0.6em; + padding-top: .6em; } -fieldset .group-field-1 th, fieldset .group-header-2 th { +fieldset .group-field-1 th, +fieldset .group-header-2 th { padding-left: 1.5em; } -fieldset .group-field-2 th, fieldset .group-header-3 th { +fieldset .group-field-2 th, +fieldset .group-header-3 th { padding-left: 3em; } @@ -1957,8 +1818,8 @@ } .config-form .lastrow { - background: ;; - padding: 0.5em; + background: ; + padding: .5em; text-align: center; } @@ -1988,6 +1849,8 @@ } .config-form input[type="text"], +.config-form input[type="password"], +.config-form input[type="number"], .config-form select, .config-form textarea { border: 1px #A7A6AA solid; @@ -1995,6 +1858,8 @@ } .config-form input[type="text"]:focus, +.config-form input[type="password"]:focus, +.config-form input[type="number"]:focus, .config-form select:focus, .config-form textarea:focus { border: 1px #6676FF solid; @@ -2016,7 +1881,7 @@ /* error list */ .config-form dd { - margin-left: 0.5em; + margin-left: .5em; } .config-form dd:before { @@ -2032,32 +1897,7 @@ } #prefs_autoload { - margin-bottom: 0.5em; -} - -.rte_table { - table-layout: fixed; -} - -.rte_table td { - vertical-align: middle; -} - -.rte_table tr td:nth-child(1) { - font-weight: bold; -} - -.rte_table input, .rte_table select, .rte_table textarea { - width: 100%; - margin: 0; - box-sizing: border-box; - -ms-box-sizing: border-box; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; -} - -.rte_table .routine_params_table { - width: 100%; + margin-bottom: .5em; } #placeholder .button { @@ -2079,13 +1919,13 @@ .toggleButton { position: relative; cursor: pointer; - font-size: 0.8em; + font-size: .8em; text-align: center; - line-height: 1.55em; + line-height: 1.4em; height: 1.55em; overflow: hidden; - border-right: 0.1em solid #888; - border-left: 0.1em solid #888; + border-right: .1em solid #888; + border-left: .1em solid #888; } .toggleButton table, .toggleButton td, @@ -2097,7 +1937,7 @@ position: absolute; } .toggleButton .toggleOn { - color: white; + color: #fff; padding: 0 1em; } .toggleButton .toggleOff { @@ -2122,7 +1962,11 @@ padding: 0.5em; } -#table_columns input[type="text"], #table_columns select { +#table_columns input[type="text"], +#table_columns input[type="password"], +#table_columns input[type="number"], +#table_columns input[type="date"], +#table_columns select { width: 10em; box-sizing: border-box; -ms-box-sizing: border-box; @@ -2146,144 +1990,40 @@ } #left_arrow { - left:8px; - top:26px; + left: 8px; + top: 26px; } #right_arrow { - left:26px; - top:26px; + left: 26px; + top: 26px; } #up_arrow { - left:17px; - top:8px; + left: 17px; + top: 8px; } #down_arrow { - left:17px; - top:44px; + left: 17px; + top: 44px; } #zoom_in { - left:17px; - top:67px; + left: 17px; + top: 67px; } #zoom_world { - left:17px; - top:85px; + left: 17px; + top: 85px; } #zoom_out { - left:17px; - top:103px; -} - -.gis_table td { - vertical-align: middle; -} - -.gis_table select { - min-width: 151px; -} - -.gis_table .save { - font-weight: bold; - vertical-align: bottom; - height: 100px; -} - -.gis_table .button { - text-align: ; -} - -.gis_table .choice { - display:none; -} - -.CodeMirror { - font-size: 100%; - font-family: monospace; - background: white; - border: 1px solid black; -} - -.CodeMirror-scroll { - overflow: auto; - height: em; - /* This is needed to prevent an IE[67] bug where the scrolled content - is visible outside of the scrolling box. */ - position: relative; -} - -.CodeMirror-gutter { - position: absolute; left: 0; top: 0; - z-index: 10; - background-color: #f7f7f7; - border-right: 1px solid #eee; - min-width: 2em; - height: 100%; -} -.CodeMirror-gutter-text { - color: #aaa; - text-align: right; - padding: .4em .2em .4em .4em; - white-space: pre !important; -} -.CodeMirror-lines { - padding: .4em; -} - -.CodeMirror pre { - -moz-border-radius: 0; - -webkit-border-radius: 0; - -o-border-radius: 0; - border-radius: 0; - border-width: 0; margin: 0; padding: 0; background: transparent; - font-family: inherit; - font-size: inherit; - padding: 0; margin: 0; - white-space: pre; - word-wrap: normal; -} - -.CodeMirror-wrap pre { - word-wrap: break-word; - white-space: pre-wrap; -} -.CodeMirror-wrap .CodeMirror-scroll { - overflow-x: hidden; -} - -.CodeMirror textarea { - font-family: inherit !important; - font-size: inherit !important; -} - -.CodeMirror-cursor { - z-index: 10; - position: absolute; - visibility: hidden; - border-left: 1px solid black !important; -} -.CodeMirror-focused .CodeMirror-cursor { - visibility: visible; -} - -span.CodeMirror-selected { - background: #ccc !important; - color: HighlightText !important; -} -.CodeMirror-focused span.CodeMirror-selected { - background: Highlight !important; + left: 17px; + top: 103px; } -.CodeMirror-matchingbracket {color: #0f0 !important;} -.CodeMirror-nonmatchingbracket {color: #f22 !important;} - -getCssCodeMirror(); ?> - .colborder { cursor: col-resize; height: 100%; @@ -2300,13 +2040,21 @@ position: static; } -.pma_table th.draggable span, .pma_table tbody td span { +.pma_table th.draggable span, +.pma_table tbody td span { display: block; overflow: hidden; } -.cRsz { - position: absolute; +.modal-copy input { + display: block; + width: 100%; + margin-top: 1.5em; + padding: .3em 0; +} + +.cRsz { + position: absolute; } .draggable { @@ -2323,7 +2071,7 @@ } .cPointer { - background: url(getImgPath(); ?>col_pointer.png); + background: url(getImgPath('col_pointer.png');?>); height: 20px; margin-left: -5px; /* must be minus half of its width */ margin-top: -10px; @@ -2331,27 +2079,24 @@ width: 10px; } -.normalqTip { +.tooltip { background: #333 !important; - opacity: 0.8 !important; - border:1px solid #000 !important; - -moz-border-radius: 0.3em !important; - -webkit-border-radius: 0.3em !important; - border-radius: 0.3em !important; + opacity: .8 !important; + border: 1px solid #000 !important; + -moz-border-radius: .3em !important; + -webkit-border-radius: .3em !important; + border-radius: .3em !important; text-shadow: -1px -1px #000 !important; - font-size: 0.8em !important; + font-size: .8em !important; font-weight: bold !important; + padding: 1px 3px !important; } -.normalqTip * { +.tooltip * { background: none !important; color: #FFF !important; } -.normalqTipContent { - padding: 1px 3px !important; -} - .data_full_width { width: 100%; @@ -2364,7 +2109,7 @@ } .coldrop { - background: url(getImgPath(); ?>col_drop.png); + background: url(getImgPath('col_drop.png');?>); cursor: pointer; height: 16px; margin-left: 0.5em; @@ -2373,7 +2118,8 @@ width: 16px; } -.coldrop:hover, .coldrop-hover { +.coldrop:hover, +.coldrop-hover { background-color: #999; } @@ -2384,7 +2130,7 @@ } .cList .lDiv div { - padding: 0.2em 0.5em 0.2em 0.2em; + padding: .2em .5em .2em .2em; } .cList .lDiv div:hover { @@ -2400,9 +2146,9 @@ border-bottom: solid 1px #999; border-top: solid 1px #999; cursor: pointer; - font-size: 0.9em; + font-size: .9em; font-weight: bold; - padding: 0.35em 1em; + padding: .35em 1em; text-align: center; } @@ -2447,7 +2193,7 @@ } .navigation select { - margin: 0 0.8em; + margin: 0 .8em; } .cEdit { @@ -2456,7 +2202,9 @@ position: absolute; } -.cEdit input[type=text] { +.cEdit input[type=text], +.cEdit input[type=password], +.cEdit input[type=number] { background: #FFF; height: 100%; margin: 0; @@ -2467,17 +2215,18 @@ background: #FFF; border: 1px solid #999; min-width: 10em; - padding: 0.3em 0.5em; + padding: .3em .5em; } -.cEdit .edit_area select, .cEdit .edit_area textarea { +.cEdit .edit_area select, +.cEdit .edit_area textarea { width: 97%; } .cEdit .cell_edit_hint { color: #555; - font-size: 0.8em; - margin: 0.3em 0.2em; + font-size: .8em; + margin: .3em .2em; } .cEdit .edit_box { @@ -2486,23 +2235,28 @@ } .cEdit .edit_box_posting { - background: #FFF url(getImgPath(); ?>ajax_clock_small.gif) no-repeat right center; + background: #FFF url(getImgPath('ajax_clock_small.gif');?>) no-repeat right center; padding-right: 1.5em; } .cEdit .edit_area_loading { - background: #FFF url(getImgPath(); ?>ajax_clock_small.gif) no-repeat center; + background: #FFF url(getImgPath('ajax_clock_small.gif');?>) no-repeat center; height: 10em; } +.cEdit .edit_area_right { + position: absolute; + right: 0; +} + .cEdit .goto_link { background: #EEE; color: #555; - padding: 0.2em 0.3em; + padding: .2em .3em; } .saving_edited_data { - background: url(getImgPath(); ?>ajax_clock_small.gif) no-repeat left; + background: url(getImgPath('ajax_clock_small.gif');?>) no-repeat left; padding-left: 20px; } @@ -2513,523 +2267,8 @@ .ui-timepicker-div dl dd { margin: -25px 0 10px 65px; } .ui-timepicker-div td { font-size: 90%; } -/* Designer */ -.input_tab { - background-color: #A6C7E1; - color: #000000; -} - -#canvas { - background-color: #FFFFFF; - color: #000000; -} - -canvas.pmd { - display: inline-block; - overflow: hidden; - text-align: left; -} - -canvas.pmd * { - behavior: url(#default#VML); -} - -.pmd_tab { - background-color: #FFFFFF; - color: #000000; - border-collapse: collapse; - border: 1px solid #AAAAAA; - z-index: 1; - -moz-user-select: none; -} - -.tab_zag { - background-image: url(getImgPath(); ?>pmd/Header.png); - background-repeat: repeat-x; - text-align: center; - cursor: move; - padding: 1px; - font-weight: bold; -} - -.tab_zag_2 { - background-image: url(getImgPath(); ?>pmd/Header_Linked.png); - background-repeat: repeat-x; - text-align: center; - cursor: move; - padding: 1px; - font-weight: bold; -} - -.tab_field { - background: #FFFFFF; - color: #000000; - cursor: default; -} - -.tab_field_2 { - background-color: #CCFFCC; - color: #000000; - background-repeat: repeat-x; - cursor: default; -} - -.tab_field_3 { - background-color: #FFE6E6; /*#DDEEFF*/ - color: #000000; - cursor: default; -} - -#pmd_hint { - white-space: nowrap; - position: absolute; - background-color: #99FF99; - color: #000000; - left: 200px; - top: 50px; - z-index: 3; - border: #00CC66 solid 1px; - display: none; -} - -.scroll_tab { - overflow: auto; - width: 100%; - height: 500px; -} - -.pmd_Tabs { - cursor: default; - color: #0055bb; - white-space: nowrap; - text-decoration: none; - text-indent: 3px; - font-weight: bold; - margin-left: 2px; - text-align: left; - background-color: #FFFFFF; - background-image: url(getImgPath(); ?>pmd/left_panel_butt.png); - border: #CCCCCC solid 1px; -} - -.pmd_Tabs2 { - cursor: default; - color: #0055bb; - background: #FFEE99; - text-indent: 3px; - font-weight: bold; - white-space: nowrap; - text-decoration: none; - border: #9999FF solid 1px; - text-align: left; -} - -.owner { - font-weight: normal; - color: #888888; -} - -.option_tab { - padding-left: 2px; - padding-right: 2px; - width: 5px; -} - -.select_all { - vertical-align: top; - padding-left: 2px; - padding-right: 2px; - cursor: default; - width: 1px; - color: #000000; - background-image: url(getImgPath(); ?>pmd/Header.png); - background-repeat: repeat-x; -} - -.small_tab { - vertical-align: top; - background-color: #0064ea; - color: #FFFFFF; - background-image: url(getImgPath(); ?>pmd/small_tab.png); - cursor: default; - text-align: center; - font-weight: bold; - padding-left: 2px; - padding-right: 2px; - width: 1px; - text-decoration: none; -} - -.small_tab2 { - vertical-align: top; - color: #FFFFFF; - background-color: #FF9966; - cursor: default; - padding-left: 2px; - padding-right: 2px; - text-align: center; - font-weight: bold; - width: 1px; - text-decoration: none; -} - -.small_tab_pref { - background-image: url(getImgPath(); ?>pmd/Header.png); - background-repeat: repeat-x; - text-align: center; - width: 1px; -} - -.small_tab_pref2 { - vertical-align: top; - color: #FFFFFF; - background-color: #FF9966; - cursor: default; - text-align: center; - font-weight: bold; - width: 1px; - text-decoration: none; -} - -.butt { - border: #4477aa solid 1px; - font-weight: bold; - height: 19px; - width: 70px; - background-color: #FFFFFF; - color: #000000; - vertical-align: baseline; -} - -.L_butt2_1 { - padding: 1px; - text-decoration: none; - background-color: #ffffff; - color: #000000; - vertical-align: middle; - cursor: default; -} - -.L_butt2_2 { - padding: 0; - border: #0099CC solid 1px; - background: #FFEE99; - text-decoration: none; - color: #000000; - cursor: default; -} - -/* ---------------------------------------------------------------------------*/ -.bor { - width: 10px; - height: 10px; -} - -.frams1 { - background: url(getImgPath(); ?>pmd/1.png) no-repeat right bottom; -} - -.frams2 { - background: url(getImgPath(); ?>pmd/2.png) no-repeat left bottom; -} - -.frams3 { - background: url(getImgPath(); ?>pmd/3.png) no-repeat left top; -} - -.frams4 { - background: url(getImgPath(); ?>pmd/4.png) no-repeat right top; -} - -.frams5 { - background: url(getImgPath(); ?>pmd/5.png) repeat-x center bottom; -} - -.frams6 { - background: url(getImgPath(); ?>pmd/6.png) repeat-y left; -} - -.frams7 { - background: url(getImgPath(); ?>pmd/7.png) repeat-x top; -} - -.frams8 { - background: url(getImgPath(); ?>pmd/8.png) repeat-y right; -} - -#osn_tab { - background-color: #FFFFFF; - color: #000000; - border: #A9A9A9 solid 1px; -} - -.pmd_header { - background-color: #EAEEF0; - color: #000000; - text-align: center; - font-weight: bold; - margin: 0; - padding: 0; - background-image: url(getImgPath(); ?>pmd/top_panel.png); - background-position: top; - background-repeat: repeat-x; - border-right: #999999 solid 1px; - border-left: #999999 solid 1px; - height: 28px; -} - -.pmd_header a { - display: block; - float: left; - margin: 3px 1px 4px 1px; - height: 20px; - border: 1px dotted #ffffff; -} - -.pmd_header .M_bord { - display: block; - float: left; - margin: 4px; - height: 20px; - width: 2px; -} - -.pmd_header a.first { - margin-right: 1em; -} - -.pmd_header a.last { - margin-left: 1em; -} - -a.M_butt_Selected_down_IE, -a.M_butt_Selected_down { - border: 1px solid #C0C0BB; - background-color: #99FF99; - color: #000000; -} - -a.M_butt_Selected_down_IE:hover, -a.M_butt_Selected_down:hover, -a.M_butt:hover { - border: 1px solid #0099CC; - background-color: #FFEE99; - color: #000000; -} - -#layer_menu { - z-index: 1000; - position: absolute; - left: 0; - background-color: #EAEEF0; - border: #999999 solid 1px; -} - -#layer_action { - position: absolute; - left: 638px; - top: 52px; - z-index: 1000; - background-color: #CCFF99; - padding: 3px; - border: #009933 solid 1px; - white-space: nowrap; - font-weight: bold; -} - -#layer_upd_relation { - position: absolute; - left: 637px; - top: 224px; - z-index: 1000; -} - -#layer_new_relation { - position: absolute; - left: 636px; - top: 85px; - z-index: 1000; - width: 153px; -} - -#pmd_optionse { - position: absolute; - left: 636px; - top: 85px; - z-index: 1000; - width: 153px; -} - -#layer_menu_sizer { - background-image: url(getImgPath(); ?>pmd/resize.png); - cursor: nw-resize; - width: 16px; - height: 16px; -} - -.panel { - position: fixed; - top: 50px; - right: 0; - display: none; - background: #FFF; - border:1px solid #F5F5F5; - width: 350 px; - height: auto; - padding: 30px 170px 30px 30px; - color:#FFF; - z-index:99; -} - -a.trigger{ - position: fixed; - text-decoration: none; - top: 60px; right: 0; - color:#fff; - padding: 10px 40px 10px 15px; - background:#333333 url(getImgPath(); ?>pmd/plus.png) 85% 55% no-repeat; - border:1px solid #444444; - display: block; -} - -a.trigger:hover{ - position: fixed; - text-decoration: none; - top: 60px; right: 0; - color:#080808; - padding: 10px 40px 10px 15px; - background:#fff696 url(getImgPath(); ?>pmd/plus.png) 85% 55% no-repeat; - border:1px solid #999; - display: block; -} - -a.active.trigger { - background:#222222 url(getImgPath(); ?>pmd/minus.png) 85% 55% no-repeat; - z-index:999; -} - -a.active.trigger:hover { - background:#fff696 url(getImgPath(); ?>pmd/minus.png) 85% 55% no-repeat; - z-index:999; -} - -h2.tiger{ - background-repeat: repeat-x; - padding: 1px; - font-weight: bold; - padding: 50 20 50 20px; - margin: 0 0 5px 0; - width: 250px; - float: left; - color : #333; - text-align: center; -} - -h2.tiger a { - background-image: url(getImgPath(); ?>pmd/Header.png); - text-align: center; - text-decoration: none; - color : #333; - display: block; -} - -h2.tiger a:hover { - color: #000; - background-image: url(getImgPath(); ?>pmd/Header_Linked.png); -} - -h2.active { - background-image: url(getImgPath(); ?>pmd/Header.png); - background-repeat: repeat-x; - padding: 1px; - background-position: left bottom; -} - -.toggle_container { - margin: 0 0 5px; - padding: 0; - border-top: 1px solid #d6d6d6; - background: #FFF ; - width: 250px; - overflow: hidden; - font-size: 1.2em; - clear: both; -} - -.toggle_container .block { - background-color: #DBE4E8; - padding:40 15 40 15px; /*--Padding of Container--*/ - border:1px solid #999; - color:#000; -} - -.history_table { - text-align: center; - background-color: #9999CC; -} - -.history_table2 { - text-align: center; - background-color: #DBE4E8; -} - -#filter { - display: none; - position: absolute; - top: 0%; - left: 0%; - width: 100%; - height: 100%; - background-color: #CCA; - z-index:10; - opacity:0.5; - filter: alpha(opacity=50); -} - -#box { - display: none; - position: absolute; - top: 20%; - left: 30%; - width: 500px; - height: 220px; - padding: 48px; - margin:0; - border: 1px solid black; - background-color: white; - z-index:101; - overflow: visible; -} - -#boxtitle { - position:absolute; - float:center; - top:0; - left:0; - width:593px; - height:20px; - padding:0; - padding-top:4px; - left-padding:8px; - margin:0; - border-bottom:4px solid #3CF; - background-color: #D0DCE0; - color:black; - font-weight:bold; - padding-left: 2px; - text-align:left; -} - -#tblfooter { - background-color: #D3DCE3; - float: right; - padding-top:10px; - color: black; - font-weight: normal; -} - input.btn { - color:#333; + color: #333; background-color: #D0DCE0; } @@ -3107,12 +2346,12 @@ } .jqplot-yaxis-tick.jqplot-breakTick { - right: -20px; - margin-right: 0px; - padding:1px 5px 1px 5px; -/* background-color: white;*/ - z-index: 2; - font-size: 1.5em; + right: -20px; + margin-right: 0px; + padding:1px 5px 1px 5px; +/* background-color: white;*/ + z-index: 2; + font-size: 1.5em; } .jqplot-y2axis-tick, .jqplot-y3axis-tick, .jqplot-y4axis-tick, .jqplot-y5axis-tick, .jqplot-y6axis-tick, .jqplot-y7axis-tick, .jqplot-y8axis-tick, .jqplot-y9axis-tick { @@ -3263,7 +2502,7 @@ font-size: 0.75em; z-index: 2; } - + td.jqplot-cursor-legend-swatch { vertical-align: middle; text-align: center; @@ -3299,6 +2538,25 @@ } div.jqplot-noData-container { - text-align: center; - background-color: rgba(96%, 96%, 96%, 0.3); + text-align: center; + background-color: rgba(96%, 96%, 96%, 0.3); +} + +#relationalTable select { + width: 125px; + margin-right: 5px; +} + +.report-data { + height:13em; + overflow:scroll; + width:570px; + border: solid 1px; + background: white; + padding: 2px; +} + +.report-description { + height:10em; + width:570px; } diff --git a/phpMyAdmin/themes/original/css/navigation.css.php b/phpMyAdmin/themes/original/css/navigation.css.php new file mode 100644 index 0000000..02147bc --- /dev/null +++ b/phpMyAdmin/themes/original/css/navigation.css.php @@ -0,0 +1,296 @@ + + +/******************************************************************************/ +/* Navigation */ + +#pma_navigation { + background: ; + color: ; + width: px; + overflow: hidden; + position: fixed; + top: 0; + : 0; + height: 100%; + border-: 1px solid gray; + z-index: 800; +} + +#pma_navigation_content { + width: 100%; + height: 100%; + position: absolute; + top: 0; + : 0; + z-index: 0; + padding-bottom: 1em; +} + +#pma_navigation ul { + margin: 0; +} + +#pma_navigation form { + margin: 0; + padding: 0; + display: inline; +} + +#pma_navigation select#select_server, +#pma_navigation select#lightm_db { + width: 100%; +} + +/******************************************************************************/ +/* specific elements */ + +#pma_navigation div.pageselector { + text-align: center; + margin: 0 0 0; + margin-: 0.75em; + border-: 1px solid #666; +} + +#pma_navigation div#pmalogo { + + background-color: ; + padding: .3em; +} + +#pma_navigation div#recentTableList { + text-align: center; + margin-bottom: 0.5em; +} + +#pma_navigation #pmalogo, +#pma_navigation #serverChoice, +#pma_navigation #leftframelinks, +#pma_navigation #recentTableList, +#pma_navigation #databaseList, +#pma_navigation div.pageselector.dbselector { + text-align: center; + margin-bottom: 0.3em; + padding-bottom: 0.3em; + border: 0; +} + +#pma_navigation #recentTableList select, +#pma_navigation #serverChoice select + { + width: 80%; +} + +#pma_navigation #recentTableList { + margin-bottom: 0; + padding-bottom: 0; +} + +#pma_navigation_content > img.throbber { + display: block; + margin: 0 auto; +} + +/* Navigation tree*/ +#pma_navigation_tree { + margin: 0; + margin-: 1em; + color: #444; + height: 74%; + position: relative; +} +#pma_navigation_tree_content { + width: 100%; + overflow: hidden; + overflow-y: auto; + position: absolute; + height: 100%; +} +#pma_navigation_tree a { + color: ; +} +#pma_navigation_tree a:hover { + text-decoration: underline; +} +#pma_navigation_tree li.activePointer { + color: ; + background-color: ; +} +#pma_navigation_tree li.selected { + color: ; + background-color: ; +} +#pma_navigation_tree li .dbItemControls { + padding-left: 4px; +} +#pma_navigation_tree li .navItemControls { + display: none; + padding-left: 4px; +} +#pma_navigation_tree li.activePointer .navItemControls { + display: inline; + opacity: 0.5; +} +#pma_navigation_tree li.activePointer .navItemControls:hover { + display: inline; + opacity: 1.0; +} +#pma_navigation_tree ul { + clear: both; + padding: 0; + list-style-type: none; + margin: 0; +} +#pma_navigation_tree ul ul { + position: relative; +} +#pma_navigation_tree li { + white-space: nowrap; + clear: both; + min-height: 16px; +} +#pma_navigation_tree img { + margin: 0; +} +#pma_navigation_tree div.block { + position: relative; + width:1.5em; + height:1.5em; + min-width: 16px; + min-height: 16px; + float: ; +} +#pma_navigation_tree div.block i, +#pma_navigation_tree div.block b { + width: 1.5em; + height: 1.5em; + min-width: 16px; + min-height: 8px; + position: absolute; + bottom: 0.7em; + : 0.75em; + z-index: 0; +} +#pma_navigation_tree div.block i { + border-: 1px solid #666; + border-bottom: 1px solid #666; +} +#pma_navigation_tree div.block i.first { /* Removes top segment */ + border-: 0; +} +/* Bottom segment for the tree element connections */ +#pma_navigation_tree div.block b { + display: block; + height: 0.75em; + bottom: 0; + : 0.75em; + border-: 1px solid #666; +} +#pma_navigation_tree div.block a, +#pma_navigation_tree div.block u { + position: absolute; + : 50%; + top: 50%; + z-index: 10; +} +#pma_navigation_tree div.block img { + position: relative; + top: -0.6em; + : 0; + margin-: -5px; +} +#pma_navigation_tree li.last > ul { + background: none; +} +#pma_navigation_tree li > a, #pma_navigation_tree li > i { + line-height: 1.5em; + height: 1.5em; + padding-: 0.3em; +} +#pma_navigation_tree .list_container { + border-: 1px solid #666; + margin-: 0.75em; + padding-: 0.75em; +} +#pma_navigation_tree .last > .list_container { + border-: 0 solid #666; +} + +/* Fast filter */ +li.fast_filter { + padding-: 0.75em; + margin-: 0.75em; + padding-: 35px; + border-: 1px solid #666; +} +li.fast_filter input { + padding-: 1.7em; + width: 100%; +} +li.fast_filter span { + position: relative; + : 1.5em; + padding: 0.2em; + cursor: pointer; + font-weight: bold; + color: #800; +} +/* IE10+ has its own reset X */ +html.ie li.fast_filter span { + display: none; +} +html.ie.ie9 li.fast_filter span, +html.ie.ie8 li.fast_filter span { + display: auto; +} +html.ie li.fast_filter input { + padding-: .2em; +} +html.ie.ie9 li.fast_filter input, +html.ie.ie8 li.fast_filter input { + padding-: 1.7em; +} +li.fast_filter.db_fast_filter { + border: 0; +} + +/* Resize handler */ +#pma_navigation_resizer { + width: 3px; + height: 100%; + background-color: #aaa; + cursor: col-resize; + position: fixed; + top: 0; + : 240px; + z-index: 801; +} +#pma_navigation_collapser { + width: 20px; + height: 22px; + line-height: 22px; + background: #eee; + color: #555; + font-weight: bold; + position: fixed; + top: 0; + : px; + text-align: center; + cursor: pointer; + z-index: 800; + text-shadow: 0px 1px 0px #fff; + filter: dropshadow(color=#fff, offx=0, offy=1); + border: 1px solid #888; +} diff --git a/phpMyAdmin/themes/original/css/theme_left.css.php b/phpMyAdmin/themes/original/css/theme_left.css.php deleted file mode 100644 index a8f3faf..0000000 --- a/phpMyAdmin/themes/original/css/theme_left.css.php +++ /dev/null @@ -1,254 +0,0 @@ - -/******************************************************************************/ -/* general tags */ -html { - font-size: get('fontsize') ? $GLOBALS['PMA_Config']->get('fontsize') : $_COOKIE['pma_fontsize']); ?>; -} - -input, select, textarea { - font-size: 1em; -} - -body { - - font-family: ; - - background: ; - color: ; - margin: 0; - padding: 0.2em 0.2em 0.2em 0.2em; -} - -a img { - border: 0; -} - -a:link, -a:visited, -a:active { - text-decoration: none; - color: #0000FF; -} - -ul { - margin:0; -} - -form { - margin: 0; - padding: 0; - display: inline; -} - -select#select_server, -select#lightm_db { - width: 100%; -} - -/* buttons in some browsers (eg. Konqueror) are block elements, - this breaks design */ -button { - display: inline; -} - -/******************************************************************************/ -/* classes */ - -/******************************************************************************/ -/* specific elements */ - -div#pmalogo { - - background-color: ; - padding:.3em; -} - -div#recentTableList { - text-align: center; - margin-bottom: 0.5em; -} - -div#recentTableList select { - width: 100%; -} - -div#pmalogo, -div#leftframelinks, -div#databaseList { - text-align: center; - margin-bottom: 0.5em; - padding-bottom: 0.5em; -} - -ul#databaseList { - margin-bottom: 0.5em; - padding-bottom: 0.5em; - padding-: 1.5em; - font-style: italic; -} - -ul#databaseList a { - display: block; - font-style: normal; -} - -div#navidbpageselector a, -ul#databaseList a { - background: ; - color: ; -} - -ul#databaseList ul { - padding-left: 1em; - padding-right: 0; -} - -ul#databaseList a:hover { - background: ; - color: ; -} - -ul#databaseList li.selected a { - background: ; - color: ; -} - -div#leftframelinks .icon { - padding: 0; - margin: 0; -} - -div#leftframelinks a img.icon { - margin: 2px; - border: 0.1em solid ; - padding: 0; -} - -div#leftframelinks a:hover img { - background-color: ; - color: ; -} - -/* serverlist */ -#body_leftFrame #list_server { - list-style-image: url(/original/img/s_host.png); - list-style-position: inside; - list-style-type: none; - margin: 0; - padding: 0; -} - -#body_leftFrame #list_server li { - margin: 0; - padding: 0; - font-size: 80%; -} - -div#left_tableList ul { - list-style-type: none; - list-style-position: outside; - margin: 0; - padding: 0; - font-size: 80%; - background: ; -} - -div#left_tableList ul ul { - font-size: 100%; -} - -div#left_tableList a { - background: ; - color: ; - text-decoration: none; -} - -div#left_tableList a:hover { - background: ; - color: ; - text-decoration: underline; -} - -div#left_tableList li { - margin: 0; - padding: 0; - white-space: nowrap; -} - - -/* marked items */ -div#left_tableList > ul li.marked > a, -div#left_tableList > ul li.marked { - background: ; - color: ; -} - - - -div#left_tableList > ul li:hover > a, -div#left_tableList > ul li:hover { - background: ; - color: ; -} - - -div#left_tableList img { - padding: 0; - vertical-align: middle; -} - -div#left_tableList ul ul { - margin-: 0; - padding-: 0.1em; - border-: 0.1em solid ; - padding-bottom: 0.1em; - border-bottom: 0.1em solid ; -} - -/* for the servers list in navi panel */ -#serverinfo .item { - white-space: nowrap; - color: ; -} -#serverinfo a:hover { - background: ; - color: ; -} - -#NavFilter { - display: none; -} - -#clear_fast_filter { - background: white; - color: black; - cursor: pointer; - padding: 0; - margin: 3px 5px 0 -23px; - position: relative; - float: right; -} - -#fast_filter { - width: 100%; - padding: 2px 0; - margin: 0; - border: 0; -} - -#fast_filter.gray { - color: gray; -} \ No newline at end of file diff --git a/phpMyAdmin/themes/original/css/theme_print.css.php b/phpMyAdmin/themes/original/css/theme_print.css.php deleted file mode 100644 index 4cf8e33..0000000 --- a/phpMyAdmin/themes/original/css/theme_print.css.php +++ /dev/null @@ -1,42 +0,0 @@ - -/* For printview */ -body, table, th, td { - color: #000000; - background-color: #ffffff; -} - -img { - border: 0; -} - -table, th, td { - border-width: 0.1em; - border-color: #000000; - border-style: solid; -} - -table { - border-collapse: collapse; - border-spacing: 0; -} - -th, td { - padding: 0.2em; -} - -th { - font-weight: bold; - background-color: #e5e5e5; -} - -.hide { - display: none; -} diff --git a/phpMyAdmin/themes/original/img/b_column_add.png b/phpMyAdmin/themes/original/img/b_column_add.png new file mode 100644 index 0000000000000000000000000000000000000000..25dc54637af42c25df91da30b00a9cdf08da81ef GIT binary patch literal 534 zcmV+x0_pvUP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipuD z6Cwb3$1A=LzdN=AuQZW%sK~{lP7Qr$Vz_|KSPFeJ*uYR6D*-IV1);?l zhp`TCqCdPY&S?+2m>pRLVCC615AKcwT&c&tvGVlV(0|MBpZr0X* Y1BxyYzJ?floB#j-07*qoM6N<$f_n4kUjP6A literal 0 HcmV?d00001 diff --git a/phpMyAdmin/themes/original/img/b_find_replace.png b/phpMyAdmin/themes/original/img/b_find_replace.png new file mode 100644 index 0000000000000000000000000000000000000000..8346a0e4439973e1a3e2d0842ec8b6ac2ac379e3 GIT binary patch literal 1209 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJXMsm#F#`j)FbFd;%$g$s6l6(v z^mSxl*w|O|J8&|PuaN8!d{yT5p%ADM}6DA$oy6xlY zHIElBxl&fMW$Bt*CAHgYTGsbWTvge+apIzrGdG-`viteWJ@*&vy!`C-hx`q1r){}7 zXWNqr=I(?@&4~+7hX-ASQ4 z|DXB(^}w06i79r6x3HYqrgUtJ<-!FsyYtuRX^%n-;bFFXbm^(_hV3kIeWssV<}S%M8fgHL(7IEGZ*O8S!Mz{Rd7#LXs3;Wu8AB(v#C^Q^kGPe*dy?N8Gk(GgoL+8VL_Q&zh{vS#J z>R_7vasJo$zyJGN9%KS)3j5gm`my}8_wit!(2oz#zhA#D{_p=SP9dNb3l6xOC4YTx z|KtD0P5aro7+3^^538pwv*i(c7MAn>-#;dh&}J3m(~;>DqFlu|udTns19ab^LnWug v9;rmOm8(liFferp-rdf?*z(Y_0a#od(9kKKv+7O)&{qteu6{1-oD!MU7S{={Y-RUl(F{73;lv z_~3c?7$QP7$yc;|AYwT-1rYD>)?1z&s>J2>i8!N~@u7kh}kW3OrMu!E4VZs1_ zzGhfIcIF3V|1dqQt|6b-NAt4_bou1fgfi0|} z)zzP)Oi7(F@k zfQgE;z`f+gK-YW3r`q6Na%1q-5JIYqU@(Y)-;WiK4>@^7Ca`G#8whJ`nb}eRug?cb zlCb9S!n?7%A#@UzeA2JwYZzN}45F9Vxfzbm4 zz5Q6$@aVoD4!cN1)P-!0ERRe^g1vs7g4~d*FoiYh+Ati4*&wkqTqBk;+LW$3Z&;` z;ms!wVF3KjiBx%GkxxHc3j+O9W&nhOUW7FjiU@5t&^*v~y-L)Z!jXKSYzH_+RUPF| aDD(%1fh}_Q#_Q4m0000Px$XGugsR5;6}lfO$sQ5?lTR}30z35pcAP-;j^9~e?g(c1su@`j|TrA^%&sv)T8 zuF>AmR6|f91-=5wDWau%67<8Q5JGN4K6}qJ9`%I__wc>ve$P4Zg@2X+&~;t?g)F5M zUJJxxdb42|(t!a?bB}a74M;E~LNfsHxS7<6?8<`Q?{7=ibsZ_Cuz<3c9cMBbrPP*E zg_r^q(0l{nbtEbTN_~sTX0u<@4XruZ-v9AICo+I4#2N`}jtm?YTI4y7Qp#bYtp&RR z>uxF8*^YAl7C~PP@LsD?Dc|8bgSE{dFa1+YM>PU{K@Lm1oL(LiPx+QTofH7g3<|Fy z#)c!*J#`|!S?c10iO~c=%G0XAQH{W!t0rBdhq;jj02XH?Ljz%e?q3yHX+Kpflnp&a@ zWTvI1&767W|Ns9+&%<_u)RhGJ1v5B2yO9RuSb4fQhHzX@PH13MRaNCUeB%a3FXJR3 z2E&+`IT8nX939mi6&gAXnp`Cg@GRg6V4TGf!@Ef@WpW||Ln9N%x47aTKtmW9JYD@< J);T3K0RZ4sFtY#v literal 0 HcmV?d00001 diff --git a/phpMyAdmin/themes/original/img/b_table_add.png b/phpMyAdmin/themes/original/img/b_table_add.png new file mode 100644 index 0000000000000000000000000000000000000000..e3ee20825007bd31648081fdb64b08b778a1f55b GIT binary patch literal 368 zcmV-$0gwKPP)Px$DoI2^R5;7ElRryBQ5c7x_i_V=YK)vBq^Kb+E@D^`6hV`7OM}Z9yfn4+4RWZl zpu6`aswqNpxCKH}Nf40{l*tVWL{5|8wX0o{p6%g1e}3mZ=RltbfKp2TWwPTqVz$Jx z)OW#k9iIo`x()zFzeg}TSM26JQA+7{Iz5P1-%MXeMbKLNJc#x&X179+_w2#HCpbDi zs^fGxyI=;xn=o~jsR}{WTr O0000E}aDc literal 0 HcmV?d00001 diff --git a/phpMyAdmin/themes/original/img/b_undo.png b/phpMyAdmin/themes/original/img/b_undo.png new file mode 100644 index 0000000000000000000000000000000000000000..498187821cfd60ca010afe1b08cf6b07f38f8de6 GIT binary patch literal 1306 zcmV+#1?BpQP)R-7j2z+(P=LJMG4+z8597cBYUOn~u=sd&am1J`vUp9({?Ti@9UEinq2|DNT zUmciAl75N}jhwxKf4)cNAknUf_h(Q(k9Ypey1((!5UO6J-;e3Jf?ST&A1J*Y zX^J^wo)GM@M;rx%hLM>LttS(4)ny`N+TV`q`v%ysv0>H(@g;`nsp zR#MyXBtt5w?ZvLgf}_FyAShkU<`FFU3k#P8ZdDV@KVe=?D1GJ@Ql%_ur_+Wl_oa;{fTyv z?B%ZONyf12X`(e;eLatN&{j_AaBgf00uHv))y?SXn8WLz5^rL18C~gc#9`A2=9kd= zE3#z_I4|&}<7j>kAC3=1TYseJEZkt9eKWXveJAl0Qfo1s#hXGte>L%yG&K-+_jxHv z$c^Tefvo=_566Lf{MiuKT*S&@VVpV`^%?MRd5C9z5Y#6VkP!V9BRTR5yh>#UZe?yI zwh^~rA`|y8Wk2m3czzlky_9{x`BT~ZGb+}x@N%xLV^ufR7m!@|1-ElP|KG7C8_f0o zQry|s>AOp*`k1#`c;gf+7IE}xezTYr$dBRLdqaKZp}u*q&n7y-?$vnh%LME!#3rJb z$u}18Dz0iK-@!AN&{)qcC)ktWyj^UY`ngk4$=y{%BUy8b_*j9T^dCX#{}oVGRoG~A zfk=_e>NAyryz>^PhtM*d#U0@d*wBRu%#BEWo74!BmwDkPx%kV!;AR5;6hlS@dHQ5c4wnZ~>hUcyOp$R-=gD9uE?Bp6B3CR+qTH^?9)R0v!Z z1c4hDwFxVTAR?(nK{qNW#7Z$G%L|SdbPz=wb?`DX{xkpYe>p9zK^gIdvp6rD=bZ07 z-)G{VZoKq}70*0d$v-;C)B6`p>pjc*P2-h=2mm403}L{ULx0~SPe!4x@tbJARThSr z*8>vcEhNQTNJ@xWTh?fjtT7~6V~C1cyKDJqAs279i3ot^4{Z8uO@J&wS~UPr=H_sv z?&oy<2N6-idbNHXqN{t1akqy|M;f~w834rn>L3S*)5OLMWGS@a@bJhC$4}&NzPf^; z;c5DM-Pj#giccJ3Vtj<5*2TyS{;R8djJ*7PIGlD=lbJnbP8`{LQ39*zaW;~j1w>?^ zE_(sc1&q5r*fZ0RRGpw=uoFnJ+nAs6BFP$>C7w-x0U)RdGBeW{9G*r}AgDtuFzKEp zIXx9wGYF}AWFKq`c+r6sMI&~*L0_*M->N}!hK-i@ll=Jom>s(o==%N)e@KSttjI=M z(IEX}G0sIRZ) zxR!Qvso^T6RTZ47JBKxOi6aMc(ak!!=_k=mDn*A&0BXa4mePBS^iT0huA-!&nUE@w zRUKJ1SPFQEG9^%%T@OG*`6IGyIRG(cfKRu}MSITzuaz^DUT;EDK~fDQRUm1C#efgj zpH7;-R0GiTxf=KU0Dv4GipytDiJAu=S@Z>wR6$S`1XUeLg^+5{|MM6nIi)z$@)(=# zrE{Qz=?UN6FyLBEi`Z(EXUre)ntouI6wD%;R8h>khc8Tj0Zt?xfkNG(ssI2007*qo IM6N<$f>s|t-2eap literal 0 HcmV?d00001 diff --git a/phpMyAdmin/themes/original/img/docs_menu_bg.png b/phpMyAdmin/themes/original/img/docs_menu_bg.png deleted file mode 100644 index 89e18332a1e62f08bc1bd50fc5c76e140cebc45b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 76 zcmeAS@N?(olHy`uVBq!ia0vp^Od!m`1|*BN@u~nRVNVyw5RU7~30*7ypJ!n9G5q?U ZQLcb_=lt)_mjk64JYD@<);T3K0RT;j6ZQZA diff --git a/phpMyAdmin/themes/original/img/item_ltr.png b/phpMyAdmin/themes/original/img/item_ltr.png deleted file mode 100644 index 2a4cb8b3efc7a84d2d689294d1375d98e48de65c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 112 zcmeAS@N?(olHy`uVBq!ia0vp^tU%1k!2%=$mgtEBDVB6cUq=Rp^(V|(yIunM>Ygr+ zAsp9}QxbmspWg@u6B`+iCAM@NNHMVVSmcov=-ZIVz`%Bi|9eX7lYXEU22WQ%mvv4F FO#ss#Ae;aI diff --git a/phpMyAdmin/themes/original/img/item_rtl.png b/phpMyAdmin/themes/original/img/item_rtl.png deleted file mode 100644 index a18e30b07b692c4f34c5f4e9c04bcbecedce2a02..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 112 zcmeAS@N?(olHy`uVBq!ia0vp^tU%1k!2%=$mgtEBDVB6cUq=Rp^(V|(yIunM>Ygr+ zAsp93yA1gl30XYhLR!1P*SpVQi>)dUV<_*6qInHGcnEb zQfX6|c{lO4l#RKaZC-XZ&u-_k%Q@eEE?Qa!_Tt0u@H@}<^E~``A^=3}gr(l4vU*i7 zyV6Lx=4yE7RGGkx6gV71cjvY=iqb#p!ylZn>j-Cf+b>x95wMRT==lzjH$f681f9ze zR{P)>$i_z3RfAovII&B>n%*Ds>XegyS_9EX5sW0f1d*FX&^tjGBX?Rzej4t{=ddW_ z9h>UH!(o9}TURNVdq{y5qM#$E1yaxnNWKtKkRh^p1YA9U=z#4*HY{(h_k{(nnF>pQ znJ2Y6(rFb^z)nJ2pnqIQ&_2v{yl+xxUhm5uO{Q#!J8DY)klFd_YP)!y2hX0`01t+}>V>!L2Ii?(iJ%bC$d(ON6}*wnOwG9V2N zOG`{7!B5mwL_|_S2m}#C`CdG|@7W+M+U(-lIXipb-}9Vv-Vy*Mg_?2)&x|dud>nH6 z+Pg4Y7{H$F@$4DL`b~nbIs5knvB+k zHj8ub763Kx9CrFf76K8`6xv9LChyt?+yu)3H}{cgBtWFDjV( zT46G1p#RVaN{MFkER1%KNN}rd=ywA89=YD?5^*~T(5|_U4sv3(jyQy?qF#!I-YIcK zeuGD!Ck%N2HSJIh+U=tYeo@e&trgAm(x7tzP$_D_zeF>F>u*g-I^VNp4(M<9KQ~%~ z3}FWb=nBN{ra3RFTFeCC z!$l`CCu*vADm$NUP}Jde?Il#nFW_p845!NWW$Et^{&SQIRV}^fRyMzZQmIB=eG~3I zc!HA^Wx-;#MFG+)=LYmWJqQGXuvo_MLh%Zf$0hUI2Iy7tvy~@~#>&eNWlKvX*<(i} i@%N3@m$wc0AN>MB3Mf9{XhoL*0000f4>3F(0hDcmaPFP@;a71 z_Ha!U+43NSBlOCl23CWKZ`^8@O-xbxD$2yLs2I^z*boFyt=akR{0Cf46?nQhhDcmaPFP@;5L5Oi(X>Z6 zRr7wA|HFET=hx56>-O~Y{D1uR>Z=Q)MvBEZZdhhT+`N&U{&vrm!v_u==nq!p*;7&D z-`m)Da8_fZBjb7}(Ol>IuTGxsl9Z4z0b-T{Ef*%QBU&P@Grc?%na{W|*anJU`}|X~ Q6KFSsr>mdKI;Vst0JudzlmGw# diff --git a/phpMyAdmin/themes/original/img/pmd/2leftarrow.png b/phpMyAdmin/themes/original/img/pmd/2leftarrow.png deleted file mode 100644 index c3565bcd5a87cbd89931990f5dbc5f8b92e024b7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 702 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47-Ir_LR^8|R4_2gIAfG~(JXbZ zQRW3811M&mx)aE-OIiwHdn8Vv43)ow$yxDO290_T5gK_AY12gWLuG^QPV@TJpDS>95N9PwN&x z>stS%cg?fjHP8FjzUbTdX~M=glh!|*w(Zk`-EUSL`nvkyt4*iAZ9DU2$C-CK&wMy? z<>T>dpU&R;a_+(Z3lIKXdi3wggDa^eEI&@s}H|kfB5z0 zcbo<4zVGSc7$PCbdho7avw;NLgYS!F zV?7&FZ~B)MEV}n!R`+AVF$=B9^Dj*md-Yj>p<%k_+1L&Sjs}bAO6mORUnCATzWG#i zGk4>kyD5v6oul^dJ#AKe`h(+UPM*-%BgdxUb&lsf}3#Iw1J_!RO$v$nR@QCo%|V h?p%1aMbqsM^WM;$ge7ZpSb$z-@O1TaS?83{1OU16YLWl| diff --git a/phpMyAdmin/themes/original/img/pmd/2leftarrow_m.png b/phpMyAdmin/themes/original/img/pmd/2leftarrow_m.png deleted file mode 100644 index 6ec8d81cb7dc40f3025fe533ba8deff70849fde0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 666 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc3?z4jzqMyzVAKil32_B-vuay`sBZGyhG`2b zd#Be=T>xYNMJjrxK^R4C{XlkJV^?|i)SUYE-1-in;`*ucYbVXE=$&5B+*8&)1t?NC zWgd_$?VJQO1c(}@Ed;5VJhytnEFf9cKNBd@I2|Miv;wHOe#(3xYMimCdFB$Jc-!0+ z5VCW@s;&jA`xdY3Te5D_@{LngZkoDs^VC(Fr?1{JbM3a->$cBXzhmx(o%1&CoWF6` z(rx>eZQs9Q=fQP*k8V70eDlE*TMwVwcI4E~V`q0AKfC+HxxJ?@>_2_+@VP6;E?hfx z<>uMzw=dtmf91}DTMwV!dHn3bvzJd^zIpcg?ejP9UcLM9=EJ9VA3uNi{N>}9ub;kt z`~3CW*Y7{R{rLIg=db_&|G(Jhkq-oU*UMSKx(>%K zze(OYH#+F=+fzXY7|OQSmtQTBc)hphECbt(T(ehkGoJ0c`g6j%Cbq}n$r>GrYhQ@n zYi?UQdEEl*wLGcLX01FqZjRNJn`Ibn8F{0Mb}XGUOMR(>^L#(kY|96>A&)tv*3GqI z`zG^YpSflO xUuNHwJ{D@8zQCywH|5jiPN~BeIzGtT8~rXm%DCy+8KA!zJYD@<);T3K0RVE_XKnxh diff --git a/phpMyAdmin/themes/original/img/pmd/2rightarrow.png b/phpMyAdmin/themes/original/img/pmd/2rightarrow.png deleted file mode 100644 index 0a4e236de26be0e71e0676f01435505136a080f8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 737 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47)t_tLR^8|R4_2gIAfG~(JXbZ zQRW3811M&mx)aE-OIiwHdn8VByCjCvJQ?ee?6V2mdbs(Zm0j9{#)Z=--VezivJIb?4c) zC$E1zdHwU*+n>+h{(SlV*PD;O-hKZ4>Fe(=-~asl_3!`x{~eY4a)IG)R1)L|j0ZLj z4lW)ZK0ygdNjU{&V{2Pmdk3$m#KfeOx`vLPzL_(Z-?(w-?&HU=-+cJ+`SX`AdgdKx zfx2ILx;TbNNU|Qh?RD5eg!Mvgn%^b0XF*%GxMp*EIm)m3_1|8xa;k$MYpDE9!r$Lo7cP3{~ap&_fsV3vPVw& zce~1^ryVy*w8fm7-TWf9NZ6h2=Fy#k3y&v%=Z*XO<;K5_%7=S%d)6^$9(|MJ*DK&v z8Y{-|{;{f&QkXN>o?jgWM}GSHE9JM=a0))`PSdry6!b^c^MTx$#gG^GC%e}e$%t8B~^x};(@+q N@O1TaS?83{1OOL=eE$Fd diff --git a/phpMyAdmin/themes/original/img/pmd/2rightarrow_m.png b/phpMyAdmin/themes/original/img/pmd/2rightarrow_m.png deleted file mode 100644 index e5ff1f0b4d3a9496459154015c11799730c72661..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 699 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc3?z4jzqMyzU~~!a32_B-vuay`sBZGyhG`2b zd#Be=T>xYNMJjrxK^R4C{XlkJV^?|i)SUYE-1-in;`*ucYbVXE=$&5B+*8&)1t?NC zWgd_$?VJQO1c(}@Ed;5VJhytnEFf9cKNBd@I2|Miv;wHOe#(3xYMimCdFB$Jc-!0+ z5VCW@s;&jA`xdY3Te5D_@{LngZkoDs^VC(Fr?1{JbM3a->$cBXzhmx(o%4Wb&^T884j-A#&F5kX?`ObqYcOKk)@Z{FRr+1$`zyI{bv)6B*zkc`p z&AXRx-@khI;oZm2A3lBg@cGNfFJC`@{r2_yk8eMI{`mRp_n$xi|NlRHT0{*Pj)o;c ze!&b3Y#bb1JUo1Y5|WZ~3d+XTwzl>TUQvmONhx&=9X)+BXD+{SlFzk&v8v@U`C|1BQl+>!;@~xE;{g;N|hm{{H`36{(~SGvl7zrFWNl z)iBz!|MU9beLm@7f9(UOf{ANBSxmfk^Sl+qEcx*M&%ScfU+fIk8kioP{bs3s`{voq zwbi#9S>B1i_Rwhz-8(~{RU?2u`lj!ZC)$B83ok{qw?r;-OTVyvY4X#rA}U92S?1e! zeBR#Wf4m3g{2hDcmqdSN5)Ap?Qdhv!c) z8^~L4VD=45WVMoN$++Y+g-x@R>jcZPjjE@;7$51suiIO`t6-1sNv`kzs@{Fu&FwbF zY~K_6jjR4@e(V*wt+L`$8c#%0q?yyhPH`5QuvgD?Yz-XG)Mw>O6f4)p)u%hDcnVde)GSF;S%T;^zp4 z-dPs3^W->ia%PF`=s= zZ|W_iw@?56DeP^ji%pP$9slgNb){N-fA1BT{N=iMKqdP5=Xe1ti3QzaSA;(_8FNk9 fu}tiK_90=G3~@%McN}wo?qKkA^>bP0l+XkKem6r5 diff --git a/phpMyAdmin/themes/original/img/pmd/5.png b/phpMyAdmin/themes/original/img/pmd/5.png deleted file mode 100644 index 51f536dcb55718123c2a919ec38fd1ba1945db3d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V8<6ZZI=>f4DSEm%hDcmaPFP@;5L5Oi(bSMD nQbIx^sw41(%bKf)y%ZU=S()QQ1+U))DrWF>^>bP0l+XkKdfXR2 diff --git a/phpMyAdmin/themes/original/img/pmd/6.png b/phpMyAdmin/themes/original/img/pmd/6.png deleted file mode 100644 index ed93cfee528ffea3c36cf41ddedcf63b90257862..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 98 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V8<6ZZI=>f4X?nUihDcmajw$=|u%1ol!K;~z we@7KB<})@hxRa8QaO2z&2Nj7>57}0R$p2g_S9@Q)1!`jOboFyt=akR{00NdDDgXcg diff --git a/phpMyAdmin/themes/original/img/pmd/7.png b/phpMyAdmin/themes/original/img/pmd/7.png deleted file mode 100644 index 7c7530f14a4a496c46e1d98b2290bfbd68bb3d23..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 105 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V8<6ZZI=>f48F;!lhDcmajw$=|u%1ncLD;aX zt;=cJ>h!*M%5I9v%*@Wrfoetu26t4hxiBV)Ffp8$VE?eFX^t>ZFN3G6pUXO@geCwA C;2XUF diff --git a/phpMyAdmin/themes/original/img/pmd/8.png b/phpMyAdmin/themes/original/img/pmd/8.png deleted file mode 100644 index 451998d1e9f2cdc1383fb67e74f57e941b07d7f8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 88 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V8<6ZZI=>f4$$PpuhDcmaPHAXLJuV++Y+$g( l-~odVk4sZv>ywWO6V$6DPINiR(ooUG~CX=H;;}|?${an^LB{Ts5Yo9?u diff --git a/phpMyAdmin/themes/original/img/pmd/Field_small.png b/phpMyAdmin/themes/original/img/pmd/Field_small.png deleted file mode 100644 index 4d80059a38ce808a88586852c9b4752c1adf1b48..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 275 zcmV+u0qp*XP)C9BPS1gmvi-=XjakzrW(1DxfeOfZ-P<%-TE3&P4k zE-eVpqHxHiz4jhI9`C__H5d*BWbbn;X?$b!RIB0j`zOFjZSsxL=X$M!q+qv`Z;X<# z1@JZ=>#7Kj8Zo ZUI5d%OZ9PGK*j(7002ovPDHLkV1jpvaYz6F diff --git a/phpMyAdmin/themes/original/img/pmd/Field_small_char.png b/phpMyAdmin/themes/original/img/pmd/Field_small_char.png deleted file mode 100644 index dcaa1c61d2840e167dcfe99f864705123e8e9eaa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 154 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V3y@T|W;X*;iJmTwAsp9J&l&O^G7w?DU|zH7 zpo9Mb9(AARPj<)(FuOV>W(0_SNILm%o4v}(h8ruk^gcg%m^&yleoC56FCMju_&)7?oJsfo|LNJ=yuS?bXVsPjO{i=DTE^h%>gTe~DWM4f DNdh^> diff --git a/phpMyAdmin/themes/original/img/pmd/Field_small_date.png b/phpMyAdmin/themes/original/img/pmd/Field_small_date.png deleted file mode 100644 index 259a8d98a5710ce1279072930a8d0a344c255bc3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 156 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V8<6ZZI=>f4C40I!hDcoQJ-?Bc$xwjxV)|<* z6&K+vMXGCEef-1O<|;TfC3kkzxXsIGzW73avPi`HnaYW~rwZTW&gs9t{|2kSfMBJI zi^@8S>v`Uq?KiEIOOyKQgM2S_E`IgNIx2hdjlT2ZzmID@;|h2i3$%{G)78&qol`;+ E0F071f4MR>Y6hDcoAde)Jv#X!L2;&Tah z(U?l+kN=(*yE)%6nc=$4%;dkhN$4J%r4PCnev-56ea~9_G+BA=*03+3N#?BOyWSRZ tYF?dqut)n(*X}*hbDQnwJY@fO!aTfPQ#aGtWHHbV22WQ%mvv4FO#mU@HB0~i diff --git a/phpMyAdmin/themes/original/img/pmd/Header.png b/phpMyAdmin/themes/original/img/pmd/Header.png deleted file mode 100644 index 3e3e4e91877bdcc76eff036f94923966e22d2f7d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 125 zcmeAS@N?(olHy`uVBq!ia0vp^Vn8gx!VDyNCJ0o3H~~H(t~;Lny8ZwEjlciTe*Jsw z!=H^0f3CdqWA>$Q@7$CR0o5pYx;TbNTux3nz$d{fn4_jrDCT%5N2J(^bG5r!{f3Q< Yo8~gSyZ!Tz6i_XLr>mdKI;Vst0GS#uN&o-= diff --git a/phpMyAdmin/themes/original/img/pmd/Header_Linked.png b/phpMyAdmin/themes/original/img/pmd/Header_Linked.png deleted file mode 100644 index cb0a4b374b49a0c1cce274528e6c8e035aaf0037..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 108 zcmeAS@N?(olHy`uVBq!ia0vp^Vn8gx#0(^xFFd^gq<8{+LR|m&XcU!Yxe>42QJ@A`X0zXR*65fr-IQF5+0PRLVJ^G6qjqKbLh* G2~7a)1tX6D diff --git a/phpMyAdmin/themes/original/img/pmd/and_icon.png b/phpMyAdmin/themes/original/img/pmd/and_icon.png deleted file mode 100644 index 3767aba9b5565a3d04ae39b78c739432c673d255..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 792 zcmV+z1LypSP)dgUva}ran6Qvv_y2pCw0Uwb;c)l#b0*DE_TK_cg9J0#dmqeU3tr3 zdd)g|%}RU5H+#l*d(51C$98Cb-}fx#1MO;}gNl@wnJ>B;`;q*S@@Ga)`JpBJQIyw~L0000PbW%=J00AH&cXxPsd7GQNyT8Ba z=;-R|>hJIK^AOH*Y5)KL@<~KNR2Ufr!Ot!OQ4|N@-#O?0Ye$((hX^YYiBK%Mv-L2Z z$!pl!*$OL*N=PF%(l$CpP4Dg8JHC$qKtwAv>lgtL0JCLxk1_i6ivSSF<%3}-f$PWT zYSjupBEp-zR%C&s>tJ1%*MWtZ5;hH+3&Ymcs4eMr+~;L{fK$mKBKHlMp>6lvd)-hoiWKgZJK$?DDxZ$WnVGM zxek=FD?AS(3(lJqJ~k^(=cs4xqs(<9w@FcMLL3rnrsIJG+9e3h7uBJ?RliGJXZQ8q>DGzcM{Lh6@P{-1Tzto>wal zecgWQ-HtQwcAoigH$R`f_2tg9Zx3Joc=Gzk>kq#^ef|Ca|9}4!qieuGG%N}7 z3ua*B;Narn;S-dQl$29YHnz64wRiA}N=!^jscY!y>6LnRuEJ+$1d8dEy!`8*Xw<#4vAa`%b3U8A z&91dfKrIXk442k$9xr8O%BVYEcXyfV%jwn}7wpbG&o!CW-+xqybMo@*)6*o58{Unn z`K~TBZ{G9Bo{fD`slF<4wmfgXXRZCZ@AZi@yGrgIy17uNX!q1iJ@2j!jW&wH{>KH* z-`ODKq)=?L=D_1FsnZT=wL5r1*z*6)tu`wCZory<;A^;Cpa_qr ii(?4K_2hzt1Kf-b3M`D#M`V(L;tZayelF{r5}E*BlopNv diff --git a/phpMyAdmin/themes/original/img/pmd/bottom.png b/phpMyAdmin/themes/original/img/pmd/bottom.png deleted file mode 100644 index 97abfc9346c45b337d62b22726eba355e569f1ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 734 zcmV<40wMj0P)xN#0004NP)t-s0001G zWo0sG%ra@wHf6msY0xrh(Pd?2H)XjpY0*AnrDbJhH)Xj{o{}ZJAnT@f&V>%|3HKPM118$hWti`{6>fTNQeALi2O-_=1GV6N`K-?faFnw z;8%&{T8iUah}>R?)nt_HW|r=3l;Cca+-{lZbfo-srTlrH<&3Q5jIi>MvFwts=90AX zm9gfQweFX*G z001#`QchC<1_%fW3=9qt7#SHJAR{w7Jv~1_N?KuIVq|`Rh>VVznWxy;+}-2j>+JCG z^YirdjP*`p0002-Nklz-OcXs#^!fme=BPdma6%?aZ9LDaz;NN?#+DRCTOB7{(VqjOXos z2Ngv!*PL_Uo%5U3s6;}Ayr-IgCsn;T9(0jVKXs~@fIH=IF)`{Vp?PWN9IyMp)dBRx zM2LjI+{O`b59okCJsBp!H=ayx!lKX2#)Bl-PLTcDUmbNToY!`TBjAdg^ zveb0tPc-cXnx^G@yb=|;yHV2HWTzjF=uoau$c@CjcKRc^{Go8rr+~;L{fK$mKBKHlMp>6lvd)-hoiWKgZJK$?DDxZ$WnVGM zxek=FD?AS(3(lJqJ~kA(3&b-@s=EIRIA5Y)>eD>CtD-XWhdG_t$%O6i(|9Ji3*Qc+)@6Vhl z2@Flck|4ie1~v{3E*>5}K?zAoIR#~7Yg=1;2d}8a#H5tEhK`=TnKPH)xN+z1n{#N;v`BOaBbFF!T0vYve`yg=d1 z{X+pfIvVeU1ZBBd9yT^M{u5hvDZ$b6_JIWx91J#W-)=IQk(+Dwjl+#ow@ws^nBaQ* z;>nXI*;wAl$b9{&=r^hSYb$fOYF>vz`>J>iksm9$4V+@nFMlR1$;vX(PHNGcg7d|i yuPRwtDkL>HHz>0TE3coirANfxT)9(`kD+L>sV?Kch`&JJF?hQAxvXr+~;L{fK$mKBKHlMp>6lvd)-hoiWKgZJK$?DDxZ$WnVGM zxek=FD?AS(3(lJqJ~kXo^ zS1S&E-G1ubjx+Cep80U(%E!|;KcBtz<;sIEcb5}K?zAoIR#~7Yg=1;2d}8a#H5tEhK`=TnKPH)xN+z1XiIj8pcb#NycBtnL&fKtINp3;_hs%X~_b&Oc>1gC6 z@v{gRYG*5JZcymnws`X7$-a5(dVA+KFSfHk;`wRazJdp4=(ghZ z&nq=bN{tGK+?}V$zN^%8wO!x9pwFzzShge~>51s%X%inkPg5~G!YG$vURZwmTQAVF N44$rjF6*2UngE_EN&x@> diff --git a/phpMyAdmin/themes/original/img/pmd/downarrow1.png b/phpMyAdmin/themes/original/img/pmd/downarrow1.png deleted file mode 100644 index 80632dd56638450fbe9cad1b2ae2e23ef6cd1439..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 758 zcmVxN#0004fP)t-s0001G zWo0sG%ra@wHf6msY0xrh(Pd?2H)XjpY0*AnrDbJhH)Xj{o{}ZJAnT@f&V~*|3rM{Muz-Ghx|x~{78uWNr2`_hxkf=;!1$zPm1}8JIW|r=3l;CWj|8AAsZkgzAo9=X^{B@=Ld7tHeqvnjP<&3cM zjjZR6t>}-f=8&=MlCS2KvF4Vw?w7OVoxuN|y6mC4>7%^rsKWKC!R@!o?zqhExyG@bL5V^z@ANPGSH60QX5mK~xwSmBC$0!cZK*;oo_gx||yb znW02P(M5RKP2c~z`#>rpNODQ)UOfMuxu$)AdLH;I#V?a|l&n2Rii6Hs(jA&lm!}ym zODmjAuSc5Z>p5JefB}N(?JVZ)I}XRT$SW|w^zx<=IUh<ho!G1K0?PW~UMU3@#HE^(JBTkp`8^n@l75+w zdeCF@Xv(ESgU^D2d!m)klVIz?0FKkJ*(JzpP`{)Z7{GfM_iB-a%IB-xgQd0c)nHN} oADdO_0L77t!a(hFUo`y75BxlAO^F|beExN#0004fP)t-s0001G zWo2b$Win{YGHKB^WxXX0}aajyhzsGHA>)Xw5Qc%sphRJ7%{$X0|eE(lTk!Gib^)Xv#Ea#5ZQX zGHTK?YST1o%r$DvG-=B`&}GHTO4aL+Vx<1}*QG;-xN za^yC4>o<1mICJ1Tfd4#!|3HKPM118&hWti{{78rVNQnGNfaXbu_)34`N`T}~iuO^1 z;8%&{T8iUah}>R?)nt_HWscismhNnn;BBD)Zk60_ndoz*{dcDPexv4ur{{{V^o*?K zjjZR6t>})i@{g_Nkg@ENujZGtZro?tHJ84!tS`t?zznH$JX-5 z*YwTW^v>Y_(BS^i;Q!L%{@UjH-RAe;>G|R5_~PpLq4>-pyG`RDEV>F@gM@cQiW z`tI}l^7Z@l_x%6={~yx)g#Z8mGIUZ-Qvd)42nY%c3=R<(85tfRBQrZaJwHH7T47;g zWPX5%jE&D6|e|PN{O&CA`7w0 z>6*BC8tW+XB80hA9g|CHYAVy+wM1c}Y%1PmX+=PgRvoI%4HcDlEU2qX%gRctt*i4; zVgidX>%^p00Y%fQ>*_M%^!UJnLKcZhN#%8Q6?JtfPL@XEU_lAz@aWjs(z?33Fjp%} zGa0a;luclKU9oF+oxguwww1XoSWv{&HmI&H#|kJ`muqb-4Hjh8v3CfrtIGz8<=NRA z2!I6{6xYNMJjrxK^R4C{XlkJV^?|i)SUYE-1-in;`*ucYbVXE=$&5B+*8&)1t?NC zWgd_$?VJQO1c(}@Ed;5VJhytnEFf9cKNBd@I2|Miv;wHOe#(3xYMimCdFB$Jc-!0+ z5VCW@s;&jA`xdY3Te5D_@{LngZkoDs^VC(Fr?1{JbIrDyYq!l>yKVNm?Q_=en7d); zJRsV*bN)}(|kDlIf?99$%XLlVxyZgks zy{9hhJ9T0I>5E6sUpac=>ah#gj$OQV>dMVC*KVD?e*5z6`&aHfxbyhgy(iBfJbU@< z_1ouf-o1MF;mwCnZ$Er`_wn-Qhue*FCL^Vk3X|6k1V z-VF>*!;&DsUrH-jXX%3p>5>{dX8AfxzYKA&$vM3+ zdxF60b;j>?4QC%xR-T~H+&gXa^GWQ*`=>cIwB0N3D*0&fOzen3L(AfccZDaLZV%DF zWxhaRiKo>J&q=}gp?@QzL=ql#ZZcb3DO?wRg^{(wyyx7Wt?W1VzLRE`;#m6r_+$NB r%WiE~Yk1(&@y15TIr+B0kN*6vwUtWR@@uq#!NB0@>gTe~DWM4fM0|jT diff --git a/phpMyAdmin/themes/original/img/pmd/exec.png b/phpMyAdmin/themes/original/img/pmd/exec.png deleted file mode 100644 index d5eaa767bb778c2ed053b3227575c6f88e57c577..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 796 zcmV+%1LOROP)=|^L17E!AxuST|Fg_z8Xicx= zN``WiQu9?idHJc|4s1KIE};9Dm19E*ZC7*2XELT>jg~OyD#)6G*Am5C_Nxuq+OI4* zSO0iB@#en(okwb8!=~0o2iSwNY$}$Jq+qo`mI-aN81HCA{kuxI@4M~eNB5nr1LWO5 zRvt_=)(k5epcZ^KRhFh}i+{f7EDXOWskuYpTlAc225g-wVCX7J<2?`EutV4J1D2sy)`Cob zJccU(1CuwzIbxZHcW~@1TetKNQ@RVl>(hNxZVQV!Xivu9s+7IfbWYz zJ6%j!%??|prl&2r3U>nHTHLnUh=6EvmQdfBBjvMude#6J-fAi9sfq1&@9B3Z-bg&$ z^ux$LGgAQxRJTUNDZ*9(Hh5aFTpJ(g1?JcL587T!ZEoma6kH9&#{H?O*rNxZk9?K( zLWgIZ@B;^52iCk&{|n%I!9v5yD_`nEp?lpkM-P>TKRsbt9c6d)aDHX7?-Eeve=2k> a*3~~*%rVb)$|Gn10000AmnD(D< z$Jg1j0)v5~EG0pH!3+m(JW{=BGZVG;XOc9QdZc*d#KKvNhzUHx3vIVCg! E0PqPgvH$=8 diff --git a/phpMyAdmin/themes/original/img/pmd/favicon.ico b/phpMyAdmin/themes/original/img/pmd/favicon.ico deleted file mode 100644 index 29c2595b1d53b36c607769e69479b23edbd27697..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1150 zcmcJNF-yci5QV=(iLiQj97IbMu8?##HWmt&cEW+Bg@vc3z4|}=2ZEiISXn5D90($a zm5pF&tr*`J2bOSWA|m12*`4IQo$L-Y^t4)NoMn3yrhs{&lrlwL0rajtUhuV!hG`gc zqI9ik3dt?3Kf^{pu-XYUCj*I7WzvT98Xg}4PZvFQkN4<0M?F@|=O+)-U&70MAeXL8 zw~qc4?u@xWrtj04l3AM&f|aT?Y?}UVR6|088pvft;!?T>nta< zPOLBbuxWP{pVgomTz|IDj`zYzk1f+K!tx+ZoO6A-AFM~}>~CJ?5o5hkcmKGSc;2D# psQUj{Q=b1tTlTuj;qXA{M4cPW-;E`)AR1z%h#!jit9TPRd;)f+aL)h$ diff --git a/phpMyAdmin/themes/original/img/pmd/grid.png b/phpMyAdmin/themes/original/img/pmd/grid.png deleted file mode 100644 index 6aee6e5bf771c6e8c24eaca986603c5306072aeb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 688 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc3?z4jzqMyzVDt*`32_B-Q&UroGR_!fUNlSH zYm|8b$N-9%r|twY?2?v3*dB=!tW!7pC${({wSg6%H_A9=owm(4rOzs5Ge{)kEReKK zS!12H-6n0DQRXG1%=5+>r+~;L{fK$mKBKHlMp>6lvd)-hoiWKgZJK$?DDxZ$WnVGM zxek=FD?AS(3(lJqJ~kXo^ zS1S&E-G1ubjx+Cep80U(%E!|;KcBtz<;sIEcb z0T`NwB|(0{3~U@6Ts%B{f)bLFatg}E*0#3x4qj1-iAgDS4IMpwGiNTpapTV2$B$pX z`S9WM=PzG+zWOBrH9zrmaSV~ToSdK_YQXL3!L@k-$HtSdBz9LyWomy=IARexM|e|F z(Wc3FOTY`t_`7;`-G><}MSQuj-3%{kg&_ zv2fk<;Ln{MEKMBpyn$sqp6?X-x`&Br56={q8xxy4Cx-h(xpmE-J@JSDJ45Af^Z)#{ S|0e+b%i!ti=d#Wzp$PzDK24?o diff --git a/phpMyAdmin/themes/original/img/pmd/help.png b/phpMyAdmin/themes/original/img/pmd/help.png deleted file mode 100644 index fe200d8d3f631816f667bcb1970da8d57bb80152..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 714 zcmV;*0yX`KP)xN#00045P)t-s0001G zWo0sG%ra@wHf6msY0xrh(Pd?2H)XjpY0*AnrDbJhH)Xj{o{}ZJc0i`g8x8+|3rM{Mu+@Jhx|y0{7Hc3N`K-?faFnw;8u$DSBd0WisM^| z++K*)W0LY@l(#?zznHz0K~v z&hWs{@5I#c%h~hI+Vs@m^xWq5;OF(`>-GQt|M>eMg#Z8mF?3Q+Qve1C2nq}g4iOj` z86F@bGdn#!KR`-aVPRrqet?LKj+vRK*x20N@bL5V^z@ANPGSH60PjgeK~xwS zmBIZ=!cZ8%;op1CJLhmVf=WfDKZ1hp|8f!n6N;8H-PhU9w#;szo(KL)_+^ukG@0i@ z_%WI#VWO!k(wsBlELtuf#z42(eWri~g4N@*8LMhP538aD3#{&+B%~iio2#bDz<`;q z+lnE}dP28|V=$1!w$%YJRAs3VD2yU!n-p0yoZOoRpkUg10^y8d%R3^V&^R1n0b6#M zrU!+r`Vs=N?!e7Kx&jn@eizgA5=A}N`N@L?oZLo6=Rs}4?lsN90^ZltNl=y8{AFKw wP|l9Noi4`IAIE*=0O3O7D3HGJ<-osu11)l8_4wA{p8x;=07*qoM6N<$g7frkd;kCd diff --git a/phpMyAdmin/themes/original/img/pmd/help_relation.png b/phpMyAdmin/themes/original/img/pmd/help_relation.png deleted file mode 100644 index 8856604feb2476a6dc99886a4954a3f2957799b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 920 zcmV;J184k+P)se+gP-;aB_0E=K9=Y8Qu(Fm#mlW%ueWy+3j(uf1R!sA_x9hudw+14 z)j5i)7le$Cjz4_-v~)1CA?0={UY)!P*#}e*iB4FlPTmFMlLaINF}$mIrrAYApwFz7 zT*XI$d|@RB`N~SkdDk~qO3u4Pvdi?YtUiiD1VE>(R5$N(iv>h<#!7Yct{TWWE7i@r zkhTvnx(N}8<6X9aNk!s#S3lcT@vbbpitoa^5Eb^%Nbv6vB@zfgW_uUkc`L1@ylVzz zGP!W&_pZE^hr2KXnNBYqU0pZxt`?B$c74BY=3QnXdLY$bF%Z+ca>ueD5P;Y-V{VRi zB+XNpgIF`8)!KC^Miyeuj711&Ff_J;2zpm21bssIS)~=k?_JgMYzt}RU4anOyGrvy zc|pP6f;5Mi-eveoT9ih0A_P+JU6lbcEE0QWtb-sNQt7))$ZRX_=v~g4cwDlZce&X` z^XXlW8uH_3(0x}E$jz;lzWNlVDR)(^j`eHUnkk@z9M?S}Ht zWb*f-c4iEKkke8An@(|A<6Y)PwTDn;yMWr65#|8}&K-9;UC*8wtuqOS+}vghI(=83 zUHMXh*Mov@7JQ9J3Coph1Hkm;M7?gMcNc@(%d`0000?A+G=b|Nry%@2}s#fBgLQ z?fZ|3`eD&_bi#P9{y?XQH#p{R9UfzHD{2ALUkSYA0E{-7_*OLd9RBAEC=FU*?hoQJ_MyvmdDL2zhO;f7cc2ru>H1U0ergnz7=jb z@vtrz5l#Xv14irGx&NJ`Waq9T%$6Cu5s-QDJ?i`RFcCNyrO_fmY3w>Oyt(xdIB@Gq zimA1_Y^VspQdA0(2exfxVfPxEmmTEjv+HPByPmG+dja_7(1(xE`YeuQF>+1GBp~@YLZG_@0B20cT%(fyp0#KzS}Y)+j9i zjYKX0E?59sD_3by2DAZX*~ns%6WcdY$>;Dr2Y_Gpf5N$ek1@WB*40K;8)h(Cd($=4 z*b}ja>M`g@FSR)$MBJT)HOBo^ntHQtyxESGp@c2aBR1dj^p#wV4-XsmBKH^S|DSM zuoFDEW)%P@U)s$1J$w1ScQaRyeMKshrlox;GSnEYu@f$yoA~yL-=m2;2K)2nb6)p- zvokE^h{71RzJc`84lW-#f|YWSfy7B?Xn1rjgI^rNb}dB0BbCnJ7Ym)wT&bMB1AG&l zWgU$tEtk%z$tTm{8(UT;Rtgoz z2w`E_HkJ^GAh^W%SpUXr^0R-m4*~W<{fyT1R;Mk35BZ=g&Dddlv5%pcqU3TIB a5`O@wr^TIerJCFT0000bVKUrJ)WI@5d&rUhaQ#>U3GY9#k* zFzz!l*ssKRAfEe>n&J^B=HoKF&*E8Mm}>nfWB*ab{-agyN0;=EKB=EctUps(erB@& z%wqYO!}7C${Z|;vuQ1kMVLZPgd45In{EA`y703K5f%UgH&u@R0-vQ#k1G#^Pi2n{3 z{~aOz$6NeQfaaeNjX&WUeAt6-~bknRJqNB`yLt2W?S~H^{`&Rj&mURma6JKHSL_*QlM77eRr|( zK6fSu9;U653@i+nwMsQ~&DmKd%sy-9dgkqC8%?FdzY^y!w-Kw|w=HdA_wnufB^%B^ zeK{%gQLeql{td<77s`huJv#ATw?F#(Hm^XHnc*RecBy(R8R!enJh4wFkKcj8S!%UJL%E=ImIPByX6y?-?}>e@KU!~aq<3&ELrtG=FVv;nf={kN9`PMW=;d$ m%S>B)&oT%VcnGY}Wcb7E%~zP@R~zgEN)Vo|elF{r5}E*$H1KNx diff --git a/phpMyAdmin/themes/original/img/pmd/pdf.png b/phpMyAdmin/themes/original/img/pmd/pdf.png deleted file mode 100644 index 8c110d30b90e1ea8763800481d337c2f97ca6443..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 905 zcmV;419tq0P)7ip7{`C_%2?d}#RSg9=(vFIux5CXwKW6+CH z4#pazrp8`KOuTd9X5s}B+yfqrCKxV$TqK$_u?aNo+7?KtZVGED{cfkbJ3BMmoevKU z4WV1SaPYak`9J?(-sj_eh41@3%aEQa4N#tu@k6<5D-Gjn?CKY{7~ zTPcJzaI`zs`O&E;2TykaVBML(s(6g#Os@QHkjpPDh1|J!2fuz}V9Oq+`^O^)G4M)P zOXs<_>UgeMY-nc1$FBP9ZPmEY8>8n?GH%JKYsWwSzU3)H@y{m{@y-uV1h6YUg|f?X z_AUU1<)W8dmI@99!{hBE4eV`e-ev}NpHHXLkxjt#XITv?@JY|hDu(T{P^_XGRSe4k zz^;0fY=;%2%3^Vir9zcs`vjgGeJ|1dLA=(KUsJV6v?=7Wxay&)5{e|K53h@=BESc$ z;xRcdm|SgQG~a}*`H`~QeiX<*S#oSSmPFt3DD?r^x`c9Xo&)4B!%=u}-41 z1=^DkYYY=q)s9*{6l<=`)Ur&m5>qc8mVcZy>_X{3f8{mWJz9qtup2 z)_3m~v^B%N6YJJ%-{n{>gDgXHJ-m7Lg$7Oh?3`LRvFq0CA1+@;))ajo?JnX|8M z7_NRZ&h%^v!}d{RC>15HTpq*sVRFWzlE433G(4BDxre>4Z@ajx7Zx6!fBJTWm4Zpd zE`w9XT`Oah4VHC-dk=Jm?@Z5xjp46^5OZ5Sy~M9W4-a1-wJz_7hgxC{LCO`6s^jx0 z&G&sKrVPe%`gE!~_-RVq9n54h#jSt=Aav=6(Vf5i>3rdM!FP7Vl}I!a1YosPAwRcP zu9*7IN$2Lpqbu%w)6KQZ}14 fp7e?T{g3@GgUV{V?*eQ=00000NkvXXu0mjfu&lUw diff --git a/phpMyAdmin/themes/original/img/pmd/plus.png b/phpMyAdmin/themes/original/img/pmd/plus.png deleted file mode 100644 index 11ef00239519326f3df0f83a1271b650371a8463..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 969 zcmV;)12+7LP)1v<_TFdjbDVQ#oF+|eLTCIzMya$vD5O6jN$R2~hw3U&L5K*t3eqA7x=AR) zE`z9)sD!R6H8YeZE9l1*W>ipgCg;a9bI#f4?7hDAb#Zh+q%5fSV%;owc-Q*g?}h(Z z<{I~5WhcFB7L*n?@4+3y{2pfB`4l|Qa5ttaSAgZWBE|5DV_lk2$Q(DXo`>CZ}C*Jz$`&)UD6u@2vu31#s znIt3BT$RAYh$^B=v*j6`XfRn#+YTLM0wOVI>nHJce8u3({^u@pEWmvq&0iB0Chlzd zX)F<574eYf4SM3$ys-Lbo>{hsde$TpZMzl4`-rib^JH0lbN{D=K>Mha8uzDO$x|?R zP^I2#&~Q+xWc2k6P;3~+Y931p9;_y$DKwjcnrh#Yj?U#HRF8!KaltP!MsWhU2uQ*} z@-!O3jinU;#HN$=JzKCQWO(Wqei%KB#Uf(xcx;yS18tysDTvti=Q~Hy7TJ2+yH~`i zySRw0ckBXS-^uqmaQYj{Q2`N96x7GFPZl3cIM<%0mylXE!}cS0)5;xvoom^A^E;fY z4fFb;r?5nf*GDPZ2oVrb2q6rDKW2exW`Arsk413KkUPh(7Y;L%LY{d5(!9oZXNQPP zJ8J=#+$lt1AvNXfx7jJ5tJ*KJESYxBkmrhX5cq@uKx3TGaFP=lh)e;i1)M0NLKqY% z#L<`gH{=sn1pBeQH@wo7=*zX%B+dox&2V5eB(@bY=cuMtyjQ$}S0OSn<&I9$qCAyt?m+ z+6R|8vp^2u>krKA?MW*4l*8+K#Ti<8M&<++i+b>?#6dz=ay{ia6>4_!jjuLMzx4O@ z^%~K}mGgFVn94Ss?Q~Aa#bJykumQ#za??CfWo-M`PiDLSQ6B>Iy~n)1V)>z1OKUB` rLPax2cDk+?4<1t4&*0Tv_`m2+)E(fv(RjDu00000NkvXXu0mjfi&53y diff --git a/phpMyAdmin/themes/original/img/pmd/query_builder.png b/phpMyAdmin/themes/original/img/pmd/query_builder.png deleted file mode 100644 index 13262f92bb7ac3659730ec23a5915574f0c8caa1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 685 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc3?z4jzqMyzVDt*`32_B-Q&UroGR_!fUNlSH zYm|8b$N-9%r|twY?2?v3*dB=!tW!7pC${({wSg6%H_A9=owm(4rOzs5Ge{)kEReKK zS!12H-6n0DQRXG1%=5+>r+~;L{fK$mKBKHlMp>6lvd)-hoiWKgZJK$?DDxZ$WnVGM zxek=FD?AS(3(lJqJ~kXo^ zS1S&E-G1ubjx+Cep80U(%E!|;KcBtz<;sIEcb5}K?zAoIR#~7Yg=1;2d}8a#H5tEhK`=TnKPH)xN+z1$dexeqy*pw~2JY0-iEYH|(-Hx7hvVpbL z_s!e4#fmph-SXhlIkD*Nizh6Xa+8yvKUi^|zi`r?)%r3!vKK?bY+V1J7$K960UZ*&wSqL!$ENlGG(Xc1n8k6fzuEH2e8ACrJ|M OSq4v6KbLh*2~7Y!jZ9wv diff --git a/phpMyAdmin/themes/original/img/pmd/relation.png b/phpMyAdmin/themes/original/img/pmd/relation.png deleted file mode 100644 index ecc49fac5a6c878600ef94d5f6ab68a5a1d117e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 295 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc3?z4jzqJQa;Q>A&u0WcBL6m`upMgP~K~$cB zL5qP)g@Hi`ETY1|r3e-@W5}G%z;%v+VGjetMTX*43=Gd07|ty8(#7aiayTihCas6ZCF!r@) z&iKCA!pM*pYh*UjRCDQut3uP0I!|3(;?ZXGW7m!4FZvfhG&@$n-0^Wwncz#&S($QL g*mdKI;Vst0HvE;`v3p{ diff --git a/phpMyAdmin/themes/original/img/pmd/reload.png b/phpMyAdmin/themes/original/img/pmd/reload.png deleted file mode 100644 index 63f0b6c92bdf34915b64e60f81886f3c25524ca1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 874 zcmV-w1C{)VP)xN#0005kP)t-s0000| zQc`7QWl~a7SXfwNV`F7yWin{YGHKB^W4BULQZi}KGHKCeWo0*IxiV?dK4PV1Wo15L zqc>%^UteEHVURmzvqoKpPho^kVumtk%ra@uGHA*>X0=UZjyhzsGHA>)Xw5Qc%sphR zI$xzbX16?MwmW05GHKE>Y0oog$}?!nG-t#&X1+3N(lTn(G-}K>YRoig%Qb1rGHK2- zY0ffh)G}<>GHTO4anCYp(>`#|G;!lJa^y5}j@xFI?rEI* zY?R<^nCont@NSjdZkgzDpYwU2<$9+0e4*ujqvnC7=7X&Ggr??-tm=%c<&CW8j;-jB zvFwts=9jbNnziSezW$uH=$*j-p}Og#x80+;;iJ6jq`c{+zU`>O^|8wMvc>4M%JQ|z z?YGMAxXkXk%<#I<_`=ln#MJS|)9lI9<;v9N%hl=2+4IfX^v>M$)ZX&c;Plqu^4Q|? z+2r=z=Jwv__u=XIq4?E2;C@9FIE>+t&R@b~WU^z!xl_W1nw`ThF){{8;`|NsAt z!ca#5002C6QchC<000321_lTS3kwVk4iOj`85$lQAR{C*J3T!=KuTI+VPa%vet?FE zjEO z8e^gxxBmYZxH2Xf6F@;q1Z;=Crd8q(=sECLf?sZAi(;ME90(4A)3(!5t2|w7D?st1 zJsRBg9nA94TfP~vfY$i>p;LXC#y_t!oq+{h4ew>%>RP%qQBrOU5}a^YRVO~S(pvX} zHYkV!M~|A&9^O^ENf$ixY@h2u4kj|715@e|jn`wDFfLaIv5{i5^XY8+XK#R(N z1!d3Ag6`#+3%u;Jj|2&MqQa+%@#<-6D)p6v0FEziJg^Ln)X(qh0t+Zj5d=yqWo;+% zE^kmk9T#QTcgYsJI7w>|90=75t;VF4-Z%WmH`h{kdvJTl1poj507*qoM6N<$f`7ls ADgXcg diff --git a/phpMyAdmin/themes/original/img/pmd/resize.png b/phpMyAdmin/themes/original/img/pmd/resize.png deleted file mode 100644 index 3c0492a3f4d828f9c1758881fa6b4e2e0fadabb5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 121 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf696VhdLp07OCrD^~_zwiq|BMZQ z;9<}qj-`bfH%@G5blUxKN26e`TQI}s*(K%+ZucJL?Xk#Eds8-9o^J*NLz$dbbjzop RD?qatJYD@<);T3K0RZ6+Djom; diff --git a/phpMyAdmin/themes/original/img/pmd/rightarrow1.png b/phpMyAdmin/themes/original/img/pmd/rightarrow1.png deleted file mode 100644 index 6d4f63b0946bba9110306342556d8dfaf9a5bab2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 746 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc3?z4jzqMyzU@Q#q32_B-Q^CL}P{fTE@>%*?U6XaI(4&uVvAo=8(8sqql{D5Y1@2L`m9nmgG4gU0!iDH zHP&g{ZPKx^mE8I#P@rkSUVGS7if_7$U? z>p&^H!t)@q;JiuUW0RsMCPhz8i=LR3y*4jg?SDLgsN;`k!!ytJA71s3yc(VaHa`gOd=l05IJ)CbT*uXvDQ{ByZl_Iqmow!- z&Vv8B3;yR#y^}ZdMe&lqmGht0Eq>Oz@=ed0r@d>Q_pN;~VdI-An_f@d@_zc}C-V;c zU$FPnfmUAc2dMqgEJgT!V(A2orHkWkgMv?H%SHnO(r z1SKgqEZDG0>)h2#9x^%_55+j2I6Ev@I+G_N;FKPVTG-TtR6TAn5yMgrUoStu6RTI9 z+Puwh8XNbfR~DAm*0?LP{fTE@>%*?U6XaI(4&uVvAo=8(8sqql{D5Y1@2L`m9nmgG4gU0!iDH zHP&g{ZPKx^mE8I#P@rkSUVGS7if_7$U? z>p&^H!t)@q;JiuUW0RsMCPhz8i=LR3y*4jrKMQ>TAQoAxee%7dH*|8p1o&zpKDZ{~}< z+3!l`zO0=8v})n2y2a0W);#T9^Sp2Ei@uGY`qw_2u<^~L_0OhnezIWqn}xexF5dHM z?cq0@PJP>P=G{&Z`f%{lrz2NBp1ASp^v%!b9{j%mL=XR8did|sqklJ^{JQn**PUnI zp1l6?D2Q(0@b>E5V5G#o@$}1C7CWV0YkX2_*%|WoF}L=k$H8;9x+E^j z(R!B}`tjq@s~=e%Z`}z9to*&@)hn+B38gh{-9o|w;J2`WM!s@=Yv1Tqh*N8$SKdBp-|YGGXD{5Oz^>#XG4scf j)Rd*H6*D9}xeFP-zO;#B+^XRK3<(BLS3j3^P6xN#00021P)t-s0000J z6B8Uqh#q*OA4#eoSg;>_upn!_AZ@%LbiE*my&+`EA%n^xj>;l;*CT7#BxCC&aOEU{ z_`2ix_4W1m z+pzfD$N1yA`|ROKkSKcq0004WQchCJ%n?a=h0pd9>r0I&QGBHV5lfT8!sH{$I)LfRy>BR) zxTPca!go`oEnpMHfUfIvpN;cW8Xm&N`~^7CZvHQCfIwTU7xW;E00000NkvXXu0mjf DC85Fs diff --git a/phpMyAdmin/themes/original/img/pmd/small_tab.png b/phpMyAdmin/themes/original/img/pmd/small_tab.png deleted file mode 100644 index bfa1b5937c2d14ad9b30b2a0b63fb20fa8ea616c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 180 zcmeAS@N?(olHy`uVBq!ia0vp^q9Dw{3?%2B3|#`Gj01c^T)TGtUwZ3*#_|6dYyLA# z|H-iCf7RCiL5uz~^!#L)^gm9W43$3_Qa&-Hykdxc#Sr{zOTwWjpmrNi7sn8Z z%Xd$l6g{B8;czftp<8PDztz6;+!ruCx0t|m;9=v7mj!qI%NAtRuHAYz>h{{b;ft;+ e{9k)G+0Cw{M3}8wHYprv4uhwwpUXO@geCx!7E3q) diff --git a/phpMyAdmin/themes/original/img/pmd/table.png b/phpMyAdmin/themes/original/img/pmd/table.png deleted file mode 100644 index caf214d23f6d4ce1a709b231842b09f52dfc7004..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 163 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAd3?%E9GuQzsxd5LKS0IfJCf`&{IW>R&{Qv*| zFHcF&2THS*1o;Is@C%rkTkmBRe+v}R^K@|x;kcfhpultLpaa9f5++0Kbf$w}6by_v rFJ8=iYRO)WBfJUAJTy2Y9u=4~oR2nYX|%X#1G37~)z4*}Q$iB}GK(uH diff --git a/phpMyAdmin/themes/original/img/pmd/toggle_lines.png b/phpMyAdmin/themes/original/img/pmd/toggle_lines.png deleted file mode 100644 index 9ab3764a6088fb3932dffa2cda193b506cf48e33..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 630 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc3?z4jzqJQajKx9jP7LeL$-D%z?E-v4TvJn1 zjWW&{WnMH(-D{M20muM~n5XUpGVGF;Lf9UO6RcA=`zN;eCAEPSpEt@lWu3OoH>J-i zWiv=5<1CQ0O<7}|w%sOen^EQ^qs;Th8K;2AB>jka+CHPKOGa6jO|s6IW}Pv~JZ+kJ z$|&<32xVU}%DE1dvMW3fA`8x&6h1a7dSX)a)U@b{S=npzvey>H53C#h+cf^SZTj!f z{NJJFze~+ix3)hX?SDKv{&+S#^QwR3)$k;+`9XN+lc=u8(H(cfMer?{=Q~aOBFz(>Fh#z4hhJvu_Vy{&@2G$LkNjK7IZD|NsA% zK(E7~U@Zyq3ubV5b|VeMN%D4gVd!9$^#F1>3p^r=85p>QL70(Y)*K0-AbW|YuPgg) z9xfgOiQ54(FMvWzJY5_^BrYc>EMS{((X6P<_{t=AvEZ@}-_s{N{0lBRbZAzlq%CW5 z@M=)=@wujGXl%^EGHG&*=z^vw!H*x~1O&vFGK-pYZ);;NW?r!%xuaCeMdRw7J1klm zkJIOJu|5-97T}m1eLEyNIyze+H7}K8^NDl!?#X2>n=2O*aPA~G-yD%dzR-_+O-%Zx yEz?76oewuCTnU!F`I&3iyM6oK{pt$gjAbxV)|X6JHhnVCy$qhNelF{r5}E)^d>l^z diff --git a/phpMyAdmin/themes/original/img/pmd/top_panel.png b/phpMyAdmin/themes/original/img/pmd/top_panel.png deleted file mode 100644 index 6d8302f97798e51cc17801e5a0813df3142ff08d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 173 zcmV;e08;;nP)P)t-su&}WI z|Ns5{{rvs?`uqF%`TF+v`1AGl@$>cX^7HNR@#^mI=g?p`>*40<-{t4sz6#oExpKn8n00000NkvXXu0mjfxYNMJjrxK^R4C{XlkJV^?|i)SUYE-1-in;`*ucYbVXE=$&5B+*8&)1t?NC zWgd_$?VJQO1c(}@Ed;5VJhytnEFf9cKNBd@I2|Miv;wHOe#(3xYMimCdFB$Jc-!0+ z5VCW@s;&jA`xdY3Te5D_@{LngZkoDs^VC(Fr?1{JbIrDyYq!k;q3yHRZJ)D#$J`A& z=WX0Mf8(yD+x9KnzJJBegDZC(T(#@a+Pz2C?LE5j!12uoPi#AKYR9oNJCB{+b^Pq^ z6X*7xy08z3PG8u6`r^?GSC3t|cI@J{;}@@=zIyZQ_1l+k-@kn4!Ie7?uHJok^TCr_ z51-zB^8EhO7Z0AjeDdak&)>iQ|NqxKl6M~%zJ?`1e!&b3Y#bb1JUo1Y5|WZ~3d+XTwzl>TUQvmO zNhx&=9X)+BXD+{Sxz><-4mvn3W!w|9|S?Iu?Jlp+- zL~ZyTHbxDO+RJVsx6`^g?R>;VDxR@CeO(Zd&v2EI`BZ4U=idj$k@kyR92~DsSzdGR z@d+)FtJ@YRXu9hDUNgUMjnmzf1q;r7Dm>tQwN@|U*-BR4Df7&J`(*#s&40i9%EHEF zd2=tNXKnA?EXDJH&(~BUrtnl>VW5?Oo=a1n`>iu#=RV5YuV0pV;?doUGl0Rs;OXk; Jvd$@?2>`Lfj<)~+ diff --git a/phpMyAdmin/themes/original/img/s_attention.png b/phpMyAdmin/themes/original/img/s_attention.png deleted file mode 100644 index 7f2578187c4a63a4233eaa9bc94ceafc1ea96b76..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 629 zcmV-*0*d{KP)3 zhb|o?2tteOkVJ)0hl&s^5iE&_P6b&gMn-0?yRw*y{*RfjgBpQr1rE&2VP-zQZRa2^LF5drI()F2Z0Z`Z;C^=XiC_d0g(KBmOAi2sD{f*&xU&Bvv zXXvJeIPrA%^!Vdl;dH%e8K~&p?6O#{VVbaW!U&ef!W6yyUku{U8)_$e>xJUbiC?Fi z=%TtwetodRAM4&;`%eZ`y&tM-HPxTP=e~y+eRc=xO`@RYf~BGze_dj{HyX<*j8^At zIf{jEtsnssSR8LdZlnd7B~6W^w<}|50ph*UkgB!^D~?0`X+W2!NvL|z#S!FJoq&p7 z8NRtSvK0T1Gb0Q0$ysFPC@hPx@|t1g9>GvYohy!Cz4KCX)Lc3m?G9}_XH(}O zvu^+@0OHHwFs43E03bkxpX!HU&ZDTlHQ+nmH2^TaKdEc6@@slFHMPT^eF-mdZ%L98 zqyZ2xEyAD+QeavekyYM?51ld0j0_&ORiv{Za%$-@LJhD((PeSQiu~ok-}`_OK$Aj;95XXZ!KE(AQoqkjluTpUr@2!v P00000NkvXXu0mjfE6N%; diff --git a/phpMyAdmin/themes/original/img/s_info.png b/phpMyAdmin/themes/original/img/s_info.png index f636683e3df7ccec7501719626bb105cda9fe085..cfd49e52825fe193ee30da19ad8b2980574cf9cc 100644 GIT binary patch literal 147 zcmeAS@N?(olHy`uVBq!ia0vp^+#t-v3?#1{n!goDv7|ftIx;YYIz!?z1eRM^{oLMy_Cz?NUj{-SrgyWT+8H~rLYj; zgOaFOM=G(A{HqfEzdl{2inH18j`pnpy1#$aF5(6c?}(>%HPw#y?A13P<%D=`&7O4cfKTXoznL?akE0)|u zk=D%#I(F2hG?E^G7=ZQu^uE?cMhi=b2ogL#IPMIM(>FAZ6^nJ2r6^)-c98=gw_vP2 zy>bN`+2)4YD)Q4socD+qGz5AMwxht%@Dv&XU?|Kj(vjMV`lxxeLB*m$aSGN|2;LKd zl6yYSo3g`OhZm0%hqHnjz99>ZHyHcd6vsh8MywANS)_yX0%kka^%ZB@%GKN zJb6CL?CTQ21wN>+Vdu6+#)?bayZzfTruuBQ|3cpyl{-)VltJyq^zLNxz`it%o7Mx$ z%Y`xn_eU7d<)@8_^=A9OTC4Iu={kNnt?Eyq;S8bNga(W;1>mYdZanD!=D(lmeexHm WKZ1K5!{$!_0000^p@>LGF-b8)Y?8L>B$~P5*fMG-<2V2JozF#S zv<+_BcX>EG9M1c`$~njXQR%-2hXz|4j0yHyEBkfuGAv?1B!h6lSle@{ZT#Vz`|8aL z4&2$)t^?iW)39XKqK#CREdby}F~`8v4Ssn(oJKfubI)Y&EI{XvAG8+&eZD!=R@qpy znp9zm)N~Sn$XuUrMIB@5LB1dTE?)|r0|y`X&Hy_4Hq>hq^ffPRi>#3yO!;twQeVe-~Eil^9fp3 zY@w*>m;n^D_7|2{lgvNDie-oYA%|CfiV~0A%Ri>Y-;Nc-+iNX^_G_;&6KVJvO#TkGuxbC4;EOjq=hxa2}DHp{b`841DbeyrwFeT2T z+$*7_ekVimK4N3PrYO?=k03RD9c|BRcmB|OA62f6HZ%2Xf@E$2Cqi9SJ$0dX7>M8I z+|?_2uS|7Lev#;%73KO<(RR_UYhAQ)$&QuVsH&(12ibgvYq9H$j6X~(PaT>3GBG>K ze{0#%Xam;m#jxLL7si58Dg#^~pl7lx@%A$P7rg?xbzT;`a?))80000APtL+xmrl$Wc`zf3n*g`v;0rbIxj*dHiZTr(m6?gBTa=mqF6Qo ztNZ~m#F3_akIwCAOSP@WH9<<)RMz+vlE{$UIr?75NZmBOzJ*kxEUe+X}JB?9)jT!y^oDK zLQExwUe@XGFqhsIZaLP7bI?9%3)Yi}p{w3$>$ba`|E~FKKCee=m)!r({S66-T?q1- R?uGyW002ovPDHLkV1m;$&p-eG diff --git a/phpMyAdmin/themes/original/img/s_top.png b/phpMyAdmin/themes/original/img/s_top.png new file mode 100644 index 0000000000000000000000000000000000000000..de05174ee0dc8b4cb5da15b7ea9c3f4d36604d4d GIT binary patch literal 443 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4#g<1Xt!J<>zE3D|ja7=P86_q~@mfEzw-fz`)4s>Eak-(R*~Vqu1d8fwujX zD((Whu7NJDEZ6n!xa@805Z{nH%jBER(qmFx+TZUTNYmaS6c})Dsoob3{ro!`B^MJE zS<_7o{@0wbKXc;ZN5#-XA+P4K9{BBhYi-2xT&a|mXL6WU?s8ebM!;*TdbVG zT*0=ju{vR?Mwd;F+t(lmq4MWFhUQ9}IQLY{6X)6VCD4U0nD|W*VLHSY`uP9 z+Nym~+0Avgelu9?xA^_3wqCwMXyR7+yDr?jm5SI|4xfHg8*|0Kdj7ecwhzQ^NUjgv e*ZjYJS$@a0sA-p64u1uPA%mx@pUXO@geCyHx~`M} literal 0 HcmV?d00001 diff --git a/phpMyAdmin/themes/original/img/sprites.png b/phpMyAdmin/themes/original/img/sprites.png index dd6ad46e68a9b0a9ac542ae832bc9c0215757542..efc9f02a37c44502c2194e9b19a1cefffd0aead2 100644 GIT binary patch literal 20509 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 Rcf9}r002ovPDHLkV1iP@_X+?2 literal 16796 zcmY(qbyOWq@FqMLcPF@eaED+Qcb5d0puwG>7f6D;yK6{rcefiX1b26L{dj+S_S@Yv zGpE}AsOp}n?s@8|Ff|ofbQEF~007YC<)k#;Bo+W5njj&(l_ou)Y;OYD!%5uge|G>L z4Lw!=H9E=Zy1q%d|9NDFZAIS-2xf}1Qo!qfS8jVr0sx3J$V-W9c`Y3KA$nqg^evfOLyig=1VaUu zUie1O?+Gp#SM;J~P~l|@jZC<8_=EsPphhC;4%6tWx!podeMqiq^r2Iu`- z8U`I8C=(RK#KdfpzyL`=aco(T%V1@@Es_Ud392U(^gV@MC;%t&3={ z-lNdnFzl;&DFcFCT2Ra^hAW8DO!UY1v7V3O31{=g>N6mjAJx;rC2O65n`bs>*1iw! zgb!$8T@0|n=QCD^P>}4mKjN!v$ag&EJl+mu!P&tL>zjd`Ub~&^UdoG%ia5Xc#$RuRkIO8L%S-9Y{sV6Te|T&~5x#G4(nRP8tK&KM$BNe@1(~(f@`< z{B1mVu)u21`YM#@J7&UQ-ecFY*DTGuO1~EP@y=Q(5vA9j8XP8hd!mMByNaQ?P-mIPtUE_4lQ5|^E5M`2 zH;hDyS=sp_Os{&<@BhfDHz80iq)z^?C{Q<%5C9meEk;@T`c!1(hkgHYTA(9Osp;Z} zMoMxM%87+=TA0b4(>|8|#sHHRxJSODVem}sP2~#vO|CfuAempm7R>YYG7TiEn=6v( z0o1VPGV@+hhE7f#22_ZU>1k4-vYh(T{r@c3pB~p!!8O_F3&Q}eDx_NgRvd#{oF;9Y z%68m4hGZVmt|VMMo{9ohVhS2Ic@q}tOWyq0yLV{T%b^I+*S-E|t)+dC$~8PJ zLPBfy2AN26hUFA(q2^Us6P z(kX0)6@e9c^(eNpzxzE`{X#&n2y4F@S9%guMVSz|zFwGn`S{Rqa$-L}-ln9j`d%tO ztz!m2ur53N9yvTu3rf30zaneBCp|a z`?2E`C_+h1p6_`LCZ@&CP0tnvo&fDYY+l5QV@9yF0!Rh#HHa_mA{5-euMBwDd&9mw2L zT3n;}H!Vg!dM+cQrAjUBmn2bn<)XM}=sf zcSqW=q4DcOd@0|26%6lLcz9M|Ci;Mpi#$}5A|Afpd-#*RpOH&BFINonyT)G>xL!Ve zG2bbKr-oL*O=eW_TkysA$rBg60<4xI?njHU(07~yr3Jw!RZm8{je-zGMaDWlL?VS; zf^K_c7IqqSg{~All6REdW|Rn&hO4&N`ZE*)uk4`$y=jh>VP!weAI7)1fD|yQk{tZ6 zW=}=nVE&avDkx|4A^7JMd0&73c{W|_=JwMsJGk8bBe+~yZ)neU7sA>QiviAY+0WGP z3i3#%!mrJCmA7FujbDx*8c0u^%ta>psodK*fEpumK=q zkjC1)zC2Hu??{c0aPR_g#qQUkuxcYMfC82xpBlo2!34~N`vHv9b{8vvVTKIWMH%KV zS4yXgTLj0dLA=pbpFeTPkhJq-$H)2%~cm6vS z?uWa0|JKxAwnO>vX`RNOPuk>SSn1T0hcB92Q=7Qz{$|wWDymX{(!xr`O8&ZP!>Se5 z;PUN^Xz~@e)K(y-*wg$yhYeSAo*FPna8Dzyu?H8|`n9dfQRCum9vWPs$cP;iN%6s!p6!fG><>fmXnqrOnIXq@=D#--QR@&Z0A-G7L;4lVXJE*8Q@*L zMr2UkrlLCMXn;GGIl7UY^P$xDeFkx!F8RS&)kLUi=|mKipvG2h5}L)wgk}YRnQ&d@ zEkxLoXQ^VopNjco$5p498JE*~a4I(Ew!Ldk`Jz776SJ*t#*Iqwpb@1kKpUY9wFmB+MmpS@9*C ztYQu=ejqvT&M*}4qg+P4*WaaNwuxBz>X_w4K`L`-J#^2i5=2WlU6LkdJ?tF11`g|_>4ha%xw zqG18fI6S&2_Mt2c;V8Fpx3nk_WN_FKI!kUy_>Xd^h=%&ek(=63n>DEjW#{^!4spQL6?_EvhSc#VGc z$sbM!l#s+v1IZtQte4?>=%{iuK8m6m(oOwezS}76@zYXkHh(5ug%H6-o;Lm18ri@`zsp^*`e>f_lu^uR(VSo z62cdrgtZD!WcJf3#MiH~H*C1YZa#^hAL;)4{*@p$7BA*cAj#U{X>e2qELH|qRNImr z-k)?`?rE_z8S+ky%mmen542Zvg{$eRgj;@nSYHR%xICfA$J zdNmBpefb~^*#c>}wfK41R06$)O|b#wKmByphdafhvzJ$cV@}_1Wr~Hk3hD~D-2pIs zzob3f;6lfX#YW3()Ar}8Y(&D@@e3;2@a_pN&(0Yr%)(}=+g6VaeVPSE!M@J{QZs=( zSUHA4-1?H(*hD{23C0S_%W?4Ww_W;FMIQ-`n3Jh5oe(fAPY{W|Zth$UEfBlt21UfY zS>iDaQ&>n#<@YK&J@YTWrI=XzA6jXRL2_x~6^_m~Xm4y$`x@shtFQ33H1y%F+RcY; ztMklvf3g4(ixh`3Vs&By^6>Cs`rp62;syj)*a1@wu;VvUgGfKYxKx6Fn9IA*@TxbR z<9{s?lPj$lB7cd-rqKtJ3dBYS^}rOX;G>|hZ6u@_Vtbj0!f+ETs8EN!z+C1(;(&|V zY2S%FSa+wLe=g_dzNNAm^suw|Zu55s9m(qEs~>a~%fsor^egQg}0D*V}&T^4z|J`PR)OvUR$8Qj+>uOxrJ~Qo6uH6kO>Suuz|`tNX}PGAY1jtzF)Wc|%{3pn z&UI;s`7)B>t>&4h*CRe+9wng8WM64zW^oKulZMtIF5+&+#>M^M-jw~QDZIQA@;n_*0r-Xl)Fv0sdmdku9!xb4b~dphAyEDMbDE& zA0}3-k$II8$3XU0sCAKeo}svI2u+Ha%dIC0RF}#E+T+wmm_Tjy26S9|?2(t)5S2A> z^bKk~vV=SvtTyXx{(=k9{<`DEIjU};;pu2;edDuV0Ef=M%+DhAfY9jFxGqUd1d#53 z;FP8{YX(~@Uz4-Q-^1I@fSS!Nz|*N{w>=&oqf&Z1@p zUD@Zt>>W+Y=>Sbb-ayMX1Xc}22Ka$9p{Vi&*cMU-Q0gT9RE+8Gd+DD%v0Y>K%6Y_N-Un%emFTLR9GZ@c@5$PqMlJV0KG?oZ=kCib|g^hkue7X)?8;U zCS?=6I7wH}3;bswkQHeRcz4Tg4f|=Xa}8DE&t`C?$e_2(=)B>7}E4aEV}q>Z6x@P;rsxOZHM@1cAV!8!TX z+FOCVae!E)55-vRVLfSaDl>{QOwr0v9e--PXlFvQ%J1NOZTD=ZX~G)XkK%g`?WE+E zUURd__)|G=x=5+qsca?8WP$VOyJta}|AeG3&`zLNtNi=Dd<`ZKV|QeV0sn!QZx-vt zJS(4ZL)c#UzTZj;dh+?_%~-GUg1Z)A#FxHUL`;A+nb=iIO_bV23Lb4_37k|2Wkz*!4}r~i$&;*CbJJo#LSE%eC=(H6ONatFoSEYSYwe3yn#xJzv4ZJ-=Gh zTDqQ^`NxJ|*t#0on>8N7-WmPH_>x3*+PmWepv;%;b*yDgq-y80brKWYwZf{QQGdxD)5VfI-7E z*T3T$ki2C{(z#>zLKe<}=X@V~c)dLBKI=&WkH?HU;l5$INrD`XNSWfZwl|ZJiF1w~ zOtyWYt9;PUpRgo>3b;$L5IeApn_|$2IX`V~Tcv`BCXA7nfl*Frg_LrqX!SS&Gl#{q zyt3XpK20)?^o$FhgM4@K4P3S2^iW@K*!=AHM-r3X2XxAS z@!ujC@oEB`P8aBUdFX2D>ZY^K-w7gkY%z+JGN@(gV^fC+?dIx0n)J$(2$Zsv3hiNW zT?3IM!FjZq@fylJ=|_* zw@O#EA(#ZmIT8U8ElTG?0K26$FUYg*&QVkZEfS2v(r}l z6L7McK@8gN`}##mR_bsO_a6{HG$Y(-*#K>zKmqN^Q^rUA_|T$(F@aYbV2whO$K+C$ zR)@-Mr3%Y%Nb`cr&_K>nO7ZB?f^@MzuYhcOEs?TIqM)F-b$K;ZVueD0lcCY(wvWT- zu%ssBHn&E6v7gqX{4WoQmaj(K z=O?3?-hxr4pewP0)7vm_M@IUHiP$7}J<)zAYO;|DXshyJa_z6arg~Tm*Y*yFJtYBy-)f4!W9{&tYbuc^_vc~koPV(`L(UWMMVVK?EyaLKN6 z2Fw?4-z8Q9#-EJaGS1s5GUM{{VGS++x#vZ2p$O$q$Ca9D4_O5lvU`Kx@J5j{L$d-q^cnZ`SLcl3Je zzd91FGdOznW;v{pdaG^;M~yar75o{7*X@bwC2h;d7V2%rH5{WZ4&KXY|Ff`Omg%X= zqu@Y5c3v#N#wLrnyE_hzUI_p84aqJd2CU^PjN@@6L6WRyaHT_(S!gxzQDh~Hv>wu4P3&{)HscUG=hS}oYhpJis7>6c6bXMHV$9d)s-dO?a>PniVb||cP6OD zbNvvJg**^VeKbfn8ti2yl!P0k;W=aF=yhq$8bfmZgpfA}uEa@3nh-viKWI1w!^^7Q9qW!H(7TH-&S>3yK?3gZxmRM>JG-kmJ@Yqz zLBT9I(noV~_fQjiBKf0cbVZZ9rdCeht5bX6I_iDwUIG15Aad=8^$f??AgThRp0zyo zs*2;F$%5D3FZ&UMJR5Xqq?1ISOP(=hRK2hoIh;m-WK>@3@rwXxq0rfJq498;B3f3Y z)Bv3!)1kw?v`?Ky^K`bnkT*2JMSvTWkefXZktP>B;fo{;AkpJ=7INF`swsnYaCla< zT${08Z9(tpZJ=VKBIRH0nI=4E*XPq0(?2f zpRz96uv4E}31eNPC?HpK&P>`0SzS~6g|<7=0PfoYmU0-IaI z8m|%xjx#-aR8J#8eu`7hv)Fc$H|SaMOLzSpTHX#`rxDq%2p7m==PsF<8OBTX(CH-Q zxf4aM@P_e0T=_n};-wdTHOYW#Vaxuh7MFXMZZG0bnrgr@a>Rq^cjV8rVFdcT+(hba zwxfjWmxZ>_txIl5^nEwzrL_L2s3e8zv>lJq0coPZSqxRIQF zGVJFasncUXG6X}~z>Xz4)9iJ?rYzU$6&-ZpIn7VO#du)1)G-4>1-=ZuE*J}F=)J+Fw63nMiSC((Hwx?+533fOAGS!yCE z!{&C}gAa8Hz<$=D?>3X*Il_dES$!IvFLkCsO#dj(Re^dC$oR1%gT?PA z{oflp?R!aN#q)ag@BPA6^w_4S?TsQ_7lu^aKRf~ghGGPJyyBrRs~QC0aSRDMRn)bS z!t4V9jYB8N=nvVJ)qJ6)_lv`^Uyz}I+p!6#YYsuDr|-k=$0B0eq^~qBTtH$cwK-C5 zMU6~nWd~gG=;Sp)Xc4u5^+>>}XjLu&Qxnqv! zU+K&4v!gtecS(~Hc=f(~@ariP(W7lj#xWRljZ)T0Tlzibz|ZKwZ^P=ICmlpmDq_9Z!kTEF_I2)TJv1`9=ke5U z4bB8f1ypM}&Sh?N*r?QT6oONo$Q2_A9r3(by^*0AO<5YNg-rsNEs;*D?r2qVKOa2yq%OfXZrhzoBqU6{`UbYpqzad^ z7XJRZyz?2qz;)xp&5?4s0f3&m#rFYnx8l(uAl=R-Hy29Z$ZY%K)65dcd@GcJk#MNc zb=u0uUB1rAh9Fy#p_ps%yg5ZSD^~C#k$@2~Bve05E1X|x-eTa^56;xkhD{Ajg~6(& zULppp_>v&9S`n<&fv};}bf%UJ+5!;#oq;qmt8*r$FF~+UeGxUR76OrFdc>u(Y0E7N zID2#JGEVA?J!7&1->BZdeAJ6pRW$wvwj1;fwA4p-(@76Y=S&sgd8xuNb(y)Sb9=SIFE<{+H>k)U3_S%mKn5>i^BhCyp*%Hsn2 zd;5atW4g5^tj3Mq#+De1#M4!LU5?G2ov&F}{>w4}^9V180lqS`YH#qH|AbFH0S37W z;{6qiorNmxvJ>NZ-06p zcQm=uKu4jO>n6lMeK${d{#8^}H)x%vbC^Wfjq(Q?iPr1!-g?Q87*gSENSUx&Glwvy zbYEI_h}n+YxFmKG#O>b)OzDQe($8^L7nf?p&uOg3;)*^_*Nd=bnXMDG@i}T{h}brm zjGl}s0)m-xG*jei_Y+B7;eYGIBWjy>T62bRAdBw_vuauEVx*VnwH!w^Lx@i4UGUcs zlE9Af3VUttB9^1OzxXeol|J?vmfQ-yS8X6@hEqvMOW31x!Z2*3iO7~2h_|Zte9^>M z7EVxH!xOogXoQqv+R-{8XC|PW`CuS<=@z5pSebYrX9f$oau7FPz6O1$WH85RhdXic z;Kdk|RrY~#PM~nGYp8b&nuNly%;2h7u;STwuDNrKh@ow31#$q=ZZEs%61!vX%8v$L z$$rE%3G>1< zdMrz*bw(76=9V?siC$5Ikp`D(5mA$pHSX&pWnpykP@5l?hAb=Bb1}8jaqx^#-YIN3 zB9m?j<@AybuT7gCs(Z*(?bIsnhug@loXrMX_ zeHuW;`1;x%j*^Bc?HWTLb>0UjVkU$LmXNIBomUfDht2&MV5}0IoOYPnArtcJ{*-y( z02coNpo5ydReve5_D!`HjRDUgue3QkS(*l)z2+A3$?ngVbo0^G3~YVp7B;qEpejRy ziG|cwkeJ8c9s+i(2i8n5+zRGdA5Yl&HpuvP#W-XCfgjzc znpPy&_y`Wc4gh!KlCwIF{&a$a8vavJvAx<4yAjVyaVp4D4Y6T(WGye_s?suwA#iO& z@`V}*zwNG)dq(I-%N?C^|n*CjOpp+9k z&g8aP0Ug45xX*<|h1`(y55!n9iUda+Dr9(q22N)EX^$08d6S6IRdj%mr`^NJ;0}x# zmiLDR5u5L5*H)AdtYj(_X8!ECsX(FS2)D||wHMN!C;jOfVM{zqJNoB**>iP2es3aF zADT`XAAxGPY^Fop&~NBG+p-JCgBkm7cH<57)co)Paxq<|Dd2m@fk7@D`bP5jyxQR> zr>L0VhcZ4kHsj#CNBU=TFouSk8&@`(G!E3@xEh_BO4v6zNFyR*C_3-*cDNGwdO@3+ z8g@RBC&|^D&TDI~*XqIg^z^j0xf!heQ>S}&mLM!FjEkc`DNQv;lr=&I$l$Y&*UV*Q zd?Sk>VPeXvsbTTi%>e-c0cmL~(o#}yj1rxlIF(ERszbSr$tcM1@bE=-si~=H(;G>| zd63L=NTb52UGIhogY(C?Z$r6L*&;q$u2TCtU~l<{snI_f{F^t6j)V4%%RiEsKbp1xEx3{-b{Z#w(DYT}BOY39p_+q=yF|}s-XbSsaJe?v(z>BXgUAUxkSO{$r z7Z=yorDQ}z#5Mt~@*9Ckr{Ys!kz$J3de8R@PnaT^W=Us8wr6@Kx{(hGNfqfC84>yU z)bpk0urQzMtg+vK9L5x6vqDM5GNq@hzp6FLcChg*F~dEHu;!FgF74`3*NOd61f%mEJoIrs>;ZC$u1iO4n z;?8SsnIcu6>)lT70x#!V`Ket$MjB`bdl>b^R7-y%*A3M_ZK23IdEzbpJ>L7N^Ag%g zIXJwW6KeO$Dfen>{>$ylN0Z)r?!n_@aj+R@va~^8P;A7W+hFDS&&AVT>s14^>#+fW zoy(iGjq_)@tXsN5*Amrfro~|U{eGn_)Kv1=i1U|u!sZ9k4qg9u#%#kqBc;9}H)~RB zx9C&z&&b~iR48g15eLVU)=;>m zt%cm|D8c4QbPSr3-mTwp*!5p0sx2XdP`&6S0kN&V2P*ynL@U_c%_B_MDnIYaA60Y- zp7!KVU-V0+QtQ0rLe}=lm-&_M?2ePeatx6&u5|Bbe7hDqbqsg`s-EMGML_0PH!RT z&AX)M>c*yB7|9bSCsw6Vd8I8@{A#t|Oy94yKG1I`$e@&?*_~82B4+1!h$WZGKG}>1=XBXqIu1bzg%Z_+}VtC zIRowjW$W#J*#f{e+VczyAABwg?fG!3uq>m}5JF;7Ul$osESNy{&jcc+8y#+-+JPd> zyPEvtGNjT)`l_G?rPi#C)}$jPQDrMFkF=G&VUMQGrD6D}B^C zJV;G!AH(Mh(mW0-5;YwhSWj~>jNkMq0GUWqf|Dp4M2aMkr-c8agju zNo=7OiRO#e_I z&vatV7F~?=wi7U^&Je+;0a@b12e@-!6Kkl<>bja@97dkEJ5;~ zW*cLF|7vD0;UcJoBoOmdGoXP5B|GaO${y8w`f9gmIzrf{?PnUQC5J^196yqwl`XT#o#MZ~R%i2=J&MqVS3Uf2#i)aBbgq z1;Sbob6Z9VA1b>3DF*tKYF7x@jp|aqb6brKxlUX;jAaVGy)*gk1>KO)#AA@W+~t%6 z;45?zOC@QJ?B!f+WeU9SDQvCbo0`6l5qn|8$i-mbEseuRSQ9LOw?hHz%55ZYevMX3 zjYVf<4ildz$0|LZ(jo&SK5}6r6_FDXGX7ta92TZgWPvwLZ_xbT6#G}fK2|sfn*%I2 zu3>JV@|{YVi>|mc|5l;mmsV6^0InF)(Z{B0|1Xl4sw5W6IOmX{M0weeM&6_I3Jk8Zc@TnjP zo4achr8YG$=7=Y4op&gLngppo!DR{SZ)CJdR*)0T``TF2XL_(EzJ$+h!mn{u>_BIl zc)em^w}drb+>4VwjFF`58_F#FXwvZU!I8fY<#VNCA*vdy$TyySf4jt!ZmxZdiue<$ zLN|(|kHyEumc{m=?WE3LH|n z8nz8X#Cg~6Y4Lo#`Ujeu$SeWue)7ml^k+X*^;mQGyh{+vAY$?xrby*S0{W0tBV1Qh zDOAGcDg#i~4z+rCqZd(8b2vz8jN+|P>N+7S>Y|pxTEJ)3`9TGT8Su{v| z6QNH@qb$uGWc{6owOYrYCP4wN@Q9ye2ZksPf!M3k@aL`r5|{?hS1RPFYx#}FeDusH ziO=YclSVRu1Muf_q28BbfYQss&r~&{>{4(8QF33>U?xh@jVGXkSpO|gLnOr~La|&U zVr|1WU0*KVs0&+U@WnvgQFhBcTu&>c%?&4%3AjeLQ5Ln@qKi?qKml)DObtH%!7D!E zCV^4w?Uv=RUV_|y`UhoAB5Nzv+wSfDn|)w@$N48 zkiuA2DEY;FNgIAVh};W^pDCiFR@rIYPA&$lwbtuGLg-p5dRk9g9Nwr!fxq@zdX^ek zHD)UvSy0(KkG#ce2(|~wajpCxYzm7DOAlaC<&IY=%E&(KaZk18Nk(OOPBCBiVv;e> z(!@~KdpZ^(z=u8aD`kE7_mC4BB!4Jj;%Z5pw+@Xmu}p!reU*NnHsox=J$bF+jx?*B zr7_teIJZY`j0j|-%o_i~pvxU0vQ`j}6M&$9ni6z_s?#xy8Yd4Se(?K6iQD7V_t%8&J7-K|+oDN0!y%n^$oh#pH+t|dsM4#$; zEj6gd)7qgU>rC3xaWGbfh9ftkgv3` zH3H=@!BX(1+C17E#BORKHsvM=xjN#rq23n8F3k&23hP>2-3^PRwzcqjV}uJ+jGbouup6 zA#S67r?b8k6+g2O^koHN?I} zqD?B>AHe*9kp-wE>*Jbz$k3YSfK}r|eTXcREk0xW@8eIJT2jh_v zTOm5N@MJ53BZaR|mVIm$a=+TNCBuyvtl{h#5s%Z&)d?!x%-%U9gA&U~jFwfD@Z__o zK{%-s?Wb`0N$$z)Q6F1!HjB<3SiL-b_S=Wdv)Dqt0X@fZB_zs!<}1pCVD_T}(5DgP zMmp;$ZAw;sc0E$hU_{K0oJs!39-?ht4X@90&r!~GqXWA+0WWw3tdY5rH=Zg`5$~&} zoXK}GCU~Pm!IP)N!v&mZnVEo*&vCsYVW2uo!5Hyr9xVgJD#!1pF_NC+pzIvu%M|a% zW{lX%@S35}UxU55>d!*Ko-Jz{tscj@^icvLM9L;t`V0`2tPkSy#HT{s;r70-QMg_0 zw=1ad{ahC&SFJJ^)@TKu`h?4;Z!DK!%>1|pM*p8-Dp8P{eE~rc^miN)SQHC^4!88L_IBqVhM)zK(jI z+#AH|^#Gs@K5FkpK0Lg4X5B&XL#DtL3)fLnHAJKRp*< z=6^PeP03;Z8Jm^RE7~R55Ar`V3cNdBbPlvwU21l9W)mVIX|%&e{M6w>XJ+DhS zZJ%wB;+e%jxnm2F9S$CG6fxA7-vXtLC^zPm*cqbh+WB(<2k+bGH$)Up}#aj?F*nILFB6wC2&e0caMD_Q)8ZKw)*9LrRtMzkjVI%U-|^9r(pw8 zB)3ohYz=-FfRIIrl6=(!7Vh;a!Gg8!jy}B->1~E3*Ke@I8A?%cvJDps;pHt;uLA9{gr!+q8 z_<<3%%_560_;s{Zg+VDH_C{g8DOwZhe6@u^$#BV9dr(55l7+XX*ff%1mprc6wGn&^ zZmj)ufJf5vFLl|kQ7Bn^k^Tvp^JDg+=suo9*4JjYQIXY^7WN%AT2bA3^k1v75`Fzf zJ*l!Q=^fW-D6p3)`K0aOc-bj9}YuApRHjQ)J726e2KilXD__*4pP~*9Ovgmcmev;v& z?|nCKa;5MDV18fyzFOG~d)(3>I`d*tRzSM{+lK7a-+d*5fJXJ3+22X`yT>+J<`d+- zGbn7HXWi>@ozK*4&bef#U;EkCSjhQaGUCL^HQ(Ukt8B|Kn^}nG;=T7b-zkpw&$bnU z+fmvj$?NM(n8_kMC%0BQRz9Y4)s<%l>m_HE-#YXBZuuA-F07U2yX73+L;azPN zyfIP7{`AEkHJ^>@f3I#1J~wsv*p_|oxHPp}jNACN{-o4)f5x#s+?(a>ZMcyas%At- z|8%_ip8g8#GGW&*SpTmZs+^t8!#u4E9jotmn&$$v{FWzBS2vh_)t6vBF`J+Je#*Yi zs|$<^U0IX-^SjOXmw+O>5op>eCR(_0nZc6MV(jm6*?`FK;xLW^J>7F@KGnZAZT+b! z5`z94f{hHSFhm!6t}6$1Fu#2W+NZ>j98XyPr#y00D*_iti2GhZ7Vz|u&*aaAw^x91 zj5AG0di(wp2?!-wMoY*KAQ^lRfJ?#fwMPS|+zG%$ngTRLmmC96=xoQ&)7W6;x45ZoE)oHE z^19g$*A|6AWE*URljtAZ=GH+P&)vopP_%SACTl(t?Vl&2u6*6DHk)XT4}ca~4vXe? zHFBu{*E{@>&U)C=G_7V6*ivCW`QmVzO*MZnyb-RDQS9))Z<(}sI%=^Y;o&G4XNp9* zPkV5Q+&eXr1*z3Cx#j@@f;~mkx1^yxD%k=9X{QOOIG{xGCxjv*Np%+!Kw-)|&wL!w z5`J&?CSM6i(IDHG7%3T2z9+RYg;mLzf!7TZITcVdbs!!YRg6tutJg&WD~H^|@f<}P zHk^NWbixu8?mMHzZUj}h70?w#f#ZjD!Nvb8ol$P~m8n?Ao6DDAffr zKm*S1H$u*q28=h$&TmcLxI2>zghl9({#Rh&l_EOkmH9`cHx_p7Yj`GpjG%V$aHag* z((KMCG;nn(u>2eowlhJ^we_3!Ya4nJNj4&%Sd>}kAgL6l@l(KA<}GQp|Di?!CZ*5?gSeC{H01OFO$v_iN`-mS^Q# zviBnk2HU;RjOsI?CL%QCvkH{huzyH`;z@TtHd(bZ9Wx2)V%KSgPADOhAUCskTSps->FUZ4SXalvF`_K2KH%N; zmx%8<^;1^U%yEg5QsMDl?gLoTzR%(g9n!kvvvAJB3#!mrI4tLMM6U7};psXL_q^f#g8xvr-CgE}^NC#{3*LStq#cZan$c`3SM4VU zU9vHQw=h5tG3iKU_siwK9$EhvyO@_p!9Qfl4X@k^0rx}-Lg)?m#}o~nk&(!U!${tV ziEVfc(N_}Z_W^k|YwGjtL-$scu+2HJgs)UHcQE*sut~6i2mLjwluGdq9*`eD5S}^? z(UjAlo`r^nAH)*z=1&CdOLbWkd#2B;VBg4o8)59eyf#4}14xIwP^9n48QXa%&{OEV zW-!z=^@9%%z6fb+f1EEZNBNiZsID)HeQi;hm-j?b${v6|h;eNJ94{__7^$P;CPya1 zFHr71rKOvrMu?Kg#NE@x3M@*?=YEu?nlQS8l9G}bnOUXF!WD?+UkrPEW#CkVF#xx) z$)XL#i=HvX{(eUKmgzm$_wQxYov|bIchJC0c<@V%5oU;H0 z1%<6@Et2iw#FYOpg8+R0m#-immWN9vmz)8Ln0Ob?pT~JM<(@}wZf@i6T=}`EsK^r=-S$0000NjoqzQA!ax=f%ynHTf7r)LI2_RPwF#-bIX2q?AMm;R{nO;NYE~ si '#808000', - 'comment_mysql' => '', - 'comment_ansi' => '', - 'comment_c' => '', - 'digit' => '', - 'digit_hex' => 'teal', - 'digit_integer' => 'teal', - 'digit_float' => 'aqua', - 'punct' => 'fuchsia', - 'alpha' => '', - 'alpha_columnType' => '#FF9900', - 'alpha_columnAttrib' => '#0000FF', - 'alpha_reservedWord' => '#990099', - 'alpha_functionName' => '#FF0000', - 'alpha_identifier' => 'black', - 'alpha_charset' => '#6495ed', - 'alpha_variable' => '#800000', - 'quote' => '#008000', - 'quote_double' => '', - 'quote_single' => '', - 'quote_backtick' => '' -); - /** * Chart colors */ diff --git a/phpMyAdmin/themes/original/sprites.lib.php b/phpMyAdmin/themes/original/sprites.lib.php index e52c608..ec57007 100644 --- a/phpMyAdmin/themes/original/sprites.lib.php +++ b/phpMyAdmin/themes/original/sprites.lib.php @@ -1,8 +1,19 @@ array( 'position' => '1', @@ -29,12 +40,12 @@ function PMA_sprites() { 'width' => '16', 'height' => '16' ), - 'b_comment' => array( + 'b_column_add' => array( 'position' => '6', 'width' => '16', 'height' => '16' ), - 'bd_browse' => array( + 'b_comment' => array( 'position' => '7', 'width' => '16', 'height' => '16' @@ -44,548 +55,603 @@ function PMA_sprites() { 'width' => '16', 'height' => '16' ), - 'bd_deltbl' => array( + 'b_deltbl' => array( 'position' => '9', 'width' => '16', 'height' => '16' ), - 'bd_drop' => array( + 'b_docs' => array( 'position' => '10', 'width' => '16', 'height' => '16' ), - 'bd_edit' => array( + 'b_drop' => array( 'position' => '11', 'width' => '16', 'height' => '16' ), - 'b_deltbl' => array( + 'b_edit' => array( 'position' => '12', 'width' => '16', 'height' => '16' ), - 'bd_empty' => array( + 'b_empty' => array( 'position' => '13', 'width' => '16', 'height' => '16' ), - 'bd_export' => array( + 'b_engine' => array( 'position' => '14', 'width' => '16', 'height' => '16' ), - 'bd_ftext' => array( + 'b_event_add' => array( 'position' => '15', 'width' => '16', 'height' => '16' ), - 'bd_index' => array( + 'b_events' => array( 'position' => '16', 'width' => '16', 'height' => '16' ), - 'bd_insrow' => array( + 'b_export' => array( 'position' => '17', 'width' => '16', 'height' => '16' ), - 'bd_nextpage' => array( + 'b_find_replace' => array( 'position' => '18', - 'width' => '8', - 'height' => '13' + 'width' => '16', + 'height' => '16' ), - 'b_docs' => array( + 'b_ftext' => array( 'position' => '19', 'width' => '16', 'height' => '16' ), - 'bd_primary' => array( + 'b_group' => array( 'position' => '20', 'width' => '16', 'height' => '16' ), - 'b_drop' => array( + 'b_help' => array( 'position' => '21', - 'width' => '16', - 'height' => '16' + 'width' => '11', + 'height' => '11' ), - 'bd_sbrowse' => array( + 'b_home' => array( 'position' => '22', - 'width' => '10', - 'height' => '10' + 'width' => '16', + 'height' => '16' ), - 'bd_select' => array( + 'b_import' => array( 'position' => '23', 'width' => '16', 'height' => '16' ), - 'bd_spatial' => array( + 'b_index' => array( 'position' => '24', 'width' => '16', 'height' => '16' ), - 'bd_unique' => array( + 'b_index_add' => array( 'position' => '25', 'width' => '16', 'height' => '16' ), - 'b_edit' => array( + 'b_info' => array( 'position' => '26', - 'width' => '16', - 'height' => '16' + 'width' => '11', + 'height' => '11' ), - 'b_empty' => array( + 'b_inline_edit' => array( 'position' => '27', 'width' => '16', 'height' => '16' ), - 'b_engine' => array( + 'b_insrow' => array( 'position' => '28', 'width' => '16', 'height' => '16' ), - 'b_event_add' => array( + 'b_minus' => array( 'position' => '29', - 'width' => '16', - 'height' => '16' + 'width' => '9', + 'height' => '9' ), - 'b_events' => array( + 'b_more' => array( 'position' => '30', 'width' => '16', 'height' => '16' ), - 'b_export' => array( + 'b_move' => array( 'position' => '31', 'width' => '16', 'height' => '16' ), - 'b_ftext' => array( + 'b_newdb' => array( 'position' => '32', 'width' => '16', 'height' => '16' ), - 'b_help' => array( + 'b_newtbl' => array( 'position' => '33', - 'width' => '11', - 'height' => '11' + 'width' => '16', + 'height' => '16' ), - 'b_home' => array( + 'b_nextpage' => array( 'position' => '34', 'width' => '16', 'height' => '16' ), - 'b_import' => array( + 'b_plus' => array( 'position' => '35', - 'width' => '16', - 'height' => '16' + 'width' => '9', + 'height' => '9' ), - 'b_index' => array( + 'b_primary' => array( 'position' => '36', 'width' => '16', 'height' => '16' ), - 'b_info' => array( + 'b_print' => array( 'position' => '37', - 'width' => '11', - 'height' => '11' + 'width' => '16', + 'height' => '16' ), - 'b_inline_edit' => array( + 'b_props' => array( 'position' => '38', 'width' => '16', 'height' => '16' ), - 'b_insrow' => array( + 'b_relations' => array( 'position' => '39', 'width' => '16', 'height' => '16' ), - 'b_minus' => array( + 'b_routine_add' => array( 'position' => '40', - 'width' => '9', - 'height' => '9' + 'width' => '16', + 'height' => '16' ), - 'b_more' => array( + 'b_routines' => array( 'position' => '41', 'width' => '16', 'height' => '16' ), - 'b_newdb' => array( + 'b_save' => array( 'position' => '42', 'width' => '16', 'height' => '16' ), - 'b_newtbl' => array( + 'b_sbrowse' => array( 'position' => '43', - 'width' => '16', - 'height' => '16' + 'width' => '10', + 'height' => '10' ), - 'b_nextpage' => array( + 'b_search' => array( 'position' => '44', 'width' => '16', 'height' => '16' ), - 'b_plus' => array( + 'b_selboard' => array( 'position' => '45', - 'width' => '9', - 'height' => '9' + 'width' => '16', + 'height' => '16' ), - 'b_primary' => array( + 'b_select' => array( 'position' => '46', 'width' => '16', 'height' => '16' ), - 'b_print' => array( + 'b_snewtbl' => array( 'position' => '47', - 'width' => '16', - 'height' => '16' + 'width' => '10', + 'height' => '10' ), - 'b_props' => array( + 'b_spatial' => array( 'position' => '48', 'width' => '16', 'height' => '16' ), - 'b_relations' => array( + 'b_sql' => array( 'position' => '49', 'width' => '16', 'height' => '16' ), - 'b_routine_add' => array( + 'b_sqlhelp' => array( 'position' => '50', 'width' => '16', 'height' => '16' ), - 'b_routines' => array( + 'b_table_add' => array( 'position' => '51', 'width' => '16', 'height' => '16' ), - 'b_save' => array( + 'b_tblanalyse' => array( 'position' => '52', 'width' => '16', 'height' => '16' ), - 'b_sbrowse' => array( + 'b_tblexport' => array( 'position' => '53', - 'width' => '10', - 'height' => '10' + 'width' => '16', + 'height' => '16' ), - 'b_search' => array( + 'b_tblimport' => array( 'position' => '54', 'width' => '16', 'height' => '16' ), - 'b_selboard' => array( + 'b_tblops' => array( 'position' => '55', 'width' => '16', 'height' => '16' ), - 'b_select' => array( + 'b_tbloptimize' => array( 'position' => '56', 'width' => '16', 'height' => '16' ), - 'b_snewtbl' => array( + 'b_tipp' => array( 'position' => '57', - 'width' => '10', - 'height' => '10' + 'width' => '16', + 'height' => '16' ), - 'b_spatial' => array( + 'b_trigger_add' => array( 'position' => '58', 'width' => '16', 'height' => '16' ), - 'b_sqlhelp' => array( + 'b_triggers' => array( 'position' => '59', 'width' => '16', 'height' => '16' ), - 'b_sql' => array( + 'b_undo' => array( 'position' => '60', 'width' => '16', 'height' => '16' ), - 'b_tblanalyse' => array( + 'b_unique' => array( 'position' => '61', 'width' => '16', 'height' => '16' ), - 'b_tblexport' => array( + 'b_usradd' => array( 'position' => '62', 'width' => '16', 'height' => '16' ), - 'b_tblimport' => array( + 'b_usrcheck' => array( 'position' => '63', 'width' => '16', 'height' => '16' ), - 'b_tblops' => array( + 'b_usrdrop' => array( 'position' => '64', 'width' => '16', 'height' => '16' ), - 'b_tbloptimize' => array( + 'b_usredit' => array( 'position' => '65', 'width' => '16', 'height' => '16' ), - 'b_tipp' => array( + 'b_usrlist' => array( 'position' => '66', 'width' => '16', 'height' => '16' ), - 'b_trigger_add' => array( + 'b_view' => array( 'position' => '67', 'width' => '16', 'height' => '16' ), - 'b_triggers' => array( + 'b_view_add' => array( 'position' => '68', 'width' => '16', 'height' => '16' ), - 'b_unique' => array( + 'b_views' => array( 'position' => '69', 'width' => '16', 'height' => '16' ), - 'b_usradd' => array( + 'bd_browse' => array( 'position' => '70', 'width' => '16', 'height' => '16' ), - 'b_usrcheck' => array( + 'bd_deltbl' => array( 'position' => '71', 'width' => '16', 'height' => '16' ), - 'b_usrdrop' => array( + 'bd_drop' => array( 'position' => '72', 'width' => '16', 'height' => '16' ), - 'b_usredit' => array( + 'bd_edit' => array( 'position' => '73', 'width' => '16', 'height' => '16' ), - 'b_usrlist' => array( + 'bd_empty' => array( 'position' => '74', 'width' => '16', 'height' => '16' ), - 'b_view' => array( + 'bd_export' => array( 'position' => '75', 'width' => '16', 'height' => '16' ), - 'b_views' => array( + 'bd_ftext' => array( 'position' => '76', 'width' => '16', 'height' => '16' ), - 'col_drop' => array( + 'bd_index' => array( 'position' => '77', 'width' => '16', 'height' => '16' ), - 'docs_menu_bg' => array( + 'bd_insrow' => array( 'position' => '78', - 'width' => '2', - 'height' => '2' - ), - 'eye_grey' => array( - 'position' => '79', 'width' => '16', 'height' => '16' ), - 'eye' => array( + 'bd_nextpage' => array( + 'position' => '79', + 'width' => '8', + 'height' => '13' + ), + 'bd_primary' => array( 'position' => '80', 'width' => '16', 'height' => '16' ), - 'item_ltr' => array( + 'bd_sbrowse' => array( 'position' => '81', - 'width' => '5', - 'height' => '9' + 'width' => '10', + 'height' => '10' ), - 'item_rtl' => array( + 'bd_select' => array( 'position' => '82', - 'width' => '5', - 'height' => '9' + 'width' => '16', + 'height' => '16' ), - 'more' => array( + 'bd_spatial' => array( 'position' => '83', - 'width' => '13', + 'width' => '16', 'height' => '16' ), - 'new_data_hovered' => array( + 'bd_unique' => array( 'position' => '84', 'width' => '16', 'height' => '16' ), - 'new_data' => array( + 'col_drop' => array( 'position' => '85', 'width' => '16', 'height' => '16' ), - 'new_data_selected_hovered' => array( + 'eye' => array( 'position' => '86', 'width' => '16', 'height' => '16' ), - 'new_data_selected' => array( + 'eye_grey' => array( 'position' => '87', 'width' => '16', 'height' => '16' ), - 'new_struct_hovered' => array( + 'lightbulb' => array( 'position' => '88', 'width' => '16', 'height' => '16' ), - 'new_struct' => array( + 'lightbulb_off' => array( 'position' => '89', 'width' => '16', 'height' => '16' ), - 'new_struct_selected_hovered' => array( + 'more' => array( 'position' => '90', - 'width' => '16', + 'width' => '13', 'height' => '16' ), - 'new_struct_selected' => array( + 'new_data' => array( 'position' => '91', 'width' => '16', 'height' => '16' ), - 's_asci' => array( + 'new_data_hovered' => array( 'position' => '92', 'width' => '16', 'height' => '16' ), - 's_asc' => array( + 'new_data_selected' => array( 'position' => '93', - 'width' => '11', - 'height' => '9' + 'width' => '16', + 'height' => '16' ), - 's_cancel' => array( + 'new_data_selected_hovered' => array( 'position' => '94', 'width' => '16', 'height' => '16' ), - 's_cog' => array( + 'new_struct' => array( 'position' => '95', 'width' => '16', 'height' => '16' ), - 's_db' => array( + 'new_struct_hovered' => array( 'position' => '96', 'width' => '16', 'height' => '16' ), - 's_desc' => array( + 'new_struct_selected' => array( 'position' => '97', + 'width' => '16', + 'height' => '16' + ), + 'new_struct_selected_hovered' => array( + 'position' => '98', + 'width' => '16', + 'height' => '16' + ), + 'pause' => array( + 'position' => '99', + 'width' => '16', + 'height' => '16' + ), + 'play' => array( + 'position' => '100', + 'width' => '16', + 'height' => '16' + ), + 's_asc' => array( + 'position' => '101', 'width' => '11', 'height' => '9' ), - 's_error2' => array( - 'position' => '98', + 's_asci' => array( + 'position' => '102', + 'width' => '16', + 'height' => '16' + ), + 's_cancel' => array( + 'position' => '103', + 'width' => '16', + 'height' => '16' + ), + 's_cog' => array( + 'position' => '104', + 'width' => '16', + 'height' => '16' + ), + 's_db' => array( + 'position' => '105', + 'width' => '16', + 'height' => '16' + ), + 's_desc' => array( + 'position' => '106', 'width' => '11', - 'height' => '11' + 'height' => '9' ), 's_error' => array( - 'position' => '99', + 'position' => '107', 'width' => '16', 'height' => '16' ), + 's_error2' => array( + 'position' => '108', + 'width' => '11', + 'height' => '11' + ), 's_host' => array( - 'position' => '100', + 'position' => '109', 'width' => '16', 'height' => '16' ), + 's_info' => array( + 'position' => '110', + 'width' => '11', + 'height' => '11' + ), 's_lang' => array( - 'position' => '101', + 'position' => '111', 'width' => '16', 'height' => '16' ), 's_loggoff' => array( - 'position' => '102', + 'position' => '112', 'width' => '16', 'height' => '16' ), 's_notice' => array( - 'position' => '103', + 'position' => '113', 'width' => '16', 'height' => '16' ), 's_passwd' => array( - 'position' => '104', + 'position' => '114', 'width' => '16', 'height' => '16' ), 's_really' => array( - 'position' => '105', + 'position' => '115', 'width' => '11', 'height' => '11' ), 's_reload' => array( - 'position' => '106', + 'position' => '116', 'width' => '16', 'height' => '16' ), 's_replication' => array( - 'position' => '107', + 'position' => '117', 'width' => '16', 'height' => '16' ), 's_rights' => array( - 'position' => '108', + 'position' => '118', 'width' => '16', 'height' => '16' ), 's_sortable' => array( - 'position' => '109', + 'position' => '119', 'width' => '11', 'height' => '15' ), 's_status' => array( - 'position' => '110', + 'position' => '120', 'width' => '16', 'height' => '16' ), 's_success' => array( - 'position' => '111', + 'position' => '121', 'width' => '16', 'height' => '16' ), 's_sync' => array( - 'position' => '112', + 'position' => '122', 'width' => '16', 'height' => '16' ), 's_tbl' => array( - 'position' => '113', + 'position' => '123', 'width' => '16', 'height' => '16' ), 's_theme' => array( - 'position' => '114', + 'position' => '124', + 'width' => '16', + 'height' => '16' + ), + 's_top' => array( + 'position' => '125', 'width' => '16', 'height' => '16' ), 's_vars' => array( - 'position' => '115', + 'position' => '126', 'width' => '16', 'height' => '16' ), 's_views' => array( - 'position' => '116', + 'position' => '127', 'width' => '10', 'height' => '10' ), 'window-new' => array( - 'position' => '117', + 'position' => '128', 'width' => '16', 'height' => '16' ), diff --git a/phpMyAdmin/themes/pmahomme/css/codemirror.css.php b/phpMyAdmin/themes/pmahomme/css/codemirror.css.php new file mode 100644 index 0000000..6a3fe36 --- /dev/null +++ b/phpMyAdmin/themes/pmahomme/css/codemirror.css.php @@ -0,0 +1,303 @@ + + +/* PADDING */ + +.CodeMirror-lines { + padding: 4px 0; /* Vertical padding around content */ +} +.CodeMirror pre { + padding: 0 4px; /* Horizontal padding of content */ +} + +.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + background-color: white; /* The little square between H and V scrollbars */ +} + +/* GUTTER */ + +.CodeMirror-gutters { + border-right: 1px solid #ddd; + background-color: #f7f7f7; + white-space: nowrap; +} +.CodeMirror-linenumbers {} +.CodeMirror-linenumber { + padding: 0 3px 0 5px; + min-width: 20px; + text-align: right; + color: #999; +} + +/* CURSOR */ + +.CodeMirror div.CodeMirror-cursor { + border-left: 1px solid black; + z-index: 3; +} +/* Shown when moving in bi-directional text */ +.CodeMirror div.CodeMirror-secondarycursor { + border-left: 1px solid silver; +} +.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor { + width: auto; + border: 0; + background: #7e7; + z-index: 1; +} +/* Can style cursor different in overwrite (non-insert) mode */ +.CodeMirror div.CodeMirror-cursor.CodeMirror-overwrite {} + +.cm-tab { display: inline-block; } + +/* DEFAULT THEME */ + +.cm-s-default .cm-keyword {color: #708;} +.cm-s-default .cm-atom {color: #219;} +.cm-s-default .cm-number {color: #164;} +.cm-s-default .cm-def {color: #00f;} +.cm-s-default .cm-variable {color: black;} +.cm-s-default .cm-variable-2 {color: #05a;} +.cm-s-default .cm-variable-3 {color: #085;} +.cm-s-default .cm-property {color: black;} +.cm-s-default .cm-operator {color: black;} +.cm-s-default .cm-comment {color: #a50;} +.cm-s-default .cm-string {color: #a11;} +.cm-s-default .cm-string-2 {color: #f50;} +.cm-s-default .cm-meta {color: #555;} +.cm-s-default .cm-error {color: #f00;} +.cm-s-default .cm-qualifier {color: #555;} +.cm-s-default .cm-builtin {color: #30a;} +.cm-s-default .cm-bracket {color: #997;} +.cm-s-default .cm-tag {color: #170;} +.cm-s-default .cm-attribute {color: #00c;} +.cm-s-default .cm-header {color: blue;} +.cm-s-default .cm-quote {color: #090;} +.cm-s-default .cm-hr {color: #999;} +.cm-s-default .cm-link {color: #00c;} + +.cm-negative {color: #d44;} +.cm-positive {color: #292;} +.cm-header, .cm-strong {font-weight: bold;} +.cm-em {font-style: italic;} +.cm-link {text-decoration: underline;} + +.cm-invalidchar {color: #f00;} + +div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} +div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} + +/* STOP */ + +/* The rest of this file contains styles related to the mechanics of + the editor. You probably shouldn't touch them. */ + +.CodeMirror { + line-height: 1; + position: relative; + overflow: hidden; + background: white; + color: black; + font-family: monospace; + height: em; +} + +#inline_editor_outer .CodeMirror { + height: em; +} + +.CodeMirror-scroll { + /* 30px is the magic margin used to hide the element's real scrollbars */ + /* See overflow: hidden in .CodeMirror */ + margin-bottom: -30px; margin-right: -30px; + padding-bottom: 30px; padding-right: 30px; + height: 100%; + outline: none; /* Prevent dragging from highlighting the element */ + position: relative; +} +.CodeMirror-sizer { + position: relative; +} + +/* The fake, visible scrollbars. Used to force redraw during scrolling + before actuall scrolling happens, thus preventing shaking and + flickering artifacts. */ +.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + position: absolute; + z-index: 6; + display: none; +} +.CodeMirror-vscrollbar { + right: 0; top: 0; + overflow-x: hidden; + overflow-y: scroll; +} +.CodeMirror-hscrollbar { + bottom: 0; left: 0; + overflow-y: hidden; + overflow-x: scroll; +} +.CodeMirror-scrollbar-filler { + right: 0; bottom: 0; +} +.CodeMirror-gutter-filler { + left: 0; bottom: 0; +} + +.CodeMirror-gutters { + position: absolute; left: 0; top: 0; + padding-bottom: 30px; + z-index: 3; +} +.CodeMirror-gutter { + white-space: normal; + height: 100%; + padding-bottom: 30px; + margin-bottom: -32px; + display: inline-block; + /* Hack to make IE7 behave */ + *zoom:1; + *display:inline; +} +.CodeMirror-gutter-elt { + position: absolute; + cursor: default; + z-index: 4; +} + +.CodeMirror-lines { + cursor: text; +} +.CodeMirror pre { + /* Reset some styles that the rest of the page might have set */ + -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; + border-width: 0; + background: transparent; + font-family: inherit; + font-size: inherit; + margin: 0; + white-space: pre; + word-wrap: normal; + line-height: inherit; + color: inherit; + z-index: 2; + position: relative; + overflow: visible; +} +.CodeMirror-wrap pre { + word-wrap: break-word; + white-space: pre-wrap; + word-break: normal; +} +.CodeMirror-code pre { + border-right: 30px solid transparent; + width: -webkit-fit-content; + width: -moz-fit-content; + width: fit-content; +} +.CodeMirror-wrap .CodeMirror-code pre { + border-right: none; + width: auto; +} +.CodeMirror-linebackground { + position: absolute; + left: 0; right: 0; top: 0; bottom: 0; + z-index: 0; +} + +.CodeMirror-linewidget { + position: relative; + z-index: 2; + overflow: auto; +} + +.CodeMirror-widget { + display: inline-block; +} + +.CodeMirror-wrap .CodeMirror-scroll { + overflow-x: hidden; +} + +.CodeMirror-measure { + position: absolute; + width: 100%; height: 0px; + overflow: hidden; + visibility: hidden; +} +.CodeMirror-measure pre { position: static; } + +.CodeMirror div.CodeMirror-cursor { + position: absolute; + visibility: hidden; + border-right: none; + width: 0; +} +.CodeMirror-focused div.CodeMirror-cursor { + visibility: visible; +} + +.CodeMirror-selected { background: #d9d9d9; } +.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } + +.cm-searching { + background: #ffa; + background: rgba(255, 255, 0, .4); +} + +/* IE7 hack to prevent it from returning funny offsetTops on the spans */ +.CodeMirror span { *vertical-align: text-bottom; } + +@media print { + /* Hide the cursor when printing */ + .CodeMirror div.CodeMirror-cursor { + visibility: hidden; + } +} + +span.cm-keyword, span.cm-statement-verb { + color: #909; +} +span.cm-variable { + color: black; +} +span.cm-comment { + color: #808000; +} +span.cm-mysql-string { + color: #008000; +} +span.cm-operator { + color: fuchsia; +} +span.cm-mysql-word { + color: black; +} +span.cm-builtin { + color: #f00; +} +span.cm-variable-2 { + color: #f90; +} +span.cm-variable-3 { + color: #00f; +} +span.cm-separator { + color: fuchsia; +} +span.cm-number { + color: teal; +} diff --git a/phpMyAdmin/themes/pmahomme/css/common.css.php b/phpMyAdmin/themes/pmahomme/css/common.css.php new file mode 100644 index 0000000..46ba547 --- /dev/null +++ b/phpMyAdmin/themes/pmahomme/css/common.css.php @@ -0,0 +1,2795 @@ + +/******************************************************************************/ + +/* general tags */ +html { + font-size: getFontSize(); ?> +} + +input, +select, +textarea { + font-size: 1em; +} + + +body { + + font-family: ; + + padding: 0; + margin: 0; + margin-: 240px; + color: #444; + background: #fff; +} + +body#loginform { + margin: 0; +} + +#page_content { + margin: 0 .5em; +} + + +textarea, +tt, +pre, +code { + font-family: ; +} + + + +h1 { + font-size: 140%; + font-weight: bold; +} + +h2 { + font-size: 2em; + font-weight: normal; + text-shadow: 0 1px 0 #fff; + padding: 10px 0 10px; + padding-: 3px; + color: #777; +} + +/* Hiding icons in the page titles */ +h2 img { + display: none; +} + +h2 a img { + display: inline; +} + +.data, +.data_full_width { + margin: 0 0 12px; +} + +.data_full_width { + width: 100%; +} + +#table_results td.data { +border-right: 1px solid #bbb; +} + +h3 { + font-weight: bold; +} + +a, +a:link, +a:visited, +a:active { + text-decoration: none; + color: #235a81; + cursor: pointer; + outline: none; + +} + +a:hover { + text-decoration: underline; + color: #235a81; +} + +#initials_table { + background: #f3f3f3; + border: 1px solid #aaa; + margin-bottom: 10px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; +} + +#initials_table td { + padding: 8px !important; +} + +#initials_table a { + border: 1px solid #aaa; + background: #fff; + padding: 4px 8px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; + getCssGradient('ffffff', 'cccccc'); ?> +} + +dfn { + font-style: normal; +} + +dfn:hover { + font-style: normal; + cursor: help; +} + +th { + font-weight: bold; + color: ; + background: #f3f3f3; + getCssGradient('ffffff', 'cccccc'); ?> +} + +a img { + border: 0; +} + +hr { + color: ; + background-color: ; + border: 0; + height: 1px; +} + +form { + padding: 0; + margin: 0; + display: inline; +} + +input[type=text], +input[type=password], +input[type=number], +input[type=date] { + border-radius: 2px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + + box-shadow: 0 1px 2px #ddd; + -moz-box-shadow: 0 1px 2px #ddd; + -webkit-box-shadow: 0 1px 2px #ddd; + + background: white; + border: 1px solid #aaa; + color: #555; + padding: 4px; + margin: 6px; + +} + +input[type=submit], +button[type=submit]:not(.mult_submit) { + font-weight: bold !important; +} + +input[type=submit], +button[type=submit]:not(.mult_submit), +input[type=reset], +input[name=submit_reset], +input.button { + margin-left: 14px; + border: 1px solid #aaa; + padding: 3px 7px; + color: #111; + text-decoration: none; + background: #ddd; + + border-radius: 12px; + -webkit-border-radius: 12px; + -moz-border-radius: 12px; + + text-shadow: 0 1px 0 #fff; + + getCssGradient('ffffff', 'cccccc'); ?> +} + +input[type=submit]:hover, +button[type=submit]:not(.mult_submit):hover, +input[type=reset]:hover, +input[name=submit_reset]:hover, +input.button:hover { + position: relative; + getCssGradient('cccccc', 'dddddd'); ?> + cursor: pointer; +} + +input[type=submit]:active, +button[type=submit]:not(.mult_submit):active, +input[type=reset]:active, +input[name=submit_reset]:active, +input.button:active { + position: relative; + top: 1px; + left: 1px; +} + +textarea { + overflow: visible; + height: em; +} + +textarea.char { + height: em; +} + +fieldset { + margin-top: 1em; + border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + -webkit-border-radius: 4px 4px 0 0; + border: #aaa solid 1px; + padding: 1.5em; + background: #eee; + text-shadow: 1px 1px 2px #fff inset; + -moz-box-shadow: 1px 1px 2px #fff inset; + -webkit-box-shadow: 1px 1px 2px #fff inset; + box-shadow: 1px 1px 2px #fff inset; +} + +fieldset fieldset { + margin: .8em; + background: #fff; + border: 1px solid #aaa; + background: #E8E8E8; + +} + +fieldset legend { + font-weight: bold; + color: #444; + padding: 5px 10px; + border-radius: 2px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + border: 1px solid #aaa; + background-color: #fff; + -moz-box-shadow: 3px 3px 15px #bbb; + -webkit-box-shadow: 3px 3px 15px #bbb; + box-shadow: 3px 3px 15px #bbb; + max-width: 100%; +} + +.some-margin { + margin: 1.5em; +} + +/* buttons in some browsers (eg. Konqueror) are block elements, + this breaks design */ +button { + display: inline; +} + +table caption, +table th, +table td { + padding: .3em; + margin: .1em; + vertical-align: top; + text-shadow: 0 1px 0 #fff; +} + +/* 3.4 */ +table { + border-collapse: collapse; +} + +th { + border-right: 1px solid #fff; + text-align: left; +} + + +img, +button { + vertical-align: middle; +} + +input[type="checkbox"], +input[type="radio"] { + vertical-align: -11%; +} + + +select { + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + border-radius: 2px; + + -moz-box-shadow: 0 1px 2px #ddd; + -webkit-box-shadow: 0 1px 2px #ddd; + box-shadow: 0 1px 2px #ddd; + + border: 1px solid #aaa; + color: #333; + padding: 3px; + background: white; +} + +select[multiple] { + getCssGradient('ffffff', 'f2f2f2'); ?> +} + +/******************************************************************************/ +/* classes */ +.clearfloat { + clear: both; +} + +.floatleft { + float: ; + margin-: 1em; +} + +.floatright { + float: ; +} + +.center { + text-align: center; +} + +table.nospacing { + border-spacing: 0; +} + +table.nopadding tr th, table.nopadding tr td { + padding: 0; +} + +th.left, td.left { + text-align: left; +} + +th.center, td.center { + text-align: center; +} + +th.right, td.right { + text-align: right; +} + +tr.vtop th, tr.vtop td, th.vtop, td.vtop { + vertical-align: top; +} + +tr.vmiddle th, tr.vmiddle td, th.vmiddle, td.vmiddle { + vertical-align: middle; +} + +tr.vbottom th, tr.vbottom td, th.vbottom, td.vbottom { + vertical-align: bottom; +} + +.paddingtop { + padding-top: 1em; +} + +.separator { + color: #fff; + text-shadow: 0 1px 0 #000; +} + +div.tools { + /* border: 1px solid #000; */ + padding: .2em; +} + +div.tools a { + color: #3a7ead !important; +} + +div.tools, +fieldset.tblFooters { + margin-top: 0; + margin-bottom: .5em; + /* avoid a thick line since this should be used under another fieldset */ + border-top: 0; + text-align: ; + float: none; + clear: both; + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 5px; +} + +div.null_div { + height: 20px; + text-align: center; + font-style: normal; + min-width: 50px; +} + +fieldset .formelement { + float: ; + margin-: .5em; + /* IE */ + white-space: nowrap; +} + +/* revert for Gecko */ +fieldset div[class=formelement] { + white-space: normal; +} + +button.mult_submit { + border: none; + background-color: transparent; +} + +/* odd items 1,3,5,7,... */ +table tr.odd th, +.odd { + background: #fff; + getCssIEClearFilter(); ?> +} + +/* even items 2,4,6,8,... */ +/* (tested on CRTs and ACLs) */ +table tr.even th, +.even { + background: #DFDFDF; + getCssIEClearFilter(); ?> +} + +/* odd table rows 1,3,5,7,... */ +table tr.odd th, +table tr.odd, +table tr.even th, +table tr.even { + text-align: ; +} + + +/* marked table rows */ +td.marked, +table tr.marked td, +table tr.marked th, +table tr.marked { + getCssGradient('ced6df', 'b6c6d7'); ?> + color: ; +} + + + +/* hovered items */ +.odd:hover, +.even:hover, +.hover { + getCssGradient('ced6df', 'b6c6d7'); ?> + color: ; +} + +/* hovered table rows */ +table tr.odd:hover th, +table tr.even:hover th, +table tr.hover th { + getCssGradient('ced6df', 'b6c6d7'); ?> + color: ; +} + + +/** + * marks table rows/cells if the db field is in a where condition + */ +.condition { + border-color: !important; +} + +th.condition { + border-width: 1px 1px 0 1px; + border-style: solid; +} + +td.condition { + border-width: 0 1px 0 1px; + border-style: solid; +} + +tr:last-child td.condition { + border-width: 0 1px 1px 1px; +} + + +/* for first th which must have right border set (ltr only) */ +.before-condition { + border-right: 1px solid ; +} + + +/** + * cells with the value NULL + */ +td.null { + font-style: italic; + text-align: ; +} + +table .valueHeader { + text-align: ; + white-space: normal; +} +table .value { + text-align: ; + white-space: normal; +} +/* IE doesnt handles 'pre' right */ +table [class=value] { + white-space: normal; +} + + + +.value { + font-family: ; +} + +.attention { + color: red; + font-weight: bold; +} +.allfine { + color: green; +} + + +img.lightbulb { + cursor: pointer; +} + +.pdflayout { + overflow: hidden; + clip: inherit; + background-color: #fff; + display: none; + border: 1px solid #000; + position: relative; +} + +.pdflayout_table { + background: #D3DCE3; + color: #000; + overflow: hidden; + clip: inherit; + z-index: 2; + display: inline; + visibility: inherit; + cursor: move; + position: absolute; + font-size: 80%; + border: 1px dashed #000; +} + +/* Doc links in SQL */ +.cm-sql-doc { + text-decoration: none; + border-bottom: 1px dotted #000; + color: inherit !important; +} + +/* no extra space in table cells */ +td .icon { + margin: 0; +} + +.selectallarrow { + margin-: .3em; + margin-: .6em; +} + +/* message boxes: error, confirmation */ +#pma_errors, #pma_demo { + padding: 0 0.5em; +} + +.success h1, +.notice h1, +div.error h1 { + border-bottom: 2px solid; + font-weight: bold; + text-align: ; + margin: 0 0 .2em 0; +} + +div.success, +div.notice, +div.error { + margin: .5em 0 1.3em; + border: 1px solid; + background-repeat: no-repeat; + + background-position: 10px 50%; + padding: 10px 10px 10px 10px; + + background-position: 99% 50%; + padding: 10px 35px 10px 10px; + + + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; + + -moz-box-shadow: 0 1px 1px #fff inset; + -webkit-box-shadow: 0 1px 1px #fff inset; + box-shadow: 0 1px 1px #fff inset; +} + +.success a, +.notice a, +.error a { + text-decoration: underline; +} + +.success { + color: #000; + background-color: #ebf8a4; +} + +h1.success, +div.success { + border-color: #a2d246; +} +.success h1 { + border-color: #00FF00; +} + +.notice { + color: #000; + background-color: #e8eef1; +} + +h1.notice, +div.notice { + border-color: #3a6c7e; +} + +.notice h1 { + border-color: #ffb10a; +} + +.error { + border: 1px solid maroon !important; + color: #000; + background: pink; +} + +h1.error, +div.error { + border-color: #333; +} + +div.error h1 { + border-color: #ff0000; +} + +.confirmation { + color: #000; + background-color: pink; +} + +fieldset.confirmation { +} + +fieldset.confirmation legend { +} + +/* end messageboxes */ + +.tblcomment { + font-size: 70%; + font-weight: normal; + color: #000099; +} + +.tblHeaders { + font-weight: bold; + color: ; + background: ; +} + +div.tools, +.tblFooters { + font-weight: normal; + color: ; + background: ; +} + +.tblHeaders a:link, +.tblHeaders a:active, +.tblHeaders a:visited, +div.tools a:link, +div.tools a:visited, +div.tools a:active, +.tblFooters a:link, +.tblFooters a:active, +.tblFooters a:visited { + color: #0000FF; +} + +.tblHeaders a:hover, +div.tools a:hover, +.tblFooters a:hover { + color: #FF0000; +} + +/* forbidden, no privileges */ +.noPrivileges { + color: #FF0000; + font-weight: bold; +} + +/* disabled text */ +.disabled, +.disabled a:link, +.disabled a:active, +.disabled a:visited { + color: #666; +} + +.disabled a:hover { + color: #666; + text-decoration: none; +} + +tr.disabled td, +td.disabled { + background-color: #f3f3f3; + color: #aaa; +} + +.nowrap { + white-space: nowrap; +} + +/** + * login form + */ +body#loginform h1, +body#loginform a.logo { + display: block; + text-align: center; +} + +body#loginform { + margin-top: 1em; + text-align: center; +} + +body#loginform div.container { + text-align: ; + width: 30em; + margin: 0 auto; +} + +form.login label { + float: ; + width: 10em; + font-weight: bolder; +} + +.commented_column { + border-bottom: 1px dashed #000; +} + +.column_attribute { + font-size: 70%; +} + +/******************************************************************************/ +/* specific elements */ + +/* topmenu */ +#topmenu a { + text-shadow: 0 1px 0 #fff; +} + +#topmenu .error { + background: #eee;border: 0 !important;color: #aaa; +} + +ul#topmenu, +ul#topmenu2, +ul.tabs { + font-weight: bold; + list-style-type: none; + margin: 0; + padding: 0; + +} + +ul#topmenu2 { + margin: .25em .5em 0; + height: 2em; + clear: both; +} + +ul#topmenu li, +ul#topmenu2 li { + float: ; + margin: 0; + vertical-align: middle; +} + +#topmenu img, +#topmenu2 img { + margin-right: .5em; + vertical-align: -3px; +} + +.menucontainer { + getCssGradient('ffffff', 'dcdcdc'); ?> + border-top: 1px solid #aaa; +} + +/* default tab styles */ +.tabactive { + background: #fff !important; +} + +ul#topmenu2 a { + display: block; + margin: 7px 6px 7px; + margin-: 0; + padding: 4px 10px; + white-space: nowrap; + border: 1px solid #ddd; + border-radius: 20px; + -moz-border-radius: 20px; + -webkit-border-radius: 20px; + background: #f2f2f2; + +} + +fieldset.caution a { + color: #FF0000; +} +fieldset.caution a:hover { + color: #fff; + background-color: #FF0000; +} + +#topmenu { + margin-top: .5em; + padding: .1em .3em; +} + +ul#topmenu ul { + -moz-box-shadow: 1px 1px 6px #ddd; + -webkit-box-shadow: 2px 2px 3px #666; + box-shadow: 2px 2px 3px #666; +} + +ul#topmenu ul.only { + : 0; +} + +ul#topmenu > li { + border-right: 1px solid #fff; + border-left: 1px solid #ccc; +} + +/* default tab styles */ +ul#topmenu a, +ul#topmenu span { + padding: .6em; +} + +ul#topmenu ul a { + border-width: 1pt 0 0 0; + -moz-border-radius: 0; + -webkit-border-radius: 0; + border-radius: 0; +} + +ul#topmenu ul li:first-child a { + border-width: 0; +} + +/* enabled hover/active tabs */ +ul#topmenu > li > a:hover, +ul#topmenu > li > .tabactive { + text-decoration: none; +} + +ul#topmenu ul a:hover, +ul#topmenu ul .tabactive { + text-decoration: none; +} + +ul#topmenu a.tab:hover, +ul#topmenu .tabactive { + /* background-color: ; */ +} + +ul#topmenu2 a.tab:hover, +ul#topmenu2 a.tabactive { + background-color: ; + border-radius: .3em; + -moz-border-radius: .3em; + -webkit-border-radius: .3em; + text-decoration: none; +} + +/* to be able to cancel the bottom border, use
  • */ +ul#topmenu > li.active { + /* border-bottom: 0pt solid ; */ + border-right: 0; +} +/* end topmenu */ + +/* zoom search */ +div#dataDisplay input, +div#dataDisplay select { + margin: 0; + margin-: .5em; +} +div#dataDisplay th { + line-height: 2em; +} + +/* Calendar */ +table.calendar { + width: 100%; +} +table.calendar td { + text-align: center; +} +table.calendar td a { + display: block; +} + +table.calendar td a:hover { + background-color: #CCFFCC; +} + +table.calendar th { + background-color: #D3DCE3; +} + +table.calendar td.selected { + background-color: #FFCC99; +} + +img.calendar { + border: none; +} +form.clock { + text-align: center; +} +/* end Calendar */ + + +/* table stats */ +div#tablestatistics table { + float: ; + margin-bottom: .5em; + margin-: 1.5em; + margin-top: .5em; + min-width: 16em; +} + +/* END table stats */ + + +/* server privileges */ +#tableuserrights td, +#tablespecificuserrights td, +#tabledatabases td { + vertical-align: middle; +} +/* END server privileges */ + + +/* Heading */ +#topmenucontainer { + padding-: 1em; + width: 100%; +} + +#serverinfo { + border-bottom: 1px solid #fff; + background: #888; + padding: .3em .9em; + padding-: 2.2em; + text-shadow: 0 1px 0 #000; + width: 10000px; + overflow: hidden; +} + +#serverinfo .item { + white-space: nowrap; + color: #fff; +} + +#goto_pagetop { + position: fixed; + padding: .25em .25em .2em; + top: 0; + : 0; + z-index: 900; + background: #888; +} + +#span_table_comment { + font-weight: bold; + font-style: italic; + white-space: nowrap; + margin-left: 10px; + color: #D6D6D6; + text-shadow: none; +} + +#serverinfo img { + margin: 0 .1em 0; + margin-: .2em; +} + + +#textSQLDUMP { + width: 95%; + height: 95%; + font-family: Consolas, "Courier New", Courier, mono; + font-size: 110%; +} + +#TooltipContainer { + position: absolute; + z-index: 99; + width: 20em; + height: auto; + overflow: visible; + visibility: hidden; + background-color: #ffffcc; + color: #006600; + border: .1em solid #000; + padding: .5em; +} + +/* user privileges */ +#fieldset_add_user_login div.item { + border-bottom: 1px solid silver; + padding-bottom: .3em; + margin-bottom: .3em; +} + +#fieldset_add_user_login label { + float: ; + display: block; + width: 10em; + max-width: 100%; + text-align: ; + padding-: .5em; +} + +#fieldset_add_user_login span.options #select_pred_username, +#fieldset_add_user_login span.options #select_pred_hostname, +#fieldset_add_user_login span.options #select_pred_password { + width: 100%; + max-width: 100%; +} + +#fieldset_add_user_login span.options { + float: ; + display: block; + width: 12em; + max-width: 100%; + padding-: .5em; +} + +#fieldset_add_user_login input { + width: 12em; + clear: ; + max-width: 100%; +} + +#fieldset_add_user_login span.options input { + width: auto; +} + +#fieldset_user_priv div.item { + float: ; + width: 9em; + max-width: 100%; +} + +#fieldset_user_priv div.item div.item { + float: none; +} + +#fieldset_user_priv div.item label { + white-space: nowrap; +} + +#fieldset_user_priv div.item select { + width: 100%; +} + +#fieldset_user_global_rights fieldset { + float: ; +} + +#fieldset_user_group_rights fieldset { + float: ; +} + +#fieldset_user_global_rights legend input { + margin-: 2em; +} +/* END user privileges */ + + +/* serverstatus */ + +.linkElem:hover { + text-decoration: underline; + color: #235a81; + cursor: pointer; +} + +h3#serverstatusqueries span { + font-size: 60%; + display: inline; +} + +img.sortableIcon { + float: ; + background-repeat: no-repeat; + margin: 0; +} + +.buttonlinks { + float: ; + white-space: nowrap; +} + +/* Also used for the variables page */ +fieldset#tableFilter { + margin-bottom: 1em; +} + +div#serverStatusTabs { + margin-top: 1em; +} + +caption a.top { + float: ; +} + +div#serverstatusquerieschart { + float: ; + width: 500px; + height: 350px; + padding-: 30px; +} + +table#serverstatusqueriesdetails, +table#serverstatustraffic { + float: ; +} + +table#serverstatusqueriesdetails th { + min-width: 35px; +} + +table#serverstatusvariables { + width: 100%; + margin-bottom: 1em; +} +table#serverstatusvariables .name { + width: 18em; + white-space: nowrap; +} +table#serverstatusvariables .value { + width: 6em; +} +table#serverstatusconnections { + float: ; + margin-: 30px; +} + +div#serverstatus table tbody td.descr a, +div#serverstatus table .tblFooters a { + white-space: nowrap; +} + +div.liveChart { + clear: both; + min-width: 500px; + height: 400px; + padding-bottom: 80px; +} + +#addChartDialog input[type="text"] { + margin: 0; + padding: 3px; +} + +div#chartVariableSettings { + border: 1px solid #ddd; + background-color: #E6E6E6; + margin-left: 10px; +} + +table#chartGrid div.monitorChart { + background: #EBEBEB; +} + +div#serverstatus div.tabLinks { + float: ; + padding-bottom: 10px; +} + +.popupContent { + display: none; + position: absolute; + border: 1px solid #CCC; + margin: 0; + padding: 3px; + -moz-box-shadow: 2px 2px 3px #666; + -webkit-box-shadow: 2px 2px 3px #666; + box-shadow: 2px 2px 3px #666; + background-color: #fff; + z-index: 2; +} + +div#logTable { + padding-top: 10px; + clear: both; +} + +div#logTable table { + width: 100%; +} + +div#queryAnalyzerDialog { + min-width: 700px; +} + +div#queryAnalyzerDialog div.CodeMirror-scroll { + height: auto; +} + +div#queryAnalyzerDialog div#queryProfiling { + height: 300px; +} + +div#queryAnalyzerDialog td.explain { + width: 250px; +} + +div#queryAnalyzerDialog table.queryNums { + display: none; + border: 0; + text-align: left; +} + +.smallIndent { + padding-: 7px; +} + +/* end serverstatus */ + +/* server variables */ +#serverVariables { + min-width: 30em; +} +#serverVariables .var-row > div { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + line-height: 2em; +} +#serverVariables .var-header { + color: ; + background: #f3f3f3; + getCssGradient('ffffff', 'cccccc'); ?> + font-weight: bold; +} +#serverVariables .var-header .var-value { + text-align: ; +} +#serverVariables .var-row { + padding: 0.5em; + min-height: 18px; +} +#serverVariables .var-name { + width: 45%; + float: ; + font-weight: bold; +} +#serverVariables .var-name.session { + font-weight: normal; + font-style: italic; +} +#serverVariables .var-value { + width: 50%; + float: ; + text-align: ; +} +#serverVariables .var-doc { + overflow:visible; + float: ; +} + +/* server variables editor */ +#serverVariables .editLink { + padding-: 1em; + float: ; + font-family: sans-serif; +} +#serverVariables .serverVariableEditor { + width: 100%; + overflow: hidden; +} +#serverVariables .serverVariableEditor input { + width: 100%; + margin: 0 0.5em; + box-sizing: border-box; + -ms-box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + height: 2.2em; +} +#serverVariables .serverVariableEditor div { + display: block; + overflow: hidden; + padding-: 1em; +} +#serverVariables .serverVariableEditor a { + float: ; + margin: 0 0.5em; + line-height: 2em; +} +/* end server variables */ + + +p.notice { + margin: 1.5em 0; + border: 1px solid #000; + background-repeat: no-repeat; + + background-position: 10px 50%; + padding: 10px 10px 10px 25px; + + background-position: 99% 50%; + padding: 25px 10px 10px 10px + + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; + -moz-box-shadow: 0 1px 2px #fff inset; + -webkit-box-shadow: 0 1px 2px #fff inset; + box-shadow: 0 1px 2px #fff inset; + background: #555; + color: #d4fb6a; +} + +p.notice a { + color: #fff; + text-decoration: underline; +} + +/* querywindow */ +body#bodyquerywindow { + margin: 0; + padding: 0; + background-image: none; + background-color: #F5F5F5; +} + +div#querywindowcontainer { + margin: 0; + padding: 0; + width: 100%; +} + +div#querywindowcontainer fieldset { + margin-top: 0; +} +/* END querywindow */ + +/* profiling */ + +div#profilingchart { + width: 550px; + height: 370px; + float: ; +} + +#profilingchart .jqplot-highlighter-tooltip{ + top: auto !important; + left: 11px; + bottom:24px; +} + +#profilesummarytable th.header, #profiletable th.header{ + cursor: pointer; +} + +#profilesummarytable th.header .sorticon, #profiletable th.header .sorticon{ + width: 16px; + height: 16px; + background-repeat: no-repeat; + background-position: right center; + display: inline-block; + vertical-align: middle; + float: right; +} + +#profilesummarytable th.headerSortUp .sorticon, #profiletable th.headerSortUp .sorticon{ + background-image: url(getImgPath('s_desc.png');?>); +} + +#profilesummarytable th.headerSortDown .sorticon, #profiletable th.headerSortDown .sorticon{ + background-image: url(getImgPath('s_asc.png');?>); +} + +/* END profiling */ + +/* table charting */ + +#resizer { + border: 1px solid silver; +} +#inner-resizer { /* make room for the resize handle */ + padding: 10px; +} + +/* END table charting */ + +/* querybox */ + +#togglequerybox { + margin: 0 10px; +} + +#serverstatus h3 +{ + margin: 15px 0; + font-weight: normal; + color: #999; + font-size: 1.7em; +} +#sectionlinks { + padding: 16px; + background: #f3f3f3; + border: 1px solid #aaa; + border-radius: 5px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + box-shadow: 0 1px 1px #fff inset; + -webkit-box-shadow: 0 1px 1px #fff inset; + -moz-box-shadow: 0 1px 1px #fff inset; +} +#sectionlinks a, +.buttonlinks a, +a.button { + font-size: .88em; + font-weight: bold; + text-shadow: 0 1px 0 #fff; + line-height: 35px; + margin-: 7px; + border: 1px solid #aaa; + padding: 5px 10px; + color: #111; + text-decoration: none; + background: #ddd; + white-space: nowrap; + border-radius: 20px; + -webkit-border-radius: 20px; + -moz-border-radius: 20px; + box-shadow: 1px 1px 2px rgba(0,0,0,.5); + /* + -webkit-box-shadow: 1px 1px 2px rgba(0,0,0,.5); + -moz-box-shadow: 1px 1px 2px rgba(0,0,0,.5); + text-shadow: #fff 0 1px 0; + */ + getCssGradient('ffffff', 'cccccc'); ?> +} +#sectionlinks a:hover, +.buttonlinks a:hover, +a.button:hover { + getCssGradient('cccccc', 'dddddd'); ?> +} + +div#sqlquerycontainer { + float: ; + width: 69%; + /* height: 15em; */ +} + +div#tablefieldscontainer { + float: ; + width: 29%; + /* height: 15em; */ +} + +div#tablefieldscontainer select { + width: 100%; + background: #fff; + /* height: 12em; */ +} + +textarea#sqlquery { + width: 100%; + /* height: 100%; */ + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + border: 1px solid #aaa; + padding: 5px; + font-family: inherit; +} +textarea#sql_query_edit { + height: 7em; + width: 95%; + display: block; +} +div#queryboxcontainer div#bookmarkoptions { + margin-top: .5em; +} +/* end querybox */ + +/* main page */ +#maincontainer { + /* background-image: url(getImgPath('logo_right.png');?>); */ + /* background-position: bottom; */ + /* background-repeat: no-repeat; */ +} + +#mysqlmaininformation, +#pmamaininformation { + float: ; + width: 49%; +} + +#maincontainer ul { + list-style-type: disc; + vertical-align: middle; +} + +#maincontainer li { + margin-bottom: .3em; +} +/* END main page */ + + +/* iconic view for ul items */ + +li.no_bullets { + list-style-type:none !important; + margin-left: -25px !important; //align with other list items which have bullets +} + +/* END iconic view for ul items */ + +#body_browse_foreigners { + background: ; + margin: .5em .5em 0 .5em; +} + +#bodyquerywindow { + background: ; +} + +#bodythemes { + width: 500px; + margin: auto; + text-align: center; +} + +#bodythemes img { + border: .1em solid #000; +} + +#bodythemes a:hover img { + border: .1em solid red; +} + +#fieldset_select_fields { + float: ; +} + +#selflink { + clear: both; + display: block; + margin-top: 1em; + margin-bottom: 1em; + width: 98%; + margin-: 1%; + border-top: .1em solid silver; + text-align: ; +} + +#table_innodb_bufferpool_usage, +#table_innodb_bufferpool_activity { + float: ; +} + +#div_mysql_charset_collations table { + float: ; +} + +.operations_half_width { + width: 48%; + float: ; +} +.operations_half_width input[type=text], +.operations_half_width input[type=password], +.operations_half_width input[type=number], +.operations_half_width select { + width: 95%; +} +.operations_half_width input[type=text].halfWidth, +.operations_half_width input[type=password].halfWidth, +.operations_half_width input[type=number].halfWidth, +.operations_half_width select.halfWidth { + width: 40%; +} +.operations_half_width ul { + list-style-type: none; + padding: 0; +} +.operations_full_width { + width: 100%; + clear: both; +} + +#qbe_div_table_list { + float: ; +} + +#qbe_div_sql_query { + float: ; +} + +label.desc { + width: 30em; + float: ; +} + +label.desc sup { + position: absolute; +} + +code.sql, +div.sqlvalidate { + display: block; + padding: 1em; + margin-top: 0; + margin-bottom: 0; + max-height: 10em; + overflow: auto; +} + +#result_query div.sqlOuter { + background: ; + padding: 1em; +} + +#PMA_slidingMessage code.sql, +div.sqlvalidate { + background: ; +} + +#main_pane_left { + width: 60%; + float: ; + padding-top: 1em; +} + +#main_pane_right { + margin-: 60%; + padding-top: 1em; + padding-: 1em; +} + +.group { + + border: 1px solid #999; + background: #f3f3f3; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: 2px 2px 5px #ccc; + -webkit-box-shadow: 2px 2px 5px #ccc; + box-shadow: 2px 2px 5px #ccc; + margin-bottom: 1em; + padding-bottom: 1em; +} + +.group h2 { + background-color: #bbb; + padding: .1em .3em; + margin-top: 0; + color: #fff; + font-size: 1.6em; + font-weight: normal; + text-shadow: 0 1px 0 #777; + -moz-box-shadow: 1px 1px 15px #999 inset; + -webkit-box-shadow: 1px 1px 15px #999 inset; + box-shadow: 1px 1px 15px #999 inset; +} + +.group-cnt { + padding: 0; + padding-: .5em; + display: inline-block; + width: 98%; +} + +textarea#partitiondefinition { + height: 3em; +} + + +/* for elements that should be revealed only via js */ +.hide { + display: none; +} + +#list_server { + list-style-image: none; +} + +/** + * Progress bar styles + */ +div.upload_progress +{ + width: 400px; + margin: 3em auto; + text-align: center; +} + +div.upload_progress_bar_outer +{ + border: 1px solid #000; + width: 202px; + position: relative; + margin: 0 auto 1em; + color: ; +} + +div.upload_progress_bar_inner +{ + background-color: ; + width: 0; + height: 12px; + margin: 1px; + overflow: hidden; + color: ; + position: relative; +} + +div.upload_progress_bar_outer div.percentage +{ + position: absolute; + top: 0; + : 0; + width: 202px; +} + +div.upload_progress_bar_inner div.percentage +{ + top: -1px; + : -1px; +} + +div#statustext { + margin-top: .5em; +} + +table#serverconnection_src_remote, +table#serverconnection_trg_remote, +table#serverconnection_src_local, +table#serverconnection_trg_local { + float: ; +} +/** + * Validation error message styles + */ +input[type=text].invalid_value, +input[type=password].invalid_value, +input[type=number].invalid_value, +input[type=date].invalid_value, +.invalid_value { + background: #FFCCCC; +} + +/** + * Ajax notification styling + */ + .ajax_notification { + top: 0; /** The notification needs to be shown on the top of the page */ + position: fixed; + margin-top: 0; + margin-right: auto; + margin-bottom: 0; + margin-: auto; + padding: 5px; /** Keep a little space on the sides of the text */ + width: 350px; + + z-index: 1100; /** If this is not kept at a high z-index, the jQueryUI modal dialogs (z-index: 1000) might hide this */ + text-align: center; + display: inline; + left: 0; + right: 0; + background-image: url(getImgPath('ajax_clock_small.gif');?>); + background-repeat: no-repeat; + background-position: 2%; + border: 1px solid #e2b709; + } + +/* additional styles */ +.ajax_notification { + margin-top: 200px; + background: #ffe57e; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + box-shadow: 0 5px 90px #888; + -moz-box-shadow: 0 5px 90px #888; + -webkit-box-shadow: 0 5px 90px #888; +} + +#loading_parent { + /** Need this parent to properly center the notification division */ + position: relative; + width: 100%; + } +/** + * Export and Import styles + */ + +.exportoptions h3, +.importoptions h3 { + border-bottom: 1px #999 solid; + font-size: 110%; +} + +.exportoptions ul, +.importoptions ul, +.format_specific_options ul { + list-style-type: none; + margin-bottom: 15px; +} + +.exportoptions li, +.importoptions li { + margin: 7px; +} +.exportoptions label, +.importoptions label, +.exportoptions p, +.importoptions p { + margin: 5px; + float: none; +} + +#csv_options label.desc, +#ldi_options label.desc, +#latex_options label.desc, +#output label.desc { + float: ; + width: 15em; +} + +.exportoptions, +.importoptions { + margin: 20px 30px 30px; + margin-: 10px; +} + +.exportoptions #buttonGo, +.importoptions #buttonGo { + font-weight: bold; + margin-: 14px; + border: 1px solid #aaa; + padding: 5px 12px; + color: #111; + text-decoration: none; + background: #ddd; + + border-radius: 12px; + -webkit-border-radius: 12px; + -moz-border-radius: 12px; + + text-shadow: 0 1px 0 #fff; + + getCssGradient('ffffff', 'cccccc'); ?> + cursor: pointer; +} +#buttonGo:hover { + getCssGradient('cccccc', 'dddddd'); ?> +} + +.format_specific_options h3 { + margin: 10px 0 0; + margin-: 10px; + border: 0; +} + +.format_specific_options { + border: 1px solid #999; + margin: 7px 0; + padding: 3px; +} + +p.desc { + margin: 5px; +} + +/** + * Export styles only + */ +select#db_select, +select#table_select { + width: 400px; +} + +.export_sub_options { + margin: 20px 0 0; + margin-: 30px; +} + +.export_sub_options h4 { + border-bottom: 1px #999 solid; +} + +.export_sub_options li.subgroup { + display: inline-block; + margin-top: 0; +} + +.export_sub_options li { + margin-bottom: 0; +} + +#quick_or_custom, +#output_quick_export { + display: none; +} +/** + * Import styles only + */ + +.importoptions #import_notification { + margin: 10px 0; + font-style: italic; +} + +input#input_import_file { + margin: 5px; +} + +.formelementrow { + margin: 5px 0 5px 0; +} + +#popup_background { + display: none; + position: fixed; + _position: absolute; /* hack for IE6 */ + width: 100%; + height: 100%; + top: 0; + : 0; + background: #000; + z-index: 1000; + overflow: hidden; +} + +/** + * Table structure styles + */ +#fieldsForm ul.table-structure-actions { + margin: 0; + padding: 0; + list-style: none; +} +#fieldsForm ul.table-structure-actions li { + float: ; + margin-: 0.3em; /* same as padding of "table td" */ +} +#fieldsForm ul.table-structure-actions .submenu li { + padding: 0; + margin: 0; +} +#fieldsForm ul.table-structure-actions .submenu li span { + padding: 0.3em; + margin: 0.1em; +} +/** + * Indexes + */ +#index_frm .index_info input, +#index_frm .index_info select { + width: 14em; + box-sizing: border-box; + -ms-box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; +} + +#index_frm .index_info div { + padding: .2em 0; +} + +#index_frm .index_info .label { + float: ; + min-width: 12em; +} + +#index_frm .slider { + width: 10em; + margin: .6em; + float: ; +} + +#index_frm .add_fields { + float: ; +} + +#index_frm .add_fields input { + margin-: 1em; +} + +#index_frm input { + margin: 0; +} + +#index_frm td { + vertical-align: middle; +} + +table#index_columns { + width: 100%; +} + +table#index_columns select { + width: 100%; +} + +#move_columns_dialog div { + padding: 1em; +} + +#move_columns_dialog ul { + list-style: none; + margin: 0; + padding: 0; +} + +#move_columns_dialog li { + background: ; + border: 1px solid #aaa; + color: ; + font-weight: bold; + margin: .4em; + padding: .2em; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; +} + +.margin#change_column_dialog { + margin: 0 .5em; +} + +/* config forms */ +.config-form ul.tabs { + margin: 1.1em .2em 0; + padding: 0 0 .3em 0; + list-style: none; + font-weight: bold; +} + +.config-form ul.tabs li { + float: ; + margin-bottom: -1px; +} + +.config-form ul.tabs li a { + display: block; + margin: .1em .2em 0; + white-space: nowrap; + text-decoration: none; + border: 1px solid ; + border-bottom: 1px solid #aaa; +} + +.config-form ul.tabs li a { + padding: 7px 10px; + -webkit-border-radius: 5px 5px 0 0; + -moz-border-radius: 5px 5px 0 0; + border-radius: 5px 5px 0 0; + background: #f2f2f2; + color: #555; + text-shadow: 0 1px 0 #fff; +} + +.config-form ul.tabs li a:hover, +.config-form ul.tabs li a:active { + background: #e5e5e5; +} + +.config-form ul.tabs li.active a { + background-color: #fff; + margin-top: 1px; + color: #000; + text-shadow: none; + border-color: #aaa; + border-bottom: 1px solid #fff; +} + +.config-form fieldset { + margin-top: 0; + padding: 0; + clear: both; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.config-form legend { + display: none; +} + +.config-form fieldset p { + margin: 0; + padding: .5em; + background: #fff; + border-top: 0; +} + +.config-form fieldset .errors { /* form error list */ + margin: 0 -2px 1em; + padding: .5em 1.5em; + background: #FBEAD9; + border: 0 #C83838 solid; + border-width: 1px 0; + list-style: none; + font-family: sans-serif; + font-size: small; +} + +.config-form fieldset .inline_errors { /* field error list */ + margin: .3em .3em .3em; + margin-: 0; + padding: 0; + list-style: none; + color: #9A0000; + font-size: small; +} + +.config-form fieldset th { + padding: .3em .3em .3em; + padding-: .5em; + text-align: ; + vertical-align: top; + width: 40%; + background: transparent; + filter: none; +} + +.config-form fieldset .doc, +.config-form fieldset .disabled-notice { + margin-: 1em; +} + +.config-form fieldset .disabled-notice { + font-size: 80%; + text-transform: uppercase; + color: #E00; + cursor: help; +} + +.config-form fieldset td { + padding-top: .3em; + padding-bottom: .3em; + vertical-align: top; +} + +.config-form fieldset th small { + display: block; + font-weight: normal; + font-family: sans-serif; + font-size: x-small; + color: #444; +} + +.config-form fieldset th, +.config-form fieldset td { + border-top: 1px solid; + border-: none; +} + +fieldset .group-header th { + background: ; +} + +fieldset .group-header + tr th { + padding-top: .6em; +} + +fieldset .group-field-1 th, +fieldset .group-header-2 th { + padding-: 1.5em; +} + +fieldset .group-field-2 th, +fieldset .group-header-3 th { + padding-: 3em; +} + +fieldset .group-field-3 th { + padding-: 4.5em; +} + +fieldset .disabled-field th, +fieldset .disabled-field th small, +fieldset .disabled-field td { + color: #666; + background-color: #ddd; +} + +.config-form .lastrow { + border-top: 1px #000 solid; +} + +.config-form .lastrow { + background: ; + padding: .5em; + text-align: center; +} + +.config-form .lastrow input { + font-weight: bold; +} + +/* form elements */ + +.config-form span.checkbox { + padding: 2px; + display: inline-block; +} + +.config-form .custom { /* customized field */ + background: #FFC; +} + +.config-form span.checkbox.custom { + padding: 1px; + border: 1px #EDEC90 solid; + background: #FFC; +} + +.config-form .field-error { + border-color: #A11 !important; +} + +.config-form input[type="text"], +.config-form input[type="password"], +.config-form input[type="number"], +.config-form select, +.config-form textarea { + border: 1px #A7A6AA solid; + height: auto; +} + +.config-form input[type="text"]:focus, +.config-form input[type="password"]:focus, +.config-form input[type="number"]:focus, +.config-form select:focus, +.config-form textarea:focus { + border: 1px #6676FF solid; + background: #F7FBFF; +} + +.config-form .field-comment-mark { + font-family: serif; + color: #007; + cursor: help; + padding: 0 .2em; + font-weight: bold; + font-style: italic; +} + +.config-form .field-comment-warning { + color: #A00; +} + +/* error list */ +.config-form dd { + margin-: .5em; +} + +.config-form dd:before { + content: "\25B8 "; +} + +.click-hide-message { + cursor: pointer; +} + +.prefsmanage_opts { + margin-: 2em; +} + +#prefs_autoload { + margin-bottom: .5em; +} + +#placeholder .button { + position: absolute; + cursor: pointer; +} + +#placeholder div.button { + font-size: smaller; + color: #999; + background-color: #eee; + padding: 2px; +} + +.wrapper { + float: ; + margin-bottom: 1.5em; +} +.toggleButton { + position: relative; + cursor: pointer; + font-size: .8em; + text-align: center; + line-height: 1.4em; + height: 1.55em; + overflow: hidden; + border-right: .1em solid #888; + border-left: .1em solid #888; + -webkit-border-radius: .3em; + -moz-border-radius: .3em; + border-radius: .3em; +} +.toggleButton table, +.toggleButton td, +.toggleButton img { + padding: 0; + position: relative; +} +.toggleButton .container { + position: absolute; +} +.toggleButton .toggleOn { + color: #fff; + padding: 0 1em; + text-shadow: 0 0 .2em #000; +} +.toggleButton .toggleOff { + padding: 0 1em; +} + +.doubleFieldset fieldset { + width: 48%; + float: ; + padding: 0; +} +.doubleFieldset fieldset.left { + margin-: 1%; +} +.doubleFieldset fieldset.right { + margin-: 1%; +} +.doubleFieldset legend { + margin-: 1.5em; +} +.doubleFieldset div.wrap { + padding: 1.5em; +} + +#table_columns input[type="text"], +#table_columns input[type="password"], +#table_columns input[type="number"], +#table_columns select { + width: 10em; + box-sizing: border-box; + -ms-box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; +} + +#table_columns select { + margin: 0 6px; +} + +#placeholder { + position: relative; + border: 1px solid #aaa; + float: ; + overflow: hidden; +} + +.placeholderDrag { + cursor: move; +} + +#placeholder .button { + position: absolute; +} + +#left_arrow { + left: 8px; + top: 26px; +} + +#right_arrow { + left: 26px; + top: 26px; +} + +#up_arrow { + left: 17px; + top: 8px; +} + +#down_arrow { + left: 17px; + top: 44px; +} + +#zoom_in { + left: 17px; + top: 67px; +} + +#zoom_world { + left: 17px; + top: 85px; +} + +#zoom_out { + left: 17px; + top: 103px; +} + +.colborder { + cursor: col-resize; + height: 100%; + margin-: -6px; + position: absolute; + width: 5px; +} + +.colborder_active { + border-: 2px solid #a44; +} + +.pma_table td { + position: static; +} + +.pma_table th.draggable span, +.pma_table tbody td span { + display: block; + overflow: hidden; +} + +.modal-copy input { + display: block; + width: 100%; + margin-top: 1.5em; + padding: .3em 0; +} + +.cRsz { + position: absolute; +} + +.cCpy { + background: #333; + color: #FFF; + font-weight: bold; + margin: .1em; + padding: .3em; + position: absolute; + text-shadow: -1px -1px #000; + + -moz-box-shadow: 0 0 .7em #000; + -webkit-box-shadow: 0 0 .7em #000; + box-shadow: 0 0 .7em #000; + -moz-border-radius: .3em; + -webkit-border-radius: .3em; + border-radius: .3em; +} + +.cPointer { + background: url(getImgPath('col_pointer.png');?>); + height: 20px; + margin-: -5px; /* must be minus half of its width */ + margin-top: -10px; + position: absolute; + width: 10px; +} + +.tooltip { + background: #333 !important; + opacity: .8 !important; + border: 1px solid #000 !important; + -moz-border-radius: .3em !important; + -webkit-border-radius: .3em !important; + border-radius: .3em !important; + text-shadow: -1px -1px #000 !important; + font-size: .8em !important; + font-weight: bold !important; + padding: 1px 3px !important; +} + +.tooltip * { + background: none !important; + color: #FFF !important; +} + +.cDrop { + left: 0; + position: absolute; + top: 0; +} + +.coldrop { + background: url(getImgPath('col_drop.png');?>); + cursor: pointer; + height: 16px; + margin-: .3em; + margin-top: .3em; + position: absolute; + width: 16px; +} + +.coldrop:hover, +.coldrop-hover { + background-color: #999; +} + +.cList { + background: #EEE; + border: solid 1px #999; + position: absolute; + -moz-box-shadow: 0 .2em .5em #333; + -webkit-box-shadow: 0 .2em .5em #333; + box-shadow: 0 .2em .5em #333; +} + +.cList .lDiv div { + padding: .2em .5em .2em; + padding-: .2em; +} + +.cList .lDiv div:hover { + background: #DDD; + cursor: pointer; +} + +.cList .lDiv div input { + cursor: pointer; +} + +.showAllColBtn { + border-bottom: solid 1px #999; + border-top: solid 1px #999; + cursor: pointer; + font-size: .9em; + font-weight: bold; + padding: .35em 1em; + text-align: center; +} + +.showAllColBtn:hover { + background: #DDD; +} + +.turnOffSelect { + -moz-user-select: none; + -khtml-user-select: none; + -webkit-user-select: none; + user-select: none; +} + +#page_content { + background-color: white; +} + +.navigation { + margin: .8em 0; + + border-radius: 5px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + + getCssGradient('eeeeee', 'cccccc'); ?> +} + +.navigation td { + margin: 0; + padding: 0; + vertical-align: middle; + white-space: nowrap; +} + +.navigation_separator { + color: #999; + display: inline-block; + font-size: 1.5em; + text-align: center; + height: 1.4em; + width: 1.2em; + text-shadow: 1px 0 #FFF; +} + +.navigation input[type=submit] { + background: none; + border: 0; + filter: none; + margin: 0; + padding: .8em .5em; + + border-radius: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; +} + +.navigation input[type=submit]:hover, +.navigation input.edit_mode_active { + color: #fff; + cursor: pointer; + text-shadow: none; + + getCssGradient('333333', '555555'); ?> +} + +.navigation select { + margin: 0 .8em; +} + +.cEdit { + margin: 0; + padding: 0; + position: absolute; +} + +.cEdit input[type=text] { + background: #FFF; + height: 100%; + margin: 0; + padding: 0; +} + +.cEdit .edit_area { + background: #FFF; + border: 1px solid #999; + min-width: 10em; + padding: .3em .5em; +} + +.cEdit .edit_area select, +.cEdit .edit_area textarea { + width: 97%; +} + +.cEdit .cell_edit_hint { + color: #555; + font-size: .8em; + margin: .3em .2em; +} + +.cEdit .edit_box { + overflow: hidden; + padding: 0; +} + +.cEdit .edit_box_posting { + background: #FFF url(getImgPath('ajax_clock_small.gif');?>) no-repeat right center; + padding-: 1.5em; +} + +.cEdit .edit_area_loading { + background: #FFF url(getImgPath('ajax_clock_small.gif');?>) no-repeat center; + height: 10em; +} + +.cEdit .edit_area_right { + position: absolute; + right: 0; +} + +.cEdit .goto_link { + background: #EEE; + color: #555; + padding: .2em .3em; +} + +.saving_edited_data { + background: url(getImgPath('ajax_clock_small.gif');?>) no-repeat left; + padding-: 20px; +} + +#relationalTable select { + width: 125px; + margin-right: 5px; +} + +/* css for timepicker */ +.ui-timepicker-div .ui-widget-header { margin-bottom: 8px; } +.ui-timepicker-div dl { text-align: ; } +.ui-timepicker-div dl dt { height: 25px; margin-bottom: -25px; } +.ui-timepicker-div dl dd { margin: 0 10px 10px 65px; } +.ui-timepicker-div td { font-size: 90%; } +.ui-tpicker-grid-label { background: none; border: none; margin: 0; padding: 0; } +.ui-timepicker-rtl { direction: rtl; } +.ui-timepicker-rtl dl { text-align: right; } +.ui-timepicker-rtl dl dd { margin: 0 65px 10px 10px; } + +input.btn { + color: #333; + background-color: #D0DCE0; +} + +body .ui-widget { + font-size: 1em; +} + +.ui-dialog fieldset legend a { + color: #235A81; +} + +/* over-riding jqplot-yaxis class */ +.jqplot-yaxis { + left:0px !important; + min-width:25px; + width:auto; +} +.jqplot-axis { + overflow:hidden; +} + +.report-data { + height:13em; + overflow:scroll; + width:570px; + border: solid 1px; + background: white; + padding: 2px; +} + +.report-description { + height:10em; + width:570px; +} diff --git a/phpMyAdmin/themes/pmahomme/css/enum_editor.css.php b/phpMyAdmin/themes/pmahomme/css/enum_editor.css.php new file mode 100644 index 0000000..da9bc07 --- /dev/null +++ b/phpMyAdmin/themes/pmahomme/css/enum_editor.css.php @@ -0,0 +1,80 @@ + + +/** + * ENUM/SET editor styles + */ +p.enum_notice { + margin: 5px 2px; + font-size: 80%; +} + +#enum_editor p { + margin-top: 0; + font-style: italic; +} + +#enum_editor .values, +#enum_editor .add { + width: 100%; +} + +#enum_editor .add td { + vertical-align: middle; + width: 50%; + padding: 0 0 0; + padding-: 1em; +} + +#enum_editor .values td.drop { + width: 1.8em; + cursor: pointer; + vertical-align: middle; +} + +#enum_editor .values input { + margin: .1em 0; + padding-: 2em; + width: 100%; +} + +#enum_editor .values img { + width: 1.8em; + vertical-align: middle; +} + +#enum_editor input.add_value { + margin: 0; + margin-: 0.4em; +} + +#enum_editor_output textarea { + width: 100%; + float: ; + margin: 1em 0 0 0; +} + +/** + * ENUM/SET editor integration for the routines editor + */ +.enum_hint { + position: relative; +} + +.enum_hint a { + position: absolute; + : 81%; + bottom: .35em; +} diff --git a/phpMyAdmin/themes/pmahomme/css/gis.css.php b/phpMyAdmin/themes/pmahomme/css/gis.css.php new file mode 100644 index 0000000..66348e3 --- /dev/null +++ b/phpMyAdmin/themes/pmahomme/css/gis.css.php @@ -0,0 +1,65 @@ + + +.gis_table td { + vertical-align: middle; +} + +.gis_table select { + min-width: 151px; + margin: 6px; +} + +.gis_table .button { + text-align: ; +} + +/** + * GIS data editor styles + */ +a.close_gis_editor { + float: ; +} + +#gis_editor { + display: none; + position: fixed; + _position: absolute; /* hack for IE */ + z-index: 1001; + overflow-y: auto; + overflow-x: hidden; +} + +#gis_data { + min-height: 230px; +} + +#gis_data_textarea { + height: 6em; +} + +#gis_data_editor { + background: #D0DCE0; + padding: 15px; + min-height: 500px; +} + +#gis_data_editor .choice { + display: none; +} + +#gis_data_editor input[type="text"] { + width: 75px; +} diff --git a/phpMyAdmin/themes/pmahomme/css/jqplot.css.php b/phpMyAdmin/themes/pmahomme/css/jqplot.css.php new file mode 100644 index 0000000..e167c9f --- /dev/null +++ b/phpMyAdmin/themes/pmahomme/css/jqplot.css.php @@ -0,0 +1,277 @@ + + +/* jqPlot */ + +/*rules for the plot target div. These will be cascaded down to all plot elements according to css rules*/ +.jqplot-target { + position: relative; + color: #222222; + font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; + font-size: 1em; +/* height: 300px; + width: 590px;*/ +} + +/*rules applied to all axes*/ +.jqplot-axis { + font-size: 0.75em; +} + +.jqplot-xaxis { + margin-top: 10px; +} + +.jqplot-x2axis { + margin-bottom: 10px; +} + +.jqplot-yaxis { + margin-: 10px; +} + +.jqplot-y2axis, .jqplot-y3axis, .jqplot-y4axis, .jqplot-y5axis, .jqplot-y6axis, .jqplot-y7axis, .jqplot-y8axis, .jqplot-y9axis, .jqplot-yMidAxis { + margin-left: 10px; + margin-right: 10px; +} + +/*rules applied to all axis tick divs*/ +.jqplot-axis-tick, .jqplot-xaxis-tick, .jqplot-yaxis-tick, .jqplot-x2axis-tick, .jqplot-y2axis-tick, .jqplot-y3axis-tick, .jqplot-y4axis-tick, .jqplot-y5axis-tick, .jqplot-y6axis-tick, .jqplot-y7axis-tick, .jqplot-y8axis-tick, .jqplot-y9axis-tick, .jqplot-yMidAxis-tick { + position: absolute; + white-space: pre; +} + + +.jqplot-xaxis-tick { + top: 0px; + /* initial position untill tick is drawn in proper place */ + : 15px; +/* padding-top: 10px;*/ + vertical-align: top; +} + +.jqplot-x2axis-tick { + bottom: 0px; + /* initial position untill tick is drawn in proper place */ + : 15px; +/* padding-bottom: 10px;*/ + vertical-align: bottom; +} + +.jqplot-yaxis-tick { + : 0px; + /* initial position untill tick is drawn in proper place */ + top: 15px; +/* padding-right: 10px;*/ + text-align: ; +} + +.jqplot-yaxis-tick.jqplot-breakTick { + : -20px; + margin-: 0px; + padding:1px 5px 1px; +/* background-color: white;*/ + z-index: 2; + font-size: 1.5em; +} + +.jqplot-y2axis-tick, .jqplot-y3axis-tick, .jqplot-y4axis-tick, .jqplot-y5axis-tick, .jqplot-y6axis-tick, .jqplot-y7axis-tick, .jqplot-y8axis-tick, .jqplot-y9axis-tick { + : 0px; + /* initial position untill tick is drawn in proper place */ + top: 15px; +/* padding-left: 10px;*/ +/* padding-right: 15px;*/ + text-align: ; +} + +.jqplot-yMidAxis-tick { + text-align: center; + white-space: nowrap; +} + +.jqplot-xaxis-label { + margin-top: 10px; + font-size: 11pt; + position: absolute; +} + +.jqplot-x2axis-label { + margin-bottom: 10px; + font-size: 11pt; + position: absolute; +} + +.jqplot-yaxis-label { + margin-right: 10px; +/* text-align: center;*/ + font-size: 11pt; + position: absolute; +} + +.jqplot-yMidAxis-label { + font-size: 11pt; + position: absolute; +} + +.jqplot-y2axis-label, .jqplot-y3axis-label, .jqplot-y4axis-label, .jqplot-y5axis-label, .jqplot-y6axis-label, .jqplot-y7axis-label, .jqplot-y8axis-label, .jqplot-y9axis-label { +/* text-align: center;*/ + font-size: 11pt; + margin-: 10px; + position: absolute; +} + +.jqplot-meterGauge-tick { + font-size: 0.75em; + color: #999999; +} + +.jqplot-meterGauge-label { + font-size: 1em; + color: #999999; +} + +table.jqplot-table-legend { + margin-top: 12px; + margin-bottom: 12px; + margin-left: 12px; + margin-right: 12px; +} + +table.jqplot-table-legend, table.jqplot-cursor-legend { + background-color: rgba(255,255,255,0.6); + border: 1px solid #cccccc; + position: absolute; + font-size: 0.75em; +} + +td.jqplot-table-legend { + vertical-align: middle; +} + +/* +These rules could be used instead of assigning +element styles and relying on js object properties. +*/ + +/* +td.jqplot-table-legend-swatch { + padding-top: 0.5em; + text-align: center; +} + +tr.jqplot-table-legend:first td.jqplot-table-legend-swatch { + padding-top: 0px; +} +*/ + +td.jqplot-seriesToggle:hover, td.jqplot-seriesToggle:active { + cursor: pointer; +} + +.jqplot-table-legend .jqplot-series-hidden { + text-decoration: line-through; +} + +div.jqplot-table-legend-swatch-outline { + border: 1px solid #cccccc; + padding: 1px; +} + +div.jqplot-table-legend-swatch { + width: 0; + height: 0; + border-top-width: 5px; + border-bottom-width: 5px; + border-left-width: 6px; + border-right-width: 6px; + border-top-style: solid; + border-bottom-style: solid; + border-left-style: solid; + border-right-style: solid; +} + +.jqplot-title { + top: 0px; + : 0px; + padding-bottom: 0.5em; + font-size: 1.2em; +} + +table.jqplot-cursor-tooltip { + border: 1px solid #cccccc; + font-size: 0.75em; +} + + +.jqplot-cursor-tooltip { + border: 1px solid #cccccc; + font-size: 0.75em; + white-space: nowrap; + background: rgba(208,208,208,0.5); + padding: 1px; +} + +.jqplot-highlighter-tooltip, .jqplot-canvasOverlay-tooltip { + border: 1px solid #cccccc; + font-size: 0.75em; + white-space: nowrap; + background: rgba(208,208,208,0.5); + padding: 1px; +} + +.jqplot-point-label { + font-size: 0.75em; + z-index: 2; +} + +td.jqplot-cursor-legend-swatch { + vertical-align: middle; + text-align: center; +} + +div.jqplot-cursor-legend-swatch { + width: 1.2em; + height: 0.7em; +} + +.jqplot-error { +/* Styles added to the plot target container when there is an error go here.*/ + text-align: center; +} + +.jqplot-error-message { +/* Styling of the custom error message div goes here.*/ + position: relative; + top: 46%; + display: inline-block; +} + +div.jqplot-bubble-label { + font-size: 0.8em; +/* background: rgba(90%, 90%, 90%, 0.15);*/ + padding-left: 2px; + padding-right: 2px; + color: rgb(20%, 20%, 20%); +} + +div.jqplot-bubble-label.jqplot-bubble-label-highlight { + background: rgba(90%, 90%, 90%, 0.7); +} + +div.jqplot-noData-container { + text-align: center; + background-color: rgba(96%, 96%, 96%, 0.3); +} diff --git a/phpMyAdmin/themes/pmahomme/css/navigation.css.php b/phpMyAdmin/themes/pmahomme/css/navigation.css.php new file mode 100644 index 0000000..0217a49 --- /dev/null +++ b/phpMyAdmin/themes/pmahomme/css/navigation.css.php @@ -0,0 +1,285 @@ + + +/******************************************************************************/ +/* Navigation */ + +#pma_navigation { + width: px; + overflow: hidden; + position: fixed; + top: 0; + : 0; + height: 100%; + background: url(./themes/pmahomme/img/left_nav_bg.png) repeat-y right 0% ; + color: ; + z-index: 800; +} + +#pma_navigation_content { + width: 100%; + height: 100%; + position: absolute; + top: 0; + : 0; + z-index: 0; +} + +#pma_navigation ul { + margin: 0; +} + +#pma_navigation form { + margin: 0; + padding: 0; + display: inline; +} + +#pma_navigation select#select_server, +#pma_navigation select#lightm_db { + width: 100%; +} + +/******************************************************************************/ +/* specific elements */ + +#pma_navigation div.pageselector { + text-align: center; + margin: 0; + margin-: 0.75em; + border-: 1px solid #666; +} + +#pma_navigation div#pmalogo { + +} + +#pma_navigation #pmalogo, +#pma_navigation #serverChoice, +#pma_navigation #leftframelinks, +#pma_navigation #recentTableList, +#pma_navigation #databaseList, +#pma_navigation div.pageselector.dbselector { + text-align: center; + padding: 5px 10px 0px; + border: 0; +} + +#pma_navigation #recentTableList select, +#pma_navigation #serverChoice select + { + width: 80%; +} + +#pma_navigation_content > img.throbber { + display: none; + margin: .3em auto 0; +} + +/* Navigation tree*/ +#pma_navigation_tree { + margin: 0; + margin-: 10px; + color: #444; + height: 74%; + position: relative; +} +#pma_navigation_tree_content { + width: 100%; + overflow: hidden; + overflow-y: auto; + position: absolute; + height: 100%; +} +#pma_navigation_tree a { + color: ; +} +#pma_navigation_tree a:hover { + text-decoration: underline; +} +#pma_navigation_tree li.activePointer { + color: ; + background-color: ; +} +#pma_navigation_tree li.selected { + color: ; + background-color: ; +} +#pma_navigation_tree li .dbItemControls { + padding-left: 4px; +} +#pma_navigation_tree li .navItemControls { + display: none; + padding-left: 4px; +} +#pma_navigation_tree li.activePointer .navItemControls { + display: inline; + opacity: 0.5; +} +#pma_navigation_tree li.activePointer .navItemControls:hover { + display: inline; + opacity: 1.0; +} +#pma_navigation_tree ul { + clear: both; + padding: 0; + list-style-type: none; + margin: 0; +} +#pma_navigation_tree ul ul { + position: relative; +} +#pma_navigation_tree li { + white-space: nowrap; + clear: both; + min-height: 16px; +} +#pma_navigation_tree img { + margin: 0; +} +#pma_navigation_tree div.block { + position: relative; + width: 1.5em; + height: 1.5em; + min-width: 16px; + min-height: 16px; + float: ; +} +#pma_navigation_tree div.block i, +#pma_navigation_tree div.block b { + width: 1.5em; + height: 1.5em; + min-width: 16px; + min-height: 8px; + position: absolute; + bottom: 0.7em; + : 0.75em; + z-index: 0; +} +#pma_navigation_tree div.block i { /* Top and right segments for the tree element connections */ + display: block; + border-: 1px solid #666; + border-bottom: 1px solid #666; +} +#pma_navigation_tree div.block i.first { /* Removes top segment */ + border-: 0; +} +#pma_navigation_tree div.block b { /* Bottom segment for the tree element connections */ + display: block; + height: 0.75em; + bottom: 0; + : 0.75em; + border-: 1px solid #666; +} +#pma_navigation_tree div.block a, +#pma_navigation_tree div.block u { + position: absolute; + : 50%; + top: 50%; + z-index: 10; +} +#pma_navigation_tree div.block img { + position: relative; + top: -0.6em; + : 0; + margin-: -7px; +} +#pma_navigation_tree div.throbber img { + top: 2px; + : 2px; +} +#pma_navigation_tree li.last > ul { + background: none; +} +#pma_navigation_tree li > a, #pma_navigation_tree li > i { + line-height: 1.5em; + height: 1.5em; + padding-: 0.3em; +} +#pma_navigation_tree .list_container { + border-: 1px solid #666; + margin-: 0.75em; + padding-: 0.75em; +} +#pma_navigation_tree .last > .list_container { + border-: 0 solid #666; +} + +/* Fast filter */ +li.fast_filter { + padding-: 0.75em; + margin-: 0.75em; + padding-: 35px; + border-: 1px solid #666; +} +li.fast_filter input { + padding-: 1.7em; + width: 100%; +} +li.fast_filter span { + position: relative; + : 1.5em; + padding: 0.2em; + cursor: pointer; + font-weight: bold; + color: #800; +} +/* IE10+ has its own reset X */ +html.ie li.fast_filter span { + display: none; +} +html.ie.ie9 li.fast_filter span, +html.ie.ie8 li.fast_filter span { + display: auto; +} +html.ie li.fast_filter input { + padding-: .2em; +} +html.ie.ie9 li.fast_filter input, +html.ie.ie8 li.fast_filter input { + padding-: 1.7em; +} +li.fast_filter.db_fast_filter { + border: 0; +} + +/* Resize handler */ +#pma_navigation_resizer { + width: 3px; + height: 100%; + background-color: #aaa; + cursor: col-resize; + position: fixed; + top: 0; + : 240px; + z-index: 801; +} +#pma_navigation_collapser { + width: 20px; + height: 22px; + line-height: 22px; + background: #eee; + color: #555; + font-weight: bold; + position: fixed; + top: 0; + : px; + text-align: center; + cursor: pointer; + z-index: 800; + text-shadow: 0px 1px 0px #fff; + filter: dropshadow(color=#fff, offx=0, offy=1); + border: 1px solid #888; +} diff --git a/phpMyAdmin/themes/pmahomme/css/pmd.css.php b/phpMyAdmin/themes/pmahomme/css/pmd.css.php new file mode 100644 index 0000000..8b04144 --- /dev/null +++ b/phpMyAdmin/themes/pmahomme/css/pmd.css.php @@ -0,0 +1,530 @@ + + +/* Designer */ +.input_tab { + background-color: #A6C7E1; + color: #000; +} + +.content_fullscreen { + position: relative; + overflow: auto; +} + +#canvas_outer { + position: relative; +} + +#canvas { + background-color: #fff; + color: #000; +} + +canvas.pmd { + display: inline-block; + overflow: hidden; + text-align: left; +} + +canvas.pmd * { + behavior: url(#default#VML); +} + +.pmd_tab { + background-color: #fff; + color: #000; + border-collapse: collapse; + border: 1px solid #aaa; + z-index: 1; + -moz-user-select: none; +} + +.tab_zag { + background-image: url(getImgPath('pmd/Header.png'); ?>); + background-repeat: repeat-x; + text-align: center; + cursor: move; + padding: 1px; + font-weight: bold; +} + +.tab_zag_2 { + background-image: url(getImgPath('pmd/Header_Linked.png'); ?>); + background-repeat: repeat-x; + text-align: center; + cursor: move; + padding: 1px; + font-weight: bold; +} + +.tab_field { + background: #fff; + color: #000; + cursor: default; +} + +.tab_field_2 { + background-color: #CCFFCC; + color: #000; + background-repeat: repeat-x; + cursor: default; +} + +.tab_field_3 { + background-color: #FFE6E6; /*#DDEEFF*/ + color: #000; + cursor: default; +} + +#pmd_hint { + white-space: nowrap; + position: absolute; + background-color: #99FF99; + color: #000; + : 200px; + top: 50px; + z-index: 3; + border: #00CC66 solid 1px; + display: none; +} + +.scroll_tab { + overflow: auto; + width: 100%; + height: 500px; +} + +.pmd_Tabs { + cursor: default; + color: #0055bb; + white-space: nowrap; + text-decoration: none; + text-indent: 3px; + font-weight: bold; + margin-left: 2px; + text-align: ; + background-color: #fff; + background-image: url(getImgPath('pmd/left_panel_butt.png'); ?>); + border: #ccc solid 1px; +} + +.pmd_Tabs2 { + cursor: default; + color: #0055bb; + background: #FFEE99; + text-indent: 3px; + font-weight: bold; + white-space: nowrap; + text-decoration: none; + border: #9999FF solid 1px; + text-align: ; +} + +.owner { + font-weight: normal; + color: #888; +} + +.option_tab { + padding-left: 2px; + padding-right: 2px; + width: 5px; +} + +.select_all { + vertical-align: top; + padding-left: 2px; + padding-right: 2px; + cursor: default; + width: 1px; + color: #000; + background-image: url(getImgPath('pmd/Header.png'); ?>); + background-repeat: repeat-x; +} + +.small_tab { + vertical-align: top; + background-color: #0064ea; + color: #fff; + background-image: url(getImgPath('pmd/small_tab.png'); ?>); + cursor: default; + text-align: center; + font-weight: bold; + padding-left: 2px; + padding-right: 2px; + width: 1px; + text-decoration: none; +} + +.small_tab2 { + vertical-align: top; + color: #fff; + background-color: #FF9966; + cursor: default; + padding-left: 2px; + padding-right: 2px; + text-align: center; + font-weight: bold; + width: 1px; + text-decoration: none; +} + +.small_tab_pref { + background-image: url(getImgPath('pmd/Header.png'); ?>); + background-repeat: repeat-x; + text-align: center; + width: 1px; +} + +.small_tab_pref2 { + vertical-align: top; + color: #fff; + background-color: #FF9966; + cursor: default; + text-align: center; + font-weight: bold; + width: 1px; + text-decoration: none; +} + +.butt { + border: #4477aa solid 1px; + font-weight: bold; + height: 19px; + width: 70px; + background-color: #fff; + color: #000; + vertical-align: baseline; +} + +.L_butt2_1 { + padding: 1px; + text-decoration: none; + vertical-align: middle; + cursor: default; +} + +.L_butt2_2 { + padding: 0; + border: #0099CC solid 1px; + background: #FFEE99; + color: #000; + text-decoration: none; + vertical-align: middle; + cursor: default; +} + +/* ---------------------------------------------------------------------------*/ +.bor { + width: 10px; + height: 10px; +} + +.frams1 { + background: url(getImgPath('pmd/1.png'); ?>) no-repeat right bottom; +} + +.frams2 { + background: url(getImgPath('pmd/2.png'); ?>) no-repeat left bottom; +} + +.frams3 { + background: url(getImgPath('pmd/3.png'); ?>) no-repeat left top; +} + +.frams4 { + background: url(getImgPath('pmd/4.png'); ?>) no-repeat right top; +} + +.frams5 { + background: url(getImgPath('pmd/5.png'); ?>) repeat-x center bottom; +} + +.frams6 { + background: url(getImgPath('pmd/6.png'); ?>) repeat-y left; +} + +.frams7 { + background: url(getImgPath('pmd/7.png'); ?>) repeat-x top; +} + +.frams8 { + background: url(getImgPath('pmd/8.png'); ?>) repeat-y right; +} + +#osn_tab { + background-color: #fff; + color: #000; + border: #A9A9A9 solid 1px; +} + +.pmd_header { + background-color: #EAEEF0; + color: #000; + text-align: center; + font-weight: bold; + margin: 0; + padding: 0; + background-image: url(getImgPath('pmd/top_panel.png'); ?>); + background-position: top; + background-repeat: repeat-x; + border-right: #999 solid 1px; + border-left: #999 solid 1px; + height: 28px; + z-index: 101; + width: 100%; + position: fixed; +} + +.pmd_header a { + display: block; + float: ; + margin: 3px 1px 4px; + height: 20px; + border: 1px dotted #fff; +} + +.pmd_header .M_bord { + display: block; + float: ; + margin: 4px; + height: 20px; + width: 2px; +} + +.pmd_header a.first { + margin-right: 1em; +} + +.pmd_header a.last { + margin-left: 1em; +} + +a.M_butt_Selected_down_IE, +a.M_butt_Selected_down { + border: 1px solid #C0C0BB; + background-color: #99FF99; + color: #000; +} + +a.M_butt_Selected_down_IE:hover, +a.M_butt_Selected_down:hover, +a.M_butt:hover { + border: 1px solid #0099CC; + background-color: #FFEE99; + color: #000; +} + +#layer_menu { + z-index: 100; + position: absolute; + : 0; + background-color: #EAEEF0; + border: #999 solid 1px; +} + +#layer_upd_relation { + position: absolute; + : 637px; + top: 224px; + z-index: 100; +} + +#layer_new_relation { + position: absolute; + : 636px; + top: 85px; + z-index: 100; + width: 153px; +} + +#pmd_optionse { + position: absolute; + : 636px; + top: 85px; + z-index: 100; + width: 153px; +} + +#layer_menu_sizer { + background-image: url(getImgPath('pmd/resize.png'); ?>); + cursor: nw-resize; + width: 16px; + height: 16px; +} + +.panel { + position: fixed; + top: 60px; + : 0; + display: none; + background: #FFF; + border: 1px solid gray; + width: 350 px; + height: auto; + padding: 30px 170px 30px; + padding-: 30px; + color: #FFF; + z-index: 102; +} + +a.trigger { + position: fixed; + text-decoration: none; + top: 60px; + : 0; + color: #fff; + padding: 10px 40px 10px 15px; + background: #333 url(getImgPath('pmd/plus.png'); ?>) 85% 55% no-repeat; + border: 1px solid #444; + display: block; + z-index: 102; +} + +a.trigger:hover { + color: #080808; + background: #fff696 url(getImgPath('pmd/plus.png'); ?>) 85% 55% no-repeat; + border: 1px solid #999; +} + +a.active.trigger { + background: #222 url(getImgPath('pmd/minus.png'); ?>) 85% 55% no-repeat; + z-index: 999; +} + +a.active.trigger:hover { + background: #fff696 url(getImgPath('pmd/minus.png'); ?>) 85% 55% no-repeat; +} + +h2.tiger { + background-repeat: repeat-x; + padding: 1px; + font-weight: bold; + padding: 50px 20px 50px; + margin: 0 0 5px 0; + width: 250px; + float: ; + color : #333; + text-align: center; +} + +h2.tiger a { + background-image: url(getImgPath('pmd/Header.png'); ?>); + text-align: center; + text-decoration: none; + color : #333; + display: block; +} + +h2.tiger a:hover { + color: #000; + background-image: url(getImgPath('pmd/Header_Linked.png'); ?>); +} + +h2.active { + background-image: url(getImgPath('pmd/Header.png'); ?>); + background-repeat: repeat-x; + padding: 1px; + background-position: left bottom; +} + +.toggle_container { + margin: 0 0 5px; + padding: 0; + border-top: 1px solid #d6d6d6; + background: #FFF; + width: 250px; + overflow: hidden; + font-size: 1.2em; + clear: both; +} + +.toggle_container .block { + background-color: #DBE4E8; + padding: 40px 15px 40px 15px; /*--Padding of Container--*/ + border:1px solid #999; + color: #000; +} + +.history_table { + text-align: center; + background-color: #9999CC; +} + +.history_table2 { + text-align: center; + background-color: #DBE4E8; +} + +#filter { + display: none; + position: absolute; + top: 0%; + left: 0%; + width: 100%; + height: 100%; + background-color: #CCA; + z-index: 10; + opacity: .5; + filter: alpha(opacity=50); +} + +#box { + display: none; + position: absolute; + top: 20%; + : 30%; + width: 500px; + height: 220px; + padding: 48px; + margin: 0; + border: 1px solid #000; + background-color: #fff; + z-index: 101; + overflow: visible; +} + +#boxtitle { + position: absolute; + float: center; + top: 0; + : 0; + width: 593px; + height: 20px; + padding: 0; + padding-top: 4px; + margin: 0; + border-bottom: 4px solid #3CF; + background-color: #D0DCE0; + color: black; + font-weight: bold; + padding-: 2px; + text-align: ; +} + +#tblfooter { + background-color: #D3DCE3; + float: ; + padding-top: 10px; + color: black; + font-weight: normal; +} + +#foreignkeychk { + text-align: ; + position: absolute; + cursor: pointer; +} diff --git a/phpMyAdmin/themes/pmahomme/css/resizable-menu.css.php b/phpMyAdmin/themes/pmahomme/css/resizable-menu.css.php new file mode 100644 index 0000000..21d90dc --- /dev/null +++ b/phpMyAdmin/themes/pmahomme/css/resizable-menu.css.php @@ -0,0 +1,57 @@ + +ul.resizable-menu a, +ul.resizable-menu span { + display: block; + margin: 0; + padding: 0; + white-space: nowrap; +} + +ul.resizable-menu .submenu { + display: none; + position: relative; +} + +ul.resizable-menu .shown { + display: inline-block; +} + +ul.resizable-menu ul { + margin: 0; + padding: 0; + position: absolute; + list-style-type: none; + display: none; + border: 1px #ddd solid; + z-index: 2; + : 0; +} + +ul.resizable-menu li:hover { + getCssGradient('ffffff', 'e5e5e5'); ?> +} + +ul.resizable-menu li:hover ul, +ul.resizable-menu .submenuhover ul { + display: block; + background: #fff; +} + +ul.resizable-menu ul li { + width: 100%; +} diff --git a/phpMyAdmin/themes/pmahomme/css/rte.css.php b/phpMyAdmin/themes/pmahomme/css/rte.css.php new file mode 100644 index 0000000..0db21a8 --- /dev/null +++ b/phpMyAdmin/themes/pmahomme/css/rte.css.php @@ -0,0 +1,43 @@ + + +.rte_table { + table-layout: fixed; +} + +.rte_table td { + vertical-align: middle; + padding: 0.2em; +} + +.rte_table tr td:nth-child(1) { + font-weight: bold; +} + +.rte_table input, +.rte_table select, +.rte_table textarea { + width: 100%; + margin: 0; + box-sizing: border-box; + -ms-box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; +} + +.rte_table .routine_params_table { + width: 100%; +} diff --git a/phpMyAdmin/themes/pmahomme/css/theme_left.css.php b/phpMyAdmin/themes/pmahomme/css/theme_left.css.php deleted file mode 100644 index 0c2c29d..0000000 --- a/phpMyAdmin/themes/pmahomme/css/theme_left.css.php +++ /dev/null @@ -1,312 +0,0 @@ - -/******************************************************************************/ -/* general tags */ -html { - font-size: get('fontsize') ? $GLOBALS['PMA_Config']->get('fontsize') : $_COOKIE['pma_fontsize']); ?>; -} - -input, select, textarea { - font-size: 1em; -} - -body { - - font-family: ; - - background: url(./themes/pmahomme/img/left_nav_bg.png) repeat-y right 0% #f3f3f3; - border-right: 1px solid #aaa; - color: ; - margin: 0; - padding: 0; -} - -a img { - border: 0; -} - -a:link, -a:visited, -a:active { - text-decoration: none; - color: #0000FF; -} - -ul { - margin:0; -} - -form { - margin: 0; - padding: 0; - display: inline; -} - -select#select_server, -select#lightm_db { - width: 100%; -} - -/* buttons in some browsers (eg. Konqueror) are block elements, - this breaks design */ -button { - display: inline; -} - -/******************************************************************************/ -/* classes */ - -.navi_dbName { - font-weight: bold; - color: ; -} - -/******************************************************************************/ -/* specific elements */ - -div#pmalogo { - -} - -div#recentTableList { - text-align: center; - margin: 20px 10px 0px 10px; -} - -div#recentTableList select { - width: 100%; -} - -div#pmalogo, -div#leftframelinks, -div#databaseList { - text-align: center; - margin: 5px 10px 0px 10px; -} - -ul#databaseList { - margin: 0.8em 0px; - padding-bottom: 0.5em; - padding-: 0.3em; - font-style: italic; -} - -ul#databaseList span { - padding: 5px; -} - -ul#databaseList a { - color: #333; - background: url(./themes/pmahomme/img/database.png) no-repeat 0 5px transparent; - display: block; - text-indent: 0; - padding: 5px 5px 5px 25px; - font-style: normal; -} - -div#navidbpageselector { - margin: 0.1em; - text-align: center; -} - -div#navidbpageselector a, -div#navidbpageselector select{ - color: #333; - margin: 0.2em; -} - -ul#databaseList ul { - margin: 0; - padding: 0; -} - -ul#databaseList li { - list-style: none; - text-indent: 20px; - margin: 0; - padding: 0; -} - -ul#databaseList a:hover { - background-color: #e4e4e4; -} - -ul#databaseList li.selected a { - background: ; - color: ; -} - -div#leftframelinks .icon { - padding: 0; - margin: 0; -} - -div#reloadlink a img, -div#leftframelinks a img.icon { - margin: 0.3em; - margin-top: 0.7em; - border: 0; -} - -div#leftframelinks a:hover img { - -} - -/* serverlist */ -#body_leftFrame #list_server { - list-style-image: url(/original/img/s_host.png); - list-style-position: inside; - list-style-type: none; - margin: 0; - padding: 0; -} - -#body_leftFrame #list_server li { - margin: 0; - padding: 0; -} - -div#left_tableList {margin:10px 10px 0 10px;} -div#left_tableList ul { - list-style-type: none; - list-style-position: outside; - margin: 0; - padding: 0; -} - -div#left_tableList ul ul { - font-size: 100%; -} - -div#left_tableList a { - color: ; - text-decoration: none; -} - -div#left_tableList a:hover { - background: ; - color: ; - text-decoration: underline; -} - -div#left_tableList li { - margin: 0; - padding: 2px 0; - white-space: nowrap; -} - -#newtable { - margin-top: 15px !important; -} - -#newtable a { - display: block; - padding: 1px; - getCssGradient('ffffff', 'cccccc'); ?> - border: 1px solid #aaa; - -moz-border-radius: 20px; - -webkit-border-radius: 20px; - border-radius: 20px; -} - -#newtable li:hover { - background: transparent !important; -} - -#newtable a:hover { - getCssGradient('cccccc', 'dddddd'); ?> -} - -#newtable li a:hover { - text-decoration: none; -} - -select{ - -moz-border-radius:2px 2px 2px 2px; - -moz-box-shadow:0 1px 2px #DDDDDD; - border:1px solid #aaa; - color:#333333; - padding:3px; - background:url(./themes/pmahomme/img/input_bg.gif); -} - - -/* marked items */ -div#left_tableList > ul li.marked > a, -div#left_tableList > ul li.marked { - background: #e4e4e4; - color: ; -} - - - -div#left_tableList > ul li:hover > a, -div#left_tableList > ul li:hover { - background: #e4e4e4; - color: ; -} - - -div#left_tableList img { - padding: 0; - vertical-align: middle; -} - -div#left_tableList ul ul { - margin-: 0; - padding-: 0.1em; - border-: 0.1em solid ; - padding-bottom: 0.1em; - border-bottom: 0.1em solid ; -} - -/* for the servers list in navi panel */ -#serverinfo .item { - white-space: nowrap; - color: ; -} -#serverinfo a:hover { - background: ; - color: ; -} -#reloadlink { - clear: both; - float: ; - display: block; - padding: 1em; -} - -#NavFilter { - display: none; -} - -#clear_fast_filter { - background: white; - color: black; - cursor: pointer; - padding: 0; - margin: 0; - position: relative; - right: 3ex; -} - -#fast_filter { - width: 85%; - padding: 0.1em; -} - -#fast_filter.gray { - color: gray; -} \ No newline at end of file diff --git a/phpMyAdmin/themes/pmahomme/css/theme_print.css.php b/phpMyAdmin/themes/pmahomme/css/theme_print.css.php deleted file mode 100644 index 428ec8d..0000000 --- a/phpMyAdmin/themes/pmahomme/css/theme_print.css.php +++ /dev/null @@ -1,42 +0,0 @@ - -/* For printview */ -body, table, th, td { - color: #000000; - background-color: #ffffff; -} - -img { - border: 0; -} - -table, th, td { - border-width: 0.1em; - border-color: #000000; - border-style: solid; -} - -table { - border-collapse: collapse; - border-spacing: 0; -} - -th, td { - padding: 0.2em; -} - -th { - font-weight: bold; - background-color: #e5e5e5; -} - -.hide { - display: none; -} diff --git a/phpMyAdmin/themes/pmahomme/css/theme_right.css.php b/phpMyAdmin/themes/pmahomme/css/theme_right.css.php deleted file mode 100644 index e30f687..0000000 --- a/phpMyAdmin/themes/pmahomme/css/theme_right.css.php +++ /dev/null @@ -1,3736 +0,0 @@ - -/******************************************************************************/ - -/* general tags */ -html { - font-size: get('fontsize') ? $GLOBALS['PMA_Config']->get('fontsize') : ( - isset($_COOKIE['pma_fontsize']) ? $_COOKIE['pma_fontsize'] : '82%'));?>; -} - -input, select, textarea { - font-size: 1em; -} - - -body { - - font-family: ; - - padding: 0; - margin: 0 0.5em 0 0; - color: #444; - background: #fff; -} - - -textarea, tt, pre, code { - font-family: ; -} - -h1 { - font-size: 140%; - font-weight: bold; -} - -h2 { - font-size: 2em; - font-weight: normal; - text-shadow: 0 1px 0 #fff; - padding: 10px 0 10px 3px; - color: #777; -} - -/* Hiding icons in the page titles */ -h2 img{display:none;} -h2 a img{display:inline;} - -.data, -.data_full_width { - margin: 0 0 12px 0; -} - -.data_full_width { - width: 100%; -} - -#table_results td.data { -border-right: 1px solid #BBBBBB; -} - -h3 { - font-weight: bold; -} - -a, a:link, -a:visited, -a:active { - text-decoration: none; - color: #235a81; - cursor: pointer; - outline: none; - -} - -a:hover { - text-decoration: underline; - color: #235a81; -} - -#initials_table { - background:#f3f3f3; - border:1px solid #aaa; - margin-bottom:10px; - -moz-border-radius:5px; - -webkit-border-radius:5px; - border-radius:5px; -} - -#initials_table td{padding:8px !important} - -#initials_table a { - border:1px solid #aaa; - background:#fff; - padding:4px 8px; - -moz-border-radius:5px; - -webkit-border-radius:5px; - border-radius:5px; - getCssGradient('ffffff', 'cccccc'); ?> -} - -dfn { - font-style: normal; -} - -dfn:hover { - font-style: normal; - cursor: help; -} - -th { - font-weight: bold; - color: ; - background: #f3f3f3; - getCssGradient('ffffff', 'cccccc'); ?> -} - -a img { - border: 0; -} - -hr { - color: ; - background-color: ; - border: 0; - height: 1px; -} - -form { - padding: 0; - margin: 0; - display: inline; -} - -input[type=text]{ - border-radius:2px; - -moz-border-radius:2px; - -webkit-border-radius:2px; - - box-shadow:0 1px 2px #ddd; - -moz-box-shadow:0 1px 2px #ddd; - -webkit-box-shadow:0 1px 2px #ddd; - - background:url(getImgPath(); ?>input_bg.gif); - border:1px solid #aaa; - color:#555555; - padding:4px; - margin:6px; - -} - -input[type=password]{ - border-radius:2px; - -moz-border-radius:2px; - -webkit-border-radius:2px; - - box-shadow:0 1px 2px #ddd; - -moz-box-shadow:0 1px 2px #ddd; - -webkit-box-shadow:0 1px 2px #ddd; - - background:url(getImgPath(); ?>input_bg.gif); - border:1px solid #aaa; - color:#555555; - padding:4px; - margin:6px; - -} - -input[type=submit]{ - font-weight:bold; - margin-left:14px; - border: 1px solid #aaa; - padding: 3px 7px; - color: #111; - text-decoration: none; - background: #ddd; - - border-radius: 12px; - -webkit-border-radius: 12px; - -moz-border-radius: 12px; - - text-shadow: 0 1px 0 #fff; - - getCssGradient('ffffff', 'cccccc'); ?> -} - -input[type=submit]:hover{position: relative; - getCssGradient('cccccc', 'dddddd'); ?> - cursor:pointer; -} - -input[type=submit]:active{position: relative; - top: 1px; - left: 1px; -} -textarea { - overflow: visible; - height: em; -} -textarea.char { - height: em; -} - -fieldset { - margin-top: 1em; - border-radius:4px 4px 0 0; - -moz-border-radius:4px 4px 0 0; - -webkit-border-radius:4px 4px 0 0; - padding:5px; - border: #aaa solid 1px; - padding: 1.5em; - background: #eee; - text-shadow:0 1px 0 #fff; - -moz-box-shadow: 1px 1px 2px #fff inset; - -webkit-box-shadow: 1px 1px 2px #fff inset; - box-shadow: 1px 1px 2px #fff inset; -} - -fieldset fieldset { - margin: 0.8em; - background:#fff; - border:1px solid #aaa; - background:none repeat scroll 0 0 #E8E8E8; - -} - -fieldset legend { - font-weight: bold; - color: #444; - padding:5px 10px; - border-radius:2px; - -moz-border-radius:2px; - -webkit-border-radius:2px; - border:1px solid #aaa; - background-color: #fff; - -moz-box-shadow:3px 3px 15px #bbb; - -webkit-box-shadow:3px 3px 15px #bbb; - box-shadow:3px 3px 15px #bbb; -} - -/* buttons in some browsers (eg. Konqueror) are block elements, - this breaks design */ -button { - display: inline; -} - -table caption, -table th, -table td { - padding: 0.3em; - margin: 0.1em; - vertical-align: top; - text-shadow:0 1px 0 #FFFFFF; -} - -/* 3.4 */ -table{border-collapse:collapse;} -th{border-right:1px solid #fff; text-align:left;} - - -img, button { - vertical-align: middle; -} - -input[type="checkbox"],input[type="radio"] { - vertical-align: -11%; -} - - -select{ - -moz-border-radius:2px; - -webkit-border-radius:2px; - border-radius:2px; - - -moz-box-shadow:0 1px 2px #ddd; - -webkit-box-shadow:0 1px 2px #ddd; - box-shadow:0 1px 2px #ddd; - - border:1px solid #aaa; - color:#333333; - padding:3px; - background:url(getImgPath(); ?>input_bg.gif) -} - -select[multiple] { - getCssGradient('ffffff', 'f2f2f2'); ?> -} - -/******************************************************************************/ -/* classes */ -.clearfloat { - clear: both; -} - -.floatleft { - float: ; - margin-: 1em; -} - -.paddingtop { - padding-top: 1em; -} - -.separator { - color: white; - text-shadow: 0 1px 0 black; -} - -div.tools { - /* border: 1px solid #000000; */ - padding: 0.2em; -} - -div.tools a{color:#3a7ead !important;} - -div.tools, -fieldset.tblFooters { - margin-top: 0; - margin-bottom: 0.5em; - /* avoid a thick line since this should be used under another fieldset */ - border-top: 0; - text-align: ; - float: none; - clear: both; - -webkit-border-radius:0 0 4px 4px; - -moz-border-radius:0 0 4px 4px; - border-radius: 0 0 4px 5px; -} - -div.null_div { - height: 20px; - text-align: center; - font-style:normal; - min-width:50px; -} - -fieldset .formelement { - float: ; - margin-: 0.5em; - /* IE */ - white-space: nowrap; -} - -/* revert for Gecko */ -fieldset div[class=formelement] { - white-space: normal; -} - -button.mult_submit { - border: none; - background-color: transparent; -} - -/* odd items 1,3,5,7,... */ -table tr.odd th, -.odd { - background: #fff; - getCssIEClearFilter(); ?> -} - -/* even items 2,4,6,8,... */ -/* (tested on CRTs and ACLs) */ -table tr.even th, -.even { - background: #DFDFDF; - getCssIEClearFilter(); ?> -} - -/* odd table rows 1,3,5,7,... */ -table tr.odd th, -table tr.odd, -table tr.even th, -table tr.even { - text-align: ; -} - - -/* marked table rows */ -td.marked, -table tr.marked td, -table tr.marked th, -table tr.marked { - background: url(getImgPath(); ?>marked_bg.png) repeat-x #b6c6d7; - color: ; -} - - - -/* hovered items */ -.odd:hover, -.even:hover, -.hover, -.structure_actions_dropdown { - background: url(getImgPath(); ?>marked_bg.png) repeat-x #b6c6d7; /* 3.4 */ - color: ; -} - -/* hovered table rows */ -table tr.odd:hover th, -table tr.even:hover th, -table tr.hover th { - background: url(getImgPath(); ?>marked_bg.png) repeat-x #b6c6d7; /* 3.4 */ - color: ; -} - - -/** - * marks table rows/cells if the db field is in a where condition - */ -.condition { - border-color: !important; -} - -th.condition { - border-width: 1px 1px 0 1px; - border-style: solid; -} - -td.condition { - border-width: 0 1px 0 1px; - border-style: solid; -} - -tr:last-child td.condition { - border-width: 0 1px 1px 1px; -} - - -/* for first th which must have right border set (ltr only) */ -.before-condition { - border-right: 1px solid ; -} - - -/** - * cells with the value NULL - */ -td.null { - font-style: italic; - text-align: ; -} - -table .valueHeader { - text-align: ; - white-space: normal; -} -table .value { - text-align: ; - white-space: normal; -} -/* IE doesnt handles 'pre' right */ -table [class=value] { - white-space: normal; -} - - - -.value { - font-family: ; -} - -.attention { - color: red; - font-weight: bold; -} -.allfine { - color: green; -} - - -img.lightbulb { - cursor: pointer; -} - -.pdflayout { - overflow: hidden; - clip: inherit; - background-color: #FFFFFF; - display: none; - border: 1px solid #000000; - position: relative; -} - -.pdflayout_table { - background: #D3DCE3; - color: #000000; - overflow: hidden; - clip: inherit; - z-index: 2; - display: inline; - visibility: inherit; - cursor: move; - position: absolute; - font-size: 80%; - border: 1px dashed #000000; -} - -/* MySQL Parser */ -.syntax { - font-family: Verdan, Arial, Tahoma; - font-size: 110%; -} - -.syntax a { - text-decoration: none; - border-bottom:1px dotted black; -} - -.syntax_comment { - padding-left: 4pt; - padding-right: 4pt; -} - -.syntax_digit { -} - -.syntax_digit_hex { -} - -.syntax_digit_integer { -} - -.syntax_digit_float { -} - -.syntax_punct { -} - -.syntax_alpha { -} - -.syntax_alpha_columnType { - text-transform: uppercase; -} - -.syntax_alpha_columnAttrib { - text-transform: uppercase; -} - -.syntax_alpha_reservedWord { - text-transform: uppercase; - font-weight: bold; -} - -.syntax_alpha_functionName { - text-transform: uppercase; -} - -.syntax_alpha_identifier { -} - -.syntax_alpha_charset { -} - -.syntax_alpha_variable { -} - -.syntax_quote { - white-space: pre; -} - -.syntax_quote_backtick { -} - -/* leave some space between icons and text */ -img.footnotemarker { - display: none; -} - -/* no extra space in table cells */ -td .icon { - margin: 0; -} - -.selectallarrow { - margin-: 0.3em; - margin-: 0.6em; -} - -/* message boxes: error, confirmation */ -.success h1, -.notice h1, -div.error h1 { - border-bottom: 2px solid; - font-weight: bold; - text-align: ; - margin: 0 0 0.2em 0; -} - -div.success, -div.notice, -div.error, -div.footnotes { - margin: 0.5em 0 1.3em 0; - border: 1px solid; - - background-repeat: no-repeat; - - background-position: 10px 50%; - padding: 10px 10px 10px 25px; - - background-position: 99% 50%; - padding: 25px 10px 10px 10px - - - padding: 0.3em; - - - -moz-border-radius:5px; - -webkit-border-radius:5px; - border-radius:5px; - - -moz-box-shadow: 0 1px 1px #fff inset; - -webkit-box-shadow: 0 1px 1px #fff inset; - box-shadow: 0 1px 1px #fff inset; -} - -.success a{text-decoration:underline;} -.notice a{text-decoration:underline;} -.error a{text-decoration:underline;} -.footnotes a{text-decoration:underline;} - -.success { - color: #000000; - background-color: #ebf8a4; -} - -h1.success, div.success { - border-color: #a2d246; - - background-image: url(getImgPath(); ?>s_success.png); - background-repeat: no-repeat; - - background-position: 5px 50%; - - background-position: 97% 50%; - - -} -.success h1 { - border-color: #00FF00; -} - -.notice, .footnotes { - color: #000; - background-color: #e8eef1; -} - -h1.notice, -div.notice, -div.footnotes { - border-color: #3a6c7e; - - background-image: url(getImgPath(); ?>s_notice.png); - background-repeat: no-repeat; - - background-position: 5px 50%; - - background-position: 97% 50%; - - -} - -.notice h1 { - border-color: #ffb10a; -} - -.error { - border:1px solid maroon !important; - color: #000; - background:pink; -} - -h1.error, -div.error { - border-color: #333; - - background-image: url(getImgPath(); ?>s_error.png); - background-repeat: no-repeat; - - background-position: 5px 50%; - - background-position: 97% 50%; - - -} - -div.error h1 { - border-color: #ff0000; -} - -.confirmation { - color: #000000; - background-color: pink; -} - -fieldset.confirmation { -} - -fieldset.confirmation legend { -} - -/* end messageboxes */ - -.tblcomment { - font-size: 70%; - font-weight: normal; - color: #000099; -} - -.tblHeaders { - font-weight: bold; - color: ; - background: ; -} - -div.tools, -.tblFooters { - font-weight: normal; - color: ; - background: ; -} - -.tblHeaders a:link, -.tblHeaders a:active, -.tblHeaders a:visited, -div.tools a:link, -div.tools a:visited, -div.tools a:active, -.tblFooters a:link, -.tblFooters a:active, -.tblFooters a:visited { - color: #0000FF; -} - -.tblHeaders a:hover, -div.tools a:hover, -.tblFooters a:hover { - color: #FF0000; -} - -/* forbidden, no privilegs */ -.noPrivileges { - color: #FF0000; - font-weight: bold; -} - -/* disabled text */ -.disabled, -.disabled a:link, -.disabled a:active, -.disabled a:visited { - color: #666666; -} - -.disabled a:hover { - color: #666666; - text-decoration: none; -} - -tr.disabled td, -td.disabled { - background-color: #f3f3f3; - color:#aaa; -} - -.nowrap { - white-space: nowrap; -} - -/** - * zoom search - */ -div#resizer { - width: 600px; - height: 400px; -} -div#querychart { - float: left; - width: 600px; -} - -/** - * login form - */ -body.loginform h1, -body.loginform a.logo { - display: block; - text-align: center; -} - -body.loginform { - text-align: center; -} - -body.loginform div.container { - text-align: ; - width: 30em; - margin: 0 auto; -} - -form.login label { - float: ; - width: 10em; - font-weight: bolder; -} - -.commented_column { - border-bottom: 1px dashed black; -} - -.column_attribute { - font-size: 70%; -} - -/******************************************************************************/ -/* specific elements */ - -/* topmenu */ -#topmenu a { - text-shadow: 0 1px 0 #fff; -} - -#topmenu .error { - background:#eee;border: 0 !important;color:#aaa; -} - -ul#topmenu, ul#topmenu2, ul.tabs { - font-weight: bold; - list-style-type: none; - margin: 0; - padding: 0; - -} - -ul#topmenu2 { - margin: 0.25em 0.5em 0; - height: 2em; - clear: both; -} - -ul#topmenu li, ul#topmenu2 li { - float: ; - margin: 0; - vertical-align: middle; -} - -#topmenu img, #topmenu2 img { - margin-right:0.5em; - vertical-align:-3px; -} - -.menucontainer{ - background:url(getImgPath(); ?>tab_bg.png) repeat-x; - border-top:1px solid #aaa; -} - -/* default tab styles */ -.tabactive { - background:#fff !important; -} - -ul#topmenu a, ul#topmenu span { - display: block; - margin: 0; - padding: 0; - white-space: nowrap; -} - -ul#topmenu ul a { - margin: 0; - -} - -ul#topmenu .submenu { - display: none; - position: relative; -} - -ul#topmenu .shown { - display: inline-block; -} - -ul#topmenu ul { - margin: 0; - padding: 0; - position: absolute; - list-style-type: none; - display: none; - border: 1px #ddd solid; - z-index: 2; -} - -ul#topmenu ul.only { - left: 0; -} - -ul#topmenu ul.notonly { - right: 0; -} - -ul#topmenu li:hover { - background:url(getImgPath(); ?>tab_hover_bg.png) repeat-x 50% 0%!important; -} - -ul#topmenu li:hover ul, ul#topmenu .submenuhover ul { - display: block; - font-weight:3em; - background:#fff; -} - -ul#topmenu ul li { - width: 100%; -} - -ul#topmenu2 a { - display: block; - margin: 7px 6px 7px 0; - padding: 4px 10px; - white-space: nowrap; - border:1px solid #ddd; - border-radius: 20px; - -moz-border-radius: 20px; - -webkit-border-radius: 20px; - background:#f2f2f2; - -} - -/* disabled tabs */ -ul#topmenu span.tab { - color: #666666; -} - -fieldset.caution a { - color: #FF0000; -} -fieldset.caution a:hover { - color: #ffffff; - background-color: #FF0000; -} - - -/* active tab */ -ul#topmenu a.tabactive, ul#topmenu2 a.tabactive { - color: black; -} - -ul#topmenu ul { - background: ; -} - -#topmenu { - margin-top: 0.5em; - padding: 0.1em 0.3em 0.1em 0.3em; -} - -ul#topmenu ul { - -moz-box-shadow: 1px 1px 6px #ddd; - -webkit-box-shadow: 2px 2px 3px #666; - box-shadow: 2px 2px 3px #666; -} - -ul#topmenu > li { - border-right: 1px solid #fff; - border-left: 1px solid #ccc; -} - -/* default tab styles */ -ul#topmenu a, ul#topmenu span { - padding: 0.6em; -} - -ul#topmenu ul a { - border-width: 1pt 0 0 0; - -moz-border-radius: 0; - -webkit-border-radius: 0; - border-radius: 0; -} - -ul#topmenu ul li:first-child a { - border-width: 0; -} - -/* enabled hover/active tabs */ -ul#topmenu > li > a:hover, -ul#topmenu > li > .tabactive { - text-decoration: none; -} - -ul#topmenu ul a:hover, -ul#topmenu ul .tabactive { - text-decoration: none; -} - -ul#topmenu a.tab:hover, -ul#topmenu .tabactive { - /* background-color: ; */ -} - -ul#topmenu2 a.tab:hover, -ul#topmenu2 a.tabactive { - background-color: ; - border-radius: 0.3em; - -moz-border-radius: 0.3em; - -webkit-border-radius: 0.3em; - text-decoration: none; -} - -/* to be able to cancel the bottom border, use
  • */ -ul#topmenu > li.active { - /* border-bottom: 0pt solid ; */ - border-right: 0; -} - -/* disabled tabs */ -ul#topmenu span.tab, -a.error { - cursor: url(getImgPath(); ?>error.ico), default; - color:#ccc; -} - -/* end topmenu */ - -/* zoom search */ -div#dataDisplay input, div#dataDisplay select { - margin: 0; - margin-: 0.5em; -} -div#dataDisplay th { - line-height: 2em; -} - -/* Calendar */ -table.calendar { - width: 100%; -} -table.calendar td { - text-align: center; -} -table.calendar td a { - display: block; -} - -table.calendar td a:hover { - background-color: #CCFFCC; -} - -table.calendar th { - background-color: #D3DCE3; -} - -table.calendar td.selected { - background-color: #FFCC99; -} - -img.calendar { - border: none; -} -form.clock { - text-align: center; -} -/* end Calendar */ - - -/* table stats */ -div#tablestatistics table { - float: ; - margin-bottom: 0.5em; - margin-: 1.5em; - margin-top: 0.5em; -} - -/* END table stats */ - - -/* server privileges */ -#tableuserrights td, -#tablespecificuserrights td, -#tabledatabases td { - vertical-align: middle; -} -/* END server privileges */ - - -/* Heading */ -#topmenucontainer { - padding-right: 1em; - width: 100%; - background-color: #dcdcdc; -} - -#serverinfo { - border-bottom:1px solid #fff; - background:#888; - padding: 0.3em 0.9em; - text-shadow:0 1px 0 #000000; - width: 10000px; - overflow: hidden; -} - -#serverinfo .item { - white-space: nowrap; - color:#fff; - float: -} - -#span_table_comment { - font-weight: normal; - font-style: italic; - white-space: nowrap; -} - -#serverinfo img { - margin: 0 0.1em 0 0.2em; -} - - -#textSQLDUMP { - width: 95%; - height: 95%; - font-family: "Courier New", Courier, mono; - font-size: 110%; -} - -#TooltipContainer { - position: absolute; - z-index: 99; - width: 20em; - height: auto; - overflow: visible; - visibility: hidden; - background-color: #ffffcc; - color: #006600; - border: 0.1em solid #000000; - padding: 0.5em; -} - -/* user privileges */ -#fieldset_add_user_login div.item { - border-bottom: 1px solid silver; - padding-bottom: 0.3em; - margin-bottom: 0.3em; -} - -#fieldset_add_user_login label { - float: ; - display: block; - width: 10em; - max-width: 100%; - text-align: ; - padding-: 0.5em; -} - -#fieldset_add_user_login span.options #select_pred_username, -#fieldset_add_user_login span.options #select_pred_hostname, -#fieldset_add_user_login span.options #select_pred_password { - width: 100%; - max-width: 100%; -} - -#fieldset_add_user_login span.options { - float: ; - display: block; - width: 12em; - max-width: 100%; - padding-: 0.5em; -} - -#fieldset_add_user_login input { - width: 12em; - clear: ; - max-width: 100%; -} - -#fieldset_add_user_login span.options input { - width: auto; -} - -#fieldset_user_priv div.item { - float: ; - width: 9em; - max-width: 100%; -} - -#fieldset_user_priv div.item div.item { - float: none; -} - -#fieldset_user_priv div.item label { - white-space: nowrap; -} - -#fieldset_user_priv div.item select { - width: 100%; -} - -#fieldset_user_global_rights fieldset { - float: ; -} -/* END user privileges */ - - -/* serverstatus */ - -.linkElem:hover { - text-decoration: underline; - color: #235a81; - cursor: pointer; -} - -h3#serverstatusqueries span { - font-size:60%; - display:inline; -} - -img.sortableIcon { - float:right; - background-repeat:no-repeat; - margin:0; -} - -.buttonlinks { - float: ; - white-space: nowrap; -} - -.jsfeature { - display: none; /* Made visible with js */ -} - -/* Also used for the variables page */ -fieldset#tableFilter { - margin-bottom:1em; -} - -div#serverStatusTabs { - margin-top:1em; -} - -caption a.top { - float: ; -} - -div#serverstatusquerieschart { - float:; - width:500px; - height:350px; - padding-: 30px; -} - -table#serverstatusqueriesdetails, table#serverstatustraffic { - float: ; -} - -table#serverstatusqueriesdetails th { - min-width: 35px; -} - -table#serverstatusvariables { - width: 100%; - margin-bottom: 1em; -} -table#serverstatusvariables .name { - width: 18em; - white-space:nowrap; -} -table#serverstatusvariables .value { - width: 6em; -} -table#serverstatusconnections { - float: ; - margin-: 30px; -} - -div#serverstatus table tbody td.descr a, -div#serverstatus table .tblFooters a { - white-space: nowrap; -} - -div.liveChart { - clear:both; - min-width:500px; - height:400px; - padding-bottom:80px; -} - -#addChartDialog input[type="text"] { - margin: 0; - padding: 3px; -} - -div#chartVariableSettings { - border:1px solid #ddd; - background-color:#E6E6E6; - margin-left:10px; -} - -table#chartGrid div.monitorChart { - background: #EBEBEB; -} - -div#serverstatus div.tabLinks { - float:; - padding-bottom: 10px; -} - -.popupContent { - display: none; - position: absolute; - border: 1px solid #CCC; - margin:0; - padding:3px; - -moz-box-shadow: 1px 1px 6px #ddd; - -webkit-box-shadow: 2px 2px 3px #666; - box-shadow: 2px 2px 3px #666; - background-color:white; - z-index: 2; -} - -div#logTable { - padding-top: 10px; - clear: both; -} - -div#logTable table { - width:100%; -} - -div#queryAnalyzerDialog { - min-width: 700px; -} - -div#queryAnalyzerDialog div.CodeMirror-scroll { - height:auto; -} - -div#queryAnalyzerDialog div#queryProfiling { - height: 250px; -} - -div#queryAnalyzerDialog td.explain { - width: 250px; -} - -div#queryAnalyzerDialog table.queryNums { - display: none; - border:0; - text-align:left; -} - -.smallIndent { - padding-left: 7px; -} - - -/* end serverstatus */ - -/* server variables */ - -a.editLink { - float: ; - font-family:sans-serif; -} - -table.serverVariableEditTable { - border:0; - margin:0; - padding:0; - width:100%; -} -table.serverVariableEditTable td { - border:0; - margin:0; - padding:0; -} -table.serverVariableEditTable td:first-child { - white-space:nowrap; - vertical-align:middle; -} - -table.serverVariableEditTable input { - width:95%; -} - -table#serverVariables td { - height:18px; -} - -/* end server variables */ - - -p.notice { - margin: 1.5em 0; - border: 1px solid #000; - - background-repeat: no-repeat; - - background-position: 10px 50%; - padding: 10px 10px 10px 25px; - - background-position: 99% 50%; - padding: 25px 10px 10px 10px - - - padding: 0.3em; - - -moz-border-radius:5px; - -webkit-border-radius:5px; - border-radius:5px; - -moz-box-shadow: 0 1px 2px #fff inset; - -webkit-box-shadow: 0 1px 2px #fff inset; - box-shadow: 0 1px 2px #fff; inset; - background:#555; - color:#d4fb6a; -} - -p.notice a { - color:#fff; - text-decoration:underline; -} - -/* querywindow */ -body#bodyquerywindow { - margin: 0; - padding: 0; - background-image: none; - background-color: #F5F5F5; -} - -div#querywindowcontainer { - margin: 0; - padding: 0; - width: 100%; -} - -div#querywindowcontainer fieldset { - margin-top: 0; -} -/* END querywindow */ - -/* profiling */ - -div#profilingchart { - width:550px; - height:370px; - float:left; -} - -/* END profiling */ - -/* table charting */ - -#resizer { - border: 1px solid silver; -} -#inner-resizer { /* make room for the resize handle */ - padding: 10px; -} - -/* END table charting */ - -/* querybox */ - -#togglequerybox{margin:0 10px} - -#serverstatus h3 -{ - margin: 15px 0; - font-weight:normal; - color:#999; - font-size:1.7em; -} -#sectionlinks{ - padding:16px; - background:#f3f3f3; - border:1px solid #aaa; - border-radius:5px; - -webkit-border-radius:5px; - -moz-border-radius:5px; - box-shadow: 0 1px 1px #fff inset; - -webkit-box-shadow: 0 1px 1px #fff inset; - -moz-box-shadow: 0 1px 1px #fff inset; -} -#sectionlinks a, .buttonlinks a, a.button { - font-size:0.88em; - font-weight:bold; - text-shadow: 0 1px 0 #fff; - line-height:35px; - margin-left:7px; - border: 1px solid #aaa; - padding: 5px 10px; - color: #111; - text-decoration: none; - background: #ddd; - white-space: nowrap; - border-radius: 20px; - -webkit-border-radius: 20px; - -moz-border-radius: 20px; - box-shadow: 1px 1px 2px rgba(0,0,0,.5); - /* - -webkit-box-shadow: 1px 1px 2px rgba(0,0,0,.5); - -moz-box-shadow: 1px 1px 2px rgba(0,0,0,.5); - text-shadow: #fff 0 1px 0; - */ - getCssGradient('ffffff', 'cccccc'); ?> -} -#sectionlinks a:hover, .buttonlinks a:hover, a.button:hover { - getCssGradient('cccccc', 'dddddd'); ?> -} - -div#sqlquerycontainer { - float: ; - width: 69%; - /* height: 15em; */ -} - -div#tablefieldscontainer { - float: ; - width: 29%; - /* height: 15em; */ -} - -div#tablefieldscontainer select { - width: 100%; - background:#fff; - /* height: 12em; */ -} - -textarea#sqlquery { - width: 100%; - /* height: 100%; */ - -moz-border-radius:4px; - -webkit-border-radius:4px; - border-raduis:4px - border:1px solid #aaa; - padding:5px; - font-family:inherit; -} -textarea#sql_query_edit{ - height:7em; - width: 95%; - display:block; -} -div#queryboxcontainer div#bookmarkoptions { - margin-top: 0.5em; -} -/* end querybox */ - -/* main page */ -#maincontainer { - /* background-image: url(getImgPath(); ?>logo_right.png); */ - /* background-position: bottom; */ - /* background-repeat: no-repeat; */ -} - -#mysqlmaininformation, -#pmamaininformation { - float: ; - width: 49%; -} - -#maincontainer ul { - list-style-type: disc; - vertical-align: middle; -} - -#maincontainer li { - margin-bottom: 0.3em; -} -/* END main page */ - - - -/* iconic view for ul items */ -li#li_create_database { - list-style-image: url(getImgPath(); ?>b_newdb.png); -} - -li#li_select_lang { - list-style-image: url(getImgPath(); ?>s_lang.png); -} - -li#li_select_mysql_collation { - list-style-image: url(getImgPath(); ?>s_asci.png); -} - -li#li_select_theme{ - list-style-image: url(getImgPath(); ?>s_theme.png); -} - -li#li_user_info{ - /* list-style-image: url(getImgPath(); ?>s_rights.png); */ -} - -li#li_mysql_status{ - list-style-image: url(getImgPath(); ?>s_status.png); -} - -li#li_mysql_variables{ - list-style-image: url(getImgPath(); ?>s_vars.png); -} - -li#li_mysql_processes{ - list-style-image: url(getImgPath(); ?>s_process.png); -} - -li#li_mysql_collations{ - list-style-image: url(getImgPath(); ?>s_asci.png); -} - -li#li_mysql_engines{ - list-style-image: url(getImgPath(); ?>b_engine.png); -} - -li#li_mysql_binlogs { - list-style-image: url(getImgPath(); ?>s_tbl.png); -} - -li#li_mysql_databases { - list-style-image: url(getImgPath(); ?>s_db.png); -} - -li#li_export { - list-style-image: url(getImgPath(); ?>b_export.png); -} - -li#li_import { - list-style-image: url(getImgPath(); ?>b_import.png); -} - -li#li_change_password { - list-style-image: url(getImgPath(); ?>s_passwd.png); -} - -li#li_log_out { - list-style-image: url(getImgPath(); ?>s_loggoff.png); -} - -li#li_mysql_privilegs{ - list-style-image: url(getImgPath(); ?>s_rights.png); -} - -li#li_switch_dbstats { - list-style-image: url(getImgPath(); ?>b_dbstatistics.png); -} - -li#li_flush_privileges { - list-style-image: url(getImgPath(); ?>s_reload.png); -} - -li#li_user_preferences { - list-style-image: url(getImgPath(); ?>b_tblops.png); -} -/* END iconic view for ul items */ - - - -#body_browse_foreigners { - background: ; - margin: 0.5em 0.5em 0 0.5em; -} - -#bodyquerywindow { - background: ; -} - -#bodythemes { - width: 500px; - margin: auto; - text-align: center; -} - -#bodythemes img { - border: 0.1em solid black; -} - -#bodythemes a:hover img { - border: 0.1em solid red; -} - -#fieldset_select_fields { - float: ; -} - -#selflink { - clear: both; - display: block; - margin-top: 1em; - margin-bottom: 1em; - background:#f3f3f3; - width: 100%; - border-top: 0.1em solid silver; - text-align: ; - - -} - -#table_innodb_bufferpool_usage, -#table_innodb_bufferpool_activity { - float: ; -} - -#div_mysql_charset_collations table { - float: ; -} - -.operations_half_width { - width: 48%; - float: ; -} - -.operations_full_width { - width: 100%; - clear: both; -} - -#qbe_div_table_list { - float: ; -} - -#qbe_div_sql_query { - float: ; -} - -label.desc { - width: 30em; - float: ; -} - -label.desc sup { - position: absolute; -} - -code.sql, div.sqlvalidate { - display: block; - padding: 1em; - margin-top: 0; - margin-bottom: 0; - border-top: 0; - border-bottom: 0; - max-height: 10em; - overflow: auto; - background: ; -} - -#main_pane_left { - width: 60%; - float: ; - padding-top: 1em; -} - -#main_pane_right { - margin-: 60%; - padding-top: 1em; - padding-: 1em; -} - -.group { - - border:1px solid #999; - background:#f3f3f3; - -moz-border-radius:4px; - -webkit-border-radius:4px; - border-radius:4px; - -moz-box-shadow:2px 2px 5px #ccc; - -webkit-box-shadow:2px 2px 5px #ccc; - box-shadow:3px 3px 10px #ddd; - margin-bottom: 1em; - padding-bottom: 1em; -} - -.group h2 { - background-color: #bbb; - padding: 0.1em 0.3em; - margin-top: 0; - color:#fff; - font-size:1.6em; - font-weight:normal; - text-shadow:0 1px 0 #777; - -moz-box-shadow: 1px 1px 15px #999 inset; - -webkit-box-shadow: 1px 1px 15px #999 inset; - box-shadow: 1px 1px 15px #999 inset; -} - -.group-cnt { - padding: 0 0 0 0.5em; - display: inline-block; - width: 98%; -} - -textarea#partitiondefinition { - height:3em; -} - -/* for elements that should be revealed only via js */ -.hide { - display: none; -} - -#li_select_server { - list-style-image: url(getImgPath(); ?>s_host.png); -} - -#list_server { - list-style-image: none; -} - -/** - * Progress bar styles - */ -div.upload_progress_bar_outer -{ - border: 1px solid black; - width: 202px; -} - -div.upload_progress_bar_inner -{ - background-color: ; - width: 0; - height: 12px; - margin: 1px; -} - -table#serverconnection_src_remote, -table#serverconnection_trg_remote, -table#serverconnection_src_local, -table#serverconnection_trg_local { - float:left; -} -/** - * Validation error message styles - */ -input[type=text].invalid_value, -.invalid_value { - background:#FFCCCC; -} - -/** - * Ajax notification styling - */ - .ajax_notification { - top: 0; /** The notification needs to be shown on the top of the page */ - position: fixed; - margin-top: 0; - margin-right: auto; - margin-bottom: 0; - margin-left: auto; - padding: 5px; /** Keep a little space on the sides of the text */ - width: 350px; - - z-index: 1100; /** If this is not kept at a high z-index, the jQueryUI modal dialogs (z-index:1000) might hide this */ - text-align: center; - display: inline; - left: 0; - right: 0; - background-image: url(getImgPath(); ?>ajax_clock_small.gif); - background-repeat: no-repeat; - background-position: 2%; - border:1px solid #e2b709; - } - -/* additional styles */ -.ajax_notification{ - margin-top:200px;background:#ffe57e; - border-radius:5px; - -moz-border-radius:5px; - -webkit-border-radius:5px; - box-shadow: 0 5px 90px #888; - -moz-box-shadow: 0 5px 90px #888; - -webkit-box-shadow: 0 5px 90px #888; -} - -#loading_parent { - /** Need this parent to properly center the notification division */ - position: relative; - width: 100%; - } -/** - * Export and Import styles - */ - -.exportoptions h3, .importoptions h3 { - border-bottom: 1px #999999 solid; - font-size: 110%; -} - -.exportoptions ul, .importoptions ul, .format_specific_options ul { - list-style-type: none; - margin-bottom: 15px; -} - -.exportoptions li, .importoptions li { - margin: 7px; -} -.exportoptions label, .importoptions label, .exportoptions p, .importoptions p { - margin: 5px; - float: none; -} - -#csv_options label.desc, #ldi_options label.desc, #latex_options label.desc, #output label.desc{ - float: left; - width: 15em; -} - -.exportoptions, .importoptions { - margin: 20px 30px 30px 10px -} - -.exportoptions #buttonGo, .importoptions #buttonGo { - font-weight:bold; - margin-left:14px; - border: 1px solid #aaa; - padding: 5px 12px; - color: #111; - text-decoration: none; - background: #ddd; - - border-radius: 12px; - -webkit-border-radius: 12px; - -moz-border-radius: 12px; - - text-shadow: 0 1px 0 #fff; - - getCssGradient('ffffff', 'cccccc'); ?> - cursor: pointer; -} -#buttonGo:hover{ - getCssGradient('cccccc', 'dddddd'); ?> -} - -.format_specific_options h3 { - margin: 10px 0 0 10px; - border: 0; -} - -.format_specific_options { - border: 1px solid #999999; - margin: 7px 0; - padding: 3px; -} - -p.desc { - margin: 5px; -} - -/** - * Export styles only - */ -select#db_select, select#table_select { - width: 400px; -} - -.export_sub_options { - margin: 20px 0 0 30px; -} - -.export_sub_options h4 { - border-bottom: 1px #999999 solid; -} - -.export_sub_options li.subgroup { - display: inline-block; - margin-top: 0; -} - -.export_sub_options li { - margin-bottom: 0; -} - -#quick_or_custom, #output_quick_export { - display: none; -} -/** - * Import styles only - */ - -.importoptions #import_notification { - margin: 10px 0; - font-style: italic; -} - -input#input_import_file { - margin: 5px; -} - -.formelementrow { - margin: 5px 0 5px 0; -} - -/** - * GIS data editor styles - */ -a.close_gis_editor { - float: right; -} - -#gis_editor { - display: none; - position: fixed; - _position: absolute; /* hack for IE */ - z-index: 1001; - overflow-y: auto; - overflow-x: hidden; -} - -#gis_data { - min-height: 230px; -} - -#gis_data_textarea { - height: 6em; -} - -#gis_data_editor { - background: #D0DCE0; - padding: 15px; - min-height: 500px; -} - -#gis_data_editor .choice { - display: none; -} - -#gis_data_editor input[type="text"] { - width: 75px; -} - -#popup_background { - display: none; - position: fixed; - _position: absolute; /* hack for IE6 */ - width: 100%; - height: 100%; - top: 0; - left: 0; - background: #000; - z-index: 1000; - overflow: hidden; -} - -/** - * ENUM/SET editor styles - */ -p.enum_notice { - margin: 5px 2px; - font-size: 80%; -} - -.enum_editor_no_js fieldset { - width: 40em; -} - -hr.enum_editor_no_js { - background-color: #aaa; -} - -#enum_editor p { - margin-top: 0; - font-style:italic; -} - -#enum_editor .values, #enum_editor .add, .enum_editor_no_js #values { - width: 100%; -} - -#enum_editor .add td { - vertical-align: middle; - width: 50%; - padding: 0 0 0 1em; -} - -#enum_editor .values td.drop { - width: 1.8em; - cursor: pointer; - vertical-align: middle; -} - -#enum_editor .values input { - margin: 0.1em 0; - padding-right: 2em; - width: 100%; -} - -#enum_editor .values img { - width: 1.8em; - vertical-align: middle; -} - -#enum_editor input.add_value { - margin: 0 0.4em 0 0; -} - -#enum_editor_output textarea, -.enum_editor_no_js input { - width: 100%; - float: right; - margin: 1em 0 0 0; -} - -.enum_editor_no_js { - width: 40em; -} - -.enum_editor_no_js input.submit { - float: left; - margin: 1em 0; -} - -/** - * ENUM/SET editor integration for the routines editor - */ -.enum_hint { - position: relative; -} - -.enum_hint a { - position: absolute; - left: 81%; - bottom: 0.35em; -} - -/** - * Table structure styles - */ -.structure_actions_dropdown { - position: absolute; - padding: 3px; - display: none; - z-index: 100; - background:#fff; - line-height:24px; - border:1px solid #aaa; - -moz-box-shadow: 0 3px 3px #ddd; -} -.structure_actions_dropdown span{display:block;} -.structure_actions_dropdown span:hover{background:#ddd;} - -td.more_opts { - white-space: nowrap; -} - -/** - * Indexes - */ -#index_frm .index_info input, -#index_frm .index_info select { - width: 14em; - box-sizing: border-box; - -ms-box-sizing: border-box; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; -} - -#index_frm .index_info div { - padding: 0.2em 0; -} - -#index_frm .index_info .label { - float: left; - min-width: 12em; -} - -#index_frm .slider { - width: 10em; - margin: 0.6em; - float: ; -} - -#index_frm .add_fields { - float: ; -} - -#index_frm .add_fields input { - margin-: 1em; -} - -#index_frm input { - margin: 0; -} - -#index_frm td { - vertical-align: middle; -} - -table#index_columns { - width: 100%; -} - -table#index_columns select { - width: 100%; -} - -iframe.IE_hack { - z-index: 1; - position: absolute; - display: none; - border: 0; - filter: alpha(opacity=0); -} - -/* config forms */ -.config-form ul.tabs { - margin: 1.1em 0.2em 0; - padding: 0 0 0.3em 0; - list-style: none; - font-weight: bold; -} - -.config-form ul.tabs li { - float: ; - margin-bottom: -1px; -} - -.config-form ul.tabs li a { - display: block; - margin: 0.1em 0.2em 0; - white-space: nowrap; - text-decoration: none; - border: 1px solid ; - border-bottom: 1px solid #aaa; -} - -.config-form ul.tabs li a { - padding: 7px 10px; - -webkit-border-radius: 5px 5px 0 0; - -moz-border-radius: 5px 5px 0 0; - border-radius: 5px 5px 0 0; - background: #f2f2f2; - color: #555; - text-shadow: 0 1px 0 #fff; -} - -.config-form ul.tabs li a:hover, -.config-form ul.tabs li a:active { - background: #e5e5e5; -} - -.config-form ul.tabs li.active a { - background-color: #fff; - margin-top: 1px; - color: #000; - text-shadow: none; - border-color: #aaa; - border-bottom: 1px solid #fff; -} - -.config-form fieldset { - margin-top: 0; - padding: 0; - clear: both; - -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; -} - -.config-form legend { - display: none; -} - -.config-form fieldset p { - margin: 0; - padding: 0.5em; - background: #fff; - border-top: 0; -} - -.config-form fieldset .errors { /* form error list */ - margin: 0 -2px 1em -2px; - padding: 0.5em 1.5em; - background: #FBEAD9; - border: 0 #C83838 solid; - border-width: 1px 0; - list-style: none; - font-family: sans-serif; - font-size: small; -} - -.config-form fieldset .inline_errors { /* field error list */ - margin: 0.3em 0.3em 0.3em 0; - padding: 0; - list-style: none; - color: #9A0000; - font-size: small; -} - -.config-form fieldset th { - padding: 0.3em 0.3em 0.3em 0.5em; - text-align: left; - vertical-align: top; - width: 40%; - background: transparent; - filter: none; -} - -.config-form fieldset .doc, .config-form fieldset .disabled-notice { - margin-left: 1em; -} - -.config-form fieldset .disabled-notice { - font-size: 80%; - text-transform: uppercase; - color: #E00; - cursor: help; -} - -.config-form fieldset td { - padding-top: 0.3em; - padding-bottom: 0.3em; - vertical-align: top; -} - -.config-form fieldset th small { - display: block; - font-weight: normal; - font-family: sans-serif; - font-size: x-small; - color: #444; -} - -.config-form fieldset th, .config-form fieldset td { - border-top: 1px solid; - border-right: none; -} - -fieldset .group-header th { - background: ; -} - -fieldset .group-header + tr th { - padding-top: 0.6em; -} - -fieldset .group-field-1 th, fieldset .group-header-2 th { - padding-left: 1.5em; -} - -fieldset .group-field-2 th, fieldset .group-header-3 th { - padding-left: 3em; -} - -fieldset .group-field-3 th { - padding-left: 4.5em; -} - -fieldset .disabled-field th, -fieldset .disabled-field th small, -fieldset .disabled-field td { - color: #666; - background-color: #ddd; -} - -.config-form .lastrow { - border-top: 1px #000 solid; -} - -.config-form .lastrow { - background: ;; - padding: 0.5em; - text-align: center; -} - -.config-form .lastrow input { - font-weight: bold; -} - -/* form elements */ - -.config-form span.checkbox { - padding: 2px; - display: inline-block; -} - -.config-form .custom { /* customized field */ - background: #FFC; -} - -.config-form span.checkbox.custom { - padding: 1px; - border: 1px #EDEC90 solid; - background: #FFC; -} - -.config-form .field-error { - border-color: #A11 !important; -} - -.config-form input[type="text"], -.config-form select, -.config-form textarea { - border: 1px #A7A6AA solid; - height: auto; -} - -.config-form input[type="text"]:focus, -.config-form select:focus, -.config-form textarea:focus { - border: 1px #6676FF solid; - background: #F7FBFF; -} - -.config-form .field-comment-mark { - font-family: serif; - color: #007; - cursor: help; - padding: 0 0.2em; - font-weight: bold; - font-style: italic; -} - -.config-form .field-comment-warning { - color: #A00; -} - -/* error list */ -.config-form dd { - margin-left: 0.5em; -} - -.config-form dd:before { - content: "\25B8 "; -} - -.click-hide-message { - cursor: pointer; -} - -.prefsmanage_opts { - margin-: 2em; -} - -#prefs_autoload { - margin-bottom: 0.5em; -} - -.rte_table { - table-layout: fixed; -} - -.rte_table td { - vertical-align: middle; -} - -.rte_table tr td:nth-child(1) { - font-weight: bold; -} - -.rte_table input, .rte_table select, .rte_table textarea { - width: 100%; - margin: 0; - box-sizing: border-box; - -ms-box-sizing: border-box; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; -} - -.rte_table .routine_params_table { - width: 100%; -} - -#placeholder .button { - position: absolute; - cursor: pointer; -} - -#placeholder div.button { - font-size: smaller; - color: #999; - background-color: #eee; - padding: 2px; -} - -.wrapper { - float: ; - margin-bottom: 1.5em; -} -.toggleButton { - position: relative; - cursor: pointer; - font-size: 0.8em; - text-align: center; - line-height: 1.55em; - height: 1.55em; - overflow: hidden; - border-right: 0.1em solid #888; - border-left: 0.1em solid #888; - -webkit-border-radius: 0.3em; - -moz-border-radius: 0.3em; - border-radius: 0.3em; -} -.toggleButton table, -.toggleButton td, -.toggleButton img { - padding: 0; - position: relative; -} -.toggleButton .container { - position: absolute; -} -.toggleButton .toggleOn { - color: white; - padding: 0 1em; - text-shadow: 0 0 0.2em #000; -} -.toggleButton .toggleOff { - padding: 0 1em; -} - -.doubleFieldset fieldset { - width: 48%; - float: ; - padding: 0; -} -.doubleFieldset fieldset.left { - margin-: 1%; -} -.doubleFieldset fieldset.right { - margin-: 1%; -} -.doubleFieldset legend { - margin-: 1.5em; -} -.doubleFieldset div.wrap { - padding: 1.5em; -} - -#table_columns input[type="text"], #table_columns select { - width: 10em; - box-sizing: border-box; - -ms-box-sizing: border-box; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; -} - -#table_columns select { - margin: 0 6px; -} - -#placeholder { - position: relative; - border: 1px solid #aaa; - float: right; - overflow: hidden; -} - -.placeholderDrag { - cursor: move; -} - -#placeholder .button { - position: absolute; -} - -#left_arrow { - left:8px; - top:26px; -} - -#right_arrow { - left:26px; - top:26px; -} - -#up_arrow { - left:17px; - top:8px; -} - -#down_arrow { - left:17px; - top:44px; -} - -#zoom_in { - left:17px; - top:67px; -} - -#zoom_world { - left:17px; - top:85px; -} - -#zoom_out { - left:17px; - top:103px; -} - -.gis_table td { - vertical-align: middle; -} - -.gis_table select { - min-width: 160px; - margin: 6px; -} - -.gis_table .save { - color: #111; - font-weight: bold; - vertical-align: bottom; - height: 100px; -} - -.gis_table .button { - text-align: ; -} - -.gis_table .choice { - display: none; -} - -.CodeMirror { - font-size: 100%; - font-family: monospace; - background: white; - border: 1px solid black; -} - -.CodeMirror-scroll { - overflow: auto; - height: em; - /* This is needed to prevent an IE[67] bug where the scrolled content - is visible outside of the scrolling box. */ - position: relative; -} - -.CodeMirror-gutter { - position: absolute; left: 0; top: 0; - z-index: 10; - background-color: #f7f7f7; - border-right: 1px solid #eee; - min-width: 2em; - height: 100%; -} -.CodeMirror-gutter-text { - color: #aaa; - text-align: right; - padding: .4em .2em .4em .4em; - white-space: pre !important; -} -.CodeMirror-lines { - padding: .4em; -} - -.CodeMirror pre { - -moz-border-radius: 0; - -webkit-border-radius: 0; - -o-border-radius: 0; - border-radius: 0; - border-width: 0; margin: 0; padding: 0; background: transparent; - font-family: inherit; - font-size: inherit; - padding: 0; margin: 0; - white-space: pre; - word-wrap: normal; -} - -.CodeMirror-wrap pre { - word-wrap: break-word; - white-space: pre-wrap; -} -.CodeMirror-wrap .CodeMirror-scroll { - overflow-x: hidden; -} - -.CodeMirror textarea { - font-family: inherit !important; - font-size: inherit !important; -} - -.CodeMirror-cursor { - z-index: 10; - position: absolute; - visibility: hidden; - border-left: 1px solid black !important; -} -.CodeMirror-focused .CodeMirror-cursor { - visibility: visible; -} - -span.CodeMirror-selected { - background: #ccc !important; - color: HighlightText !important; -} -.CodeMirror-focused span.CodeMirror-selected { - background: Highlight !important; -} - -.CodeMirror-matchingbracket {color: #0f0 !important;} -.CodeMirror-nonmatchingbracket {color: #f22 !important;} - -getCssCodeMirror(); ?> - -.colborder { - cursor: col-resize; - height: 100%; - margin-left: -6px; - position: absolute; - width: 5px; -} - -.colborder_active { - border-right: 2px solid #a44; -} - -.pma_table td { - position: static; -} - -.pma_table th.draggable span, .pma_table tbody td span { - display: block; - overflow: hidden; -} - -.cRsz { - position: absolute; -} - -.cCpy { - background: #333; - color: #FFF; - font-weight: bold; - margin: 0.1em; - padding: 0.3em; - position: absolute; - text-shadow: -1px -1px #000; - - -moz-box-shadow: 0 0 0.7em #000; - -webkit-box-shadow: 0 0 0.7em #000; - box-shadow: 0 0 0.7em #000; - -moz-border-radius: 0.3em; - -webkit-border-radius: 0.3em; - border-radius: 0.3em; -} - -.cPointer { - background: url(getImgPath(); ?>col_pointer.png); - height: 20px; - margin-left: -5px; /* must be minus half of its width */ - margin-top: -10px; - position: absolute; - width: 10px; -} - -.normalqTip { - background: #333 !important; - opacity: 0.8 !important; - border:1px solid #000 !important; - -moz-border-radius: 0.3em !important; - -webkit-border-radius: 0.3em !important; - border-radius: 0.3em !important; - text-shadow: -1px -1px #000 !important; - font-size: 0.8em !important; - font-weight: bold !important; -} - -.normalqTip * { - background: none !important; - color: #FFF !important; -} - -.normalqTipContent { - padding: 1px 3px !important; -} - -.cDrop { - left: 0; - position: absolute; - top: 0; -} - -.coldrop { - background: url(getImgPath(); ?>col_drop.png); - cursor: pointer; - height: 16px; - margin-left: 0.3em; - margin-top: 0.3em; - position: absolute; - width: 16px; -} - -.coldrop:hover, .coldrop-hover { - background-color: #999; -} - -.cList { - background: #EEE; - border: solid 1px #999; - position: absolute; - -moz-box-shadow: 0 0.2em 0.5em #333; - -webkit-box-shadow: 0 0.2em 0.5em #333; - box-shadow: 0 0.2em 0.5em #333; -} - -.cList .lDiv div { - padding: 0.2em 0.5em 0.2em 0.2em; -} - -.cList .lDiv div:hover { - background: #DDD; - cursor: pointer; -} - -.cList .lDiv div input { - cursor: pointer; -} - -.showAllColBtn { - border-bottom: solid 1px #999; - border-top: solid 1px #999; - cursor: pointer; - font-size: 0.9em; - font-weight: bold; - padding: 0.35em 1em; - text-align: center; -} - -.showAllColBtn:hover { - background: #DDD; -} - -.navigation { - margin: 0.8em 0; - - border-radius: 5px; - -webkit-border-radius: 5px; - -moz-border-radius: 5px; - - getCssGradient('eeeeee', 'cccccc'); ?> -} - -.navigation td { - margin: 0; - padding: 0; - vertical-align: middle; - white-space: nowrap; -} - -.navigation_separator { - color: #999; - display: inline-block; - font-size: 1.5em; - text-align: center; - height: 1.4em; - width: 1.2em; - text-shadow: 1px 0 #FFF; -} - -.navigation input[type=submit] { - background: none; - border: 0; - filter: none; - margin: 0; - padding: 0.8em 0.5em; - - border-radius: 0; - -webkit-border-radius: 0; - -moz-border-radius: 0; -} - -.navigation input[type=submit]:hover, .navigation input.edit_mode_active { - color: white; - cursor: pointer; - text-shadow: none; - - getCssGradient('333333', '555555'); ?> -} - -.navigation select { - margin: 0 0.8em; -} - -.cEdit { - margin: 0; - padding: 0; - position: absolute; -} - -.cEdit input[type=text] { - background: #FFF; - height: 100%; - margin: 0; - padding: 0; -} - -.cEdit .edit_area { - background: #FFF; - border: 1px solid #999; - min-width: 10em; - padding: 0.3em 0.5em; -} - -.cEdit .edit_area select, .cEdit .edit_area textarea { - width: 97%; -} - -.cEdit .cell_edit_hint { - color: #555; - font-size: 0.8em; - margin: 0.3em 0.2em; -} - -.cEdit .edit_box { - overflow: hidden; - padding: 0; -} - -.cEdit .edit_box_posting { - background: #FFF url(getImgPath(); ?>ajax_clock_small.gif) no-repeat right center; - padding-right: 1.5em; -} - -.cEdit .edit_area_loading { - background: #FFF url(getImgPath(); ?>ajax_clock_small.gif) no-repeat center; - height: 10em; -} - -.cEdit .goto_link { - background: #EEE; - color: #555; - padding: 0.2em 0.3em; -} - -.saving_edited_data { - background: url(getImgPath(); ?>ajax_clock_small.gif) no-repeat left; - padding-left: 20px; -} - -/* css for timepicker */ -.ui-timepicker-div .ui-widget-header{ margin-bottom: 8px; } -.ui-timepicker-div dl{ text-align: left; } -.ui-timepicker-div dl dt{ height: 25px; } -.ui-timepicker-div dl dd{ margin: -25px 0 10px 65px; } -.ui-timepicker-div td { font-size: 90%; } - -/* Designer */ -.input_tab { - background-color: #A6C7E1; - color: #000000; -} - -#canvas { - background-color: #FFFFFF; - color: #000000; -} - -canvas.pmd { - display: inline-block; - overflow: hidden; - text-align: left; -} - -canvas.pmd * { - behavior: url(#default#VML); -} - -.pmd_tab { - background-color: #FFFFFF; - color: #000000; - border-collapse: collapse; - border: 1px solid #AAAAAA; - z-index: 1; - -moz-user-select: none; -} - -.tab_zag { - background-image: url(getImgPath(); ?>pmd/Header.png); - background-repeat: repeat-x; - text-align: center; - cursor: move; - padding: 1px; - font-weight: bold; -} - -.tab_zag_2 { - background-image: url(getImgPath(); ?>pmd/Header_Linked.png); - background-repeat: repeat-x; - text-align: center; - cursor: move; - padding: 1px; - font-weight: bold; -} - -.tab_field { - background: #FFFFFF; - color: #000000; - cursor: default; -} - -.tab_field_2 { - background-color: #CCFFCC; - color: #000000; - background-repeat: repeat-x; - cursor: default; -} - -.tab_field_3 { - background-color: #FFE6E6; /*#DDEEFF*/ - color: #000000; - cursor: default; -} - -#pmd_hint { - white-space: nowrap; - position: absolute; - background-color: #99FF99; - color: #000000; - left: 200px; - top: 50px; - z-index: 3; - border: #00CC66 solid 1px; - display: none; -} - -.scroll_tab { - overflow: auto; - width: 100%; - height: 500px; -} - -.pmd_Tabs { - cursor: default; - color: #0055bb; - white-space: nowrap; - text-decoration: none; - text-indent: 3px; - font-weight: bold; - margin-left: 2px; - text-align: left; - background-color: #FFFFFF; - background-image: url(getImgPath(); ?>pmd/left_panel_butt.png); - border: #CCCCCC solid 1px; -} - -.pmd_Tabs2 { - cursor: default; - color: #0055bb; - background: #FFEE99; - text-indent: 3px; - font-weight: bold; - white-space: nowrap; - text-decoration: none; - border: #9999FF solid 1px; - text-align: left; -} - -.owner { - font-weight: normal; - color: #888888; -} - -.option_tab { - padding-left: 2px; - padding-right: 2px; - width: 5px; -} - -.select_all { - vertical-align: top; - padding-left: 2px; - padding-right: 2px; - cursor: default; - width: 1px; - color: #000000; - background-image: url(getImgPath(); ?>pmd/Header.png); - background-repeat: repeat-x; -} - -.small_tab { - vertical-align: top; - background-color: #0064ea; - color: #FFFFFF; - background-image: url(getImgPath(); ?>pmd/small_tab.png); - cursor: default; - text-align: center; - font-weight: bold; - padding-left: 2px; - padding-right: 2px; - width: 1px; - text-decoration: none; -} - -.small_tab2 { - vertical-align: top; - color: #FFFFFF; - background-color: #FF9966; - cursor: default; - padding-left: 2px; - padding-right: 2px; - text-align: center; - font-weight: bold; - width: 1px; - text-decoration: none; -} - -.small_tab_pref { - background-image: url(getImgPath(); ?>pmd/Header.png); - background-repeat: repeat-x; - text-align: center; - width: 1px; -} - -.small_tab_pref2 { - vertical-align: top; - color: #FFFFFF; - background-color: #FF9966; - cursor: default; - text-align: center; - font-weight: bold; - width: 1px; - text-decoration: none; -} - -.butt { - border: #4477aa solid 1px; - font-weight: bold; - height: 19px; - width: 70px; - background-color: #FFFFFF; - color: #000000; - vertical-align: baseline; -} - -.L_butt2_1 { - padding: 1px; - text-decoration: none; - background-color: #ffffff; - color: #000000; - vertical-align: middle; - cursor: default; -} - -.L_butt2_2 { - padding: 0; - border: #0099CC solid 1px; - background: #FFEE99; - text-decoration: none; - color: #000000; - cursor: default; -} - -/* ---------------------------------------------------------------------------*/ -.bor { - width: 10px; - height: 10px; -} - -.frams1 { - background: url(getImgPath(); ?>pmd/1.png) no-repeat right bottom; -} - -.frams2 { - background: url(getImgPath(); ?>pmd/2.png) no-repeat left bottom; -} - -.frams3 { - background: url(getImgPath(); ?>pmd/3.png) no-repeat left top; -} - -.frams4 { - background: url(getImgPath(); ?>pmd/4.png) no-repeat right top; -} - -.frams5 { - background: url(getImgPath(); ?>pmd/5.png) repeat-x center bottom; -} - -.frams6 { - background: url(getImgPath(); ?>pmd/6.png) repeat-y left; -} - -.frams7 { - background: url(getImgPath(); ?>pmd/7.png) repeat-x top; -} - -.frams8 { - background: url(getImgPath(); ?>pmd/8.png) repeat-y right; -} - -#osn_tab { - background-color: #FFFFFF; - color: #000000; - border: #A9A9A9 solid 1px; -} - -.pmd_header { - background-color: #EAEEF0; - color: #000000; - text-align: center; - font-weight: bold; - margin: 0; - padding: 0; - background-image: url(getImgPath(); ?>pmd/top_panel.png); - background-position: top; - background-repeat: repeat-x; - border-right: #999999 solid 1px; - border-left: #999999 solid 1px; - height: 28px; -} - -.pmd_header a { - display: block; - float: left; - margin: 3px 1px 4px 1px; - height: 20px; - border: 1px dotted #ffffff; -} - -.pmd_header .M_bord { - display: block; - float: left; - margin: 4px; - height: 20px; - width: 2px; -} - -.pmd_header a.first { - margin-right: 1em; -} - -.pmd_header a.last { - margin-left: 1em; -} - -a.M_butt_Selected_down_IE, -a.M_butt_Selected_down { - border: 1px solid #C0C0BB; - background-color: #99FF99; - color: #000000; -} - -a.M_butt_Selected_down_IE:hover, -a.M_butt_Selected_down:hover, -a.M_butt:hover { - border: 1px solid #0099CC; - background-color: #FFEE99; - color: #000000; -} - -#layer_menu { - z-index: 1000; - position: absolute; - left: 0; - background-color: #EAEEF0; - border: #999999 solid 1px; -} - -#layer_action { - position: absolute; - left: 638px; - top: 52px; - z-index: 1000; - background-color: #CCFF99; - padding: 3px; - border: #009933 solid 1px; - white-space: nowrap; - font-weight: bold; -} - -#layer_upd_relation { - position: absolute; - left: 637px; - top: 224px; - z-index: 1000; -} - -#layer_new_relation { - position: absolute; - left: 636px; - top: 85px; - z-index: 1000; - width: 153px; -} - -#pmd_optionse { - position: absolute; - left: 636px; - top: 85px; - z-index: 1000; - width: 153px; -} - -#layer_menu_sizer { - background-image: url(getImgPath(); ?>pmd/resize.png); - cursor: nw-resize; - width: 16px; - height: 16px; -} - -.panel { - position: fixed; - top: 50px; - right: 0; - display: none; - background: #FFF; - border:1px solid #F5F5F5; - width: 350 px; - height: auto; - padding: 30px 170px 30px 30px; - color:#FFF; - z-index:99; -} - -a.trigger{ - position: fixed; - text-decoration: none; - top: 60px; right: 0; - color:#fff; - padding: 10px 40px 10px 15px; - background:#333333 url(getImgPath(); ?>pmd/plus.png) 85% 55% no-repeat; - border:1px solid #444444; - display: block; -} - -a.trigger:hover{ - position: fixed; - text-decoration: none; - top: 60px; right: 0; - color:#080808; - padding: 10px 40px 10px 15px; - background:#fff696 url(getImgPath(); ?>pmd/plus.png) 85% 55% no-repeat; - border:1px solid #999; - display: block; -} - -a.active.trigger { - background:#222222 url(getImgPath(); ?>pmd/minus.png) 85% 55% no-repeat; - z-index:999; -} - -a.active.trigger:hover { - background:#fff696 url(getImgPath(); ?>pmd/minus.png) 85% 55% no-repeat; - z-index:999; -} - -h2.tiger{ - background-repeat: repeat-x; - padding: 1px; - font-weight: bold; - padding: 50 20 50 20px; - margin: 0 0 5px 0; - width: 250px; - float: left; - color : #333; - text-align: center; -} - -h2.tiger a { - background-image: url(getImgPath(); ?>pmd/Header.png); - text-align: center; - text-decoration: none; - color : #333; - display: block; -} - -h2.tiger a:hover { - color: #000; - background-image: url(getImgPath(); ?>pmd/Header_Linked.png); -} - -h2.active { - background-image: url(getImgPath(); ?>pmd/Header.png); - background-repeat: repeat-x; - padding: 1px; - background-position: left bottom; -} - -.toggle_container { - margin: 0 0 5px; - padding: 0; - border-top: 1px solid #d6d6d6; - background: #FFF ; - width: 250px; - overflow: hidden; - font-size: 1.2em; - clear: both; -} - -.toggle_container .block { - background-color: #DBE4E8; - padding:40 15 40 15px; /*--Padding of Container--*/ - border:1px solid #999; - color:#000; -} - -.history_table { - text-align: center; - background-color: #9999CC; -} - -.history_table2 { - text-align: center; - background-color: #DBE4E8; -} - -#filter { - display: none; - position: absolute; - top: 0%; - left: 0%; - width: 100%; - height: 100%; - background-color: #CCA; - z-index:10; - opacity:0.5; - filter: alpha(opacity=50); -} - -#box { - display: none; - position: absolute; - top: 20%; - left: 30%; - width: 500px; - height: 220px; - padding: 48px; - margin:0; - border: 1px solid black; - background-color: white; - z-index:101; - overflow: visible; -} - -#boxtitle { - position:absolute; - float:center; - top:0; - left:0; - width:593px; - height:20px; - padding:0; - padding-top:4px; - left-padding:8px; - margin:0; - border-bottom:4px solid #3CF; - background-color: #D0DCE0; - color:black; - font-weight:bold; - padding-left: 2px; - text-align:left; -} - -#tblfooter { - background-color: #D3DCE3; - float: right; - padding-top:10px; - color: black; - font-weight: normal; -} - -input.btn { - color:#333; - background-color: #D0DCE0; -} - -body .ui-widget { - font-size: 1em; -} - -.ui-dialog fieldset legend a { - color: #235A81; -} - -/* jqPlot */ - -/*rules for the plot target div. These will be cascaded down to all plot elements according to css rules*/ -.jqplot-target { - position: relative; - color: #222222; - font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; - font-size: 1em; -/* height: 300px; - width: 590px;*/ -} - -/*rules applied to all axes*/ -.jqplot-axis { - font-size: 0.75em; -} - -.jqplot-xaxis { - margin-top: 10px; -} - -.jqplot-x2axis { - margin-bottom: 10px; -} - -.jqplot-yaxis { - margin-right: 10px; -} - -.jqplot-y2axis, .jqplot-y3axis, .jqplot-y4axis, .jqplot-y5axis, .jqplot-y6axis, .jqplot-y7axis, .jqplot-y8axis, .jqplot-y9axis, .jqplot-yMidAxis { - margin-left: 10px; - margin-right: 10px; -} - -/*rules applied to all axis tick divs*/ -.jqplot-axis-tick, .jqplot-xaxis-tick, .jqplot-yaxis-tick, .jqplot-x2axis-tick, .jqplot-y2axis-tick, .jqplot-y3axis-tick, .jqplot-y4axis-tick, .jqplot-y5axis-tick, .jqplot-y6axis-tick, .jqplot-y7axis-tick, .jqplot-y8axis-tick, .jqplot-y9axis-tick, .jqplot-yMidAxis-tick { - position: absolute; - white-space: pre; -} - - -.jqplot-xaxis-tick { - top: 0px; - /* initial position untill tick is drawn in proper place */ - left: 15px; -/* padding-top: 10px;*/ - vertical-align: top; -} - -.jqplot-x2axis-tick { - bottom: 0px; - /* initial position untill tick is drawn in proper place */ - left: 15px; -/* padding-bottom: 10px;*/ - vertical-align: bottom; -} - -.jqplot-yaxis-tick { - right: 0px; - /* initial position untill tick is drawn in proper place */ - top: 15px; -/* padding-right: 10px;*/ - text-align: right; -} - -.jqplot-yaxis-tick.jqplot-breakTick { - right: -20px; - margin-right: 0px; - padding:1px 5px 1px 5px; -/* background-color: white;*/ - z-index: 2; - font-size: 1.5em; -} - -.jqplot-y2axis-tick, .jqplot-y3axis-tick, .jqplot-y4axis-tick, .jqplot-y5axis-tick, .jqplot-y6axis-tick, .jqplot-y7axis-tick, .jqplot-y8axis-tick, .jqplot-y9axis-tick { - left: 0px; - /* initial position untill tick is drawn in proper place */ - top: 15px; -/* padding-left: 10px;*/ -/* padding-right: 15px;*/ - text-align: left; -} - -.jqplot-yMidAxis-tick { - text-align: center; - white-space: nowrap; -} - -.jqplot-xaxis-label { - margin-top: 10px; - font-size: 11pt; - position: absolute; -} - -.jqplot-x2axis-label { - margin-bottom: 10px; - font-size: 11pt; - position: absolute; -} - -.jqplot-yaxis-label { - margin-right: 10px; -/* text-align: center;*/ - font-size: 11pt; - position: absolute; -} - -.jqplot-yMidAxis-label { - font-size: 11pt; - position: absolute; -} - -.jqplot-y2axis-label, .jqplot-y3axis-label, .jqplot-y4axis-label, .jqplot-y5axis-label, .jqplot-y6axis-label, .jqplot-y7axis-label, .jqplot-y8axis-label, .jqplot-y9axis-label { -/* text-align: center;*/ - font-size: 11pt; - margin-left: 10px; - position: absolute; -} - -.jqplot-meterGauge-tick { - font-size: 0.75em; - color: #999999; -} - -.jqplot-meterGauge-label { - font-size: 1em; - color: #999999; -} - -table.jqplot-table-legend { - margin-top: 12px; - margin-bottom: 12px; - margin-left: 12px; - margin-right: 12px; -} - -table.jqplot-table-legend, table.jqplot-cursor-legend { - background-color: rgba(255,255,255,0.6); - border: 1px solid #cccccc; - position: absolute; - font-size: 0.75em; -} - -td.jqplot-table-legend { - vertical-align:middle; -} - -/* -These rules could be used instead of assigning -element styles and relying on js object properties. -*/ - -/* -td.jqplot-table-legend-swatch { - padding-top: 0.5em; - text-align: center; -} - -tr.jqplot-table-legend:first td.jqplot-table-legend-swatch { - padding-top: 0px; -} -*/ - -td.jqplot-seriesToggle:hover, td.jqplot-seriesToggle:active { - cursor: pointer; -} - -.jqplot-table-legend .jqplot-series-hidden { - text-decoration: line-through; -} - -div.jqplot-table-legend-swatch-outline { - border: 1px solid #cccccc; - padding:1px; -} - -div.jqplot-table-legend-swatch { - width:0px; - height:0px; - border-top-width: 5px; - border-bottom-width: 5px; - border-left-width: 6px; - border-right-width: 6px; - border-top-style: solid; - border-bottom-style: solid; - border-left-style: solid; - border-right-style: solid; -} - -.jqplot-title { - top: 0px; - left: 0px; - padding-bottom: 0.5em; - font-size: 1.2em; -} - -table.jqplot-cursor-tooltip { - border: 1px solid #cccccc; - font-size: 0.75em; -} - - -.jqplot-cursor-tooltip { - border: 1px solid #cccccc; - font-size: 0.75em; - white-space: nowrap; - background: rgba(208,208,208,0.5); - padding: 1px; -} - -.jqplot-highlighter-tooltip, .jqplot-canvasOverlay-tooltip { - border: 1px solid #cccccc; - font-size: 0.75em; - white-space: nowrap; - background: rgba(208,208,208,0.5); - padding: 1px; -} - -.jqplot-point-label { - font-size: 0.75em; - z-index: 2; -} - -td.jqplot-cursor-legend-swatch { - vertical-align: middle; - text-align: center; -} - -div.jqplot-cursor-legend-swatch { - width: 1.2em; - height: 0.7em; -} - -.jqplot-error { -/* Styles added to the plot target container when there is an error go here.*/ - text-align: center; -} - -.jqplot-error-message { -/* Styling of the custom error message div goes here.*/ - position: relative; - top: 46%; - display: inline-block; -} - -div.jqplot-bubble-label { - font-size: 0.8em; -/* background: rgba(90%, 90%, 90%, 0.15);*/ - padding-left: 2px; - padding-right: 2px; - color: rgb(20%, 20%, 20%); -} - -div.jqplot-bubble-label.jqplot-bubble-label-highlight { - background: rgba(90%, 90%, 90%, 0.7); -} - -div.jqplot-noData-container { - text-align: center; - background-color: rgba(96%, 96%, 96%, 0.3); -} diff --git a/phpMyAdmin/themes/pmahomme/img/b_column_add.png b/phpMyAdmin/themes/pmahomme/img/b_column_add.png new file mode 100644 index 0000000000000000000000000000000000000000..25dc54637af42c25df91da30b00a9cdf08da81ef GIT binary patch literal 534 zcmV+x0_pvUP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipuD z6Cwb3$1A=LzdN=AuQZW%sK~{lP7Qr$Vz_|KSPFeJ*uYR6D*-IV1);?l zhp`TCqCdPY&S?+2m>pRLVCC615AKcwT&c&tvGVlV(0|MBpZr0X* Y1BxyYzJ?floB#j-07*qoM6N<$f_n4kUjP6A literal 0 HcmV?d00001 diff --git a/phpMyAdmin/themes/pmahomme/img/b_find_replace.png b/phpMyAdmin/themes/pmahomme/img/b_find_replace.png new file mode 100644 index 0000000000000000000000000000000000000000..6eaba80572411f5acb1a52b7263ccc0fdc40a546 GIT binary patch literal 883 zcmV-(1C0EMP)z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ;=}AOERCwBA{Qv(y10?_;fLLIRL-+qO{rmTC>Yu;= zeg6LaEA{8^KZf6b{yzKj=kJ!^zyD@OT8jL`W&l6{F@juh5TyC(hOAD2Q@0i1D-9>n>=z^(5B$|3MAz3CIQj1Q6H&pfi1hI2jo}{{(6J&+zBp zf1siN8NLG9@4o+K5O@^FprG?eSwvEbft`;jf4wxza+m=C0R#>MpkJk!nV7(u{{l4w z5ts(yGkY#E=!tJ*;85acxVW8z;rFjU3?JYAb%hxK5I|rT{QCU|tO;!MKM4K%_dkY9 zhpsRfX&W*;{jA5prSg$Mso*8UgXcf4|NP0I1Tz32fFK6^`t$4uPy-7SBixXy$F4CL zY3eYrvH)H7V;;l0bI}ZseoLNU;bbsL|Ns9J%m9D@g1KPJgO}eJc-fg4Sb>IIIdqvp zUrmF7jg6h*)~$OC|Nb&E9J!YG@7aC*;>ZX8zaa-AKmdUa`1$Kk_Wc)M4qkoufq~`! zcZR>f7~taKW4M0(4#Sr(pBU~wxXF-cc7}=h%g>D)Dy-Cz4FCurumLGf(*J;lINf>r zamJa2w!cLselgs+^M>K;m+uUB?_K{Ls(FDyMp>CbQr%SK=g;p)mgH!{4FL!sCK#i@ zSLvVrJ)>28|L?weeYok3pHOyt+E??+(z z00M{!**Q%Mf2OTJ#31?Y!9Rv?PpU7xet*`dZbHM`pFh7vKDc&#-HkIl7{p|hfr0*0 z1f~ZdfWS$ak&*E{kj)Il;-%p{-0UnYrb3dRUln%$c?(lGKV6ya&!3;mnOWI`zI}P$ zk+bAoB}g0~fEY>1jnm>png9O%Bc8kT{WF*tKmajPnw0O12+Hw002ov JPDHLkV1hI&r}+Q? literal 0 HcmV?d00001 diff --git a/phpMyAdmin/themes/pmahomme/img/b_group.png b/phpMyAdmin/themes/pmahomme/img/b_group.png new file mode 100644 index 0000000000000000000000000000000000000000..4530760bad39d6c857ed2f15d08c2e96e92e6e6c GIT binary patch literal 796 zcmV+%1LOROP)U7S{={Y-RUl(F{73;lv z_~3c?7$QP7$yc;|AYwT-1rYD>)?1z&s>J2>i8!N~@u7kh}kW3OrMu!E4VZs1_ zzGhfIcIF3V|1dqQt|6b-NAt4_bou1fgfi0|} z)zzP)Oi7(F@k zfQgE;z`f+gK-YW3r`q6Na%1q-5JIYqU@(Y)-;WiK4>@^7Ca`G#8whJ`nb}eRug?cb zlCb9S!n?7%A#@UzeA2JwYZzN}45F9Vxfzbm4 zz5Q6$@aVoD4!cN1)P-!0ERRe^g1vs7g4~d*FoiYh+Ati4*&wkqTqBk;+LW$3Z&;` z;ms!wVF3KjiBx%GkxxHc3j+O9W&nhOUW7FjiU@5t&^*v~y-L)Z!jXKSYzH_+RUPF| aDD(%1fh}_Q#_Q4m0000Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipuD z6BRYSeYF1o00PHJL_t(I%cYY|Y*b|whM&1}r_)Y5Hmy_IhBj*GK$}RX4VA%a0$92b z0xWRjQjr*c2;nEOE2F3hYl$Sf(1kHk6A8o+6JpeAg#wLGv0BCo)R1XQ+nLS}-09r! zoX>?}iaU)bImuZ)@0*K`UdM8r0n5kC#j3?W&P^y5O6B$cS;7|2rhsXZEthFBUG~! zlN-aS?nPvg(o%{Ee>ZbCH^R+@f7svE*GSn2?)=#1Dl7UzZ9^OgqTVdH%Veg{(zxyb zPd)N10AGyGv1e0r1+b7W{p~DynUNis zP%|MHx>iRh`+{qY9EYxNYqaI6xBGBUdzj*%r-`+1#du5Ho&Sv)(@DPNc~1TGDdFI4ie8q2S0dTD zosnxBR)Tc&^BeZn!Fn>^3=oMvOfEA^YwscI*FM9$C*NdAr`gceM_Xf@ZzoPM`pXaG z=liMr#i&xee2{Q;BezRUq~o7($=kx$;|q-aevzKe1mXyZ)L^+Y&Ldg&9JDI(BvK2jK9)2dr7ujm4*u#GGj$+IO62T?aE6 zk2TFT+?XvQqGSp=Cer5^PmeG(_z}m>K1X#hOn}e|VBS3RGZx^prw85kItlDyqr82-2SpV<%OaTa()7Bet#3xhBt!>l?(ur>YJ-lQyD5({bre1$KR7{S2-7GA%mx@pUXO@geCy7RYV5> delta 159 zcmV;Q0AT;%0lNW^B!2{FK}|sb0I$e51&Zka0044HL_t(2&&|*~4nR;4h2h^TQR!^x zS^>2+vH}{BSb{z1J?<0~2#JeIVyaVoIg=S{=6P&B2ksu~LX@BpG`dWq3z(FLgAYKf z3=IPw9RMM{X~jrD0zk!pu>rEJVY~z3DPKUJH}QIdAo&5T9~iv)6)efMAe+aNZ`S|- N002ovPDHLkV1gazK05#a diff --git a/phpMyAdmin/themes/pmahomme/img/b_move.png b/phpMyAdmin/themes/pmahomme/img/b_move.png new file mode 100644 index 0000000000000000000000000000000000000000..8fd0f307ae3ab1cd78a522d3dab918b3499d6b4f GIT binary patch literal 520 zcmV+j0{8uiP)Px$!bwCyR5;7ElFv(2aTLWrZ+whO5QCv3whUV2B7*Q`_#m;`^vi<47X1T})S@B< zCwZW5+K4|^EuuxMf=p}^(&B|WinMSsNKiT|Ic;*Vn(2Lixftg$CKChUg}b@jd+s^+ zT=>thp1xf-QfUgQP|~2ZUKqT6yrm+9pE+Uv&Iiv^`AQksW1of)N+PvHD#_#40fbQ1 z#fB^67tG|H_f}beN3DH(3cvCaAr%0Z$Ict^NBsK+Fa3-uEnGca$NgtZeB&XFb#VeA zSV^Y=Hh@uJ*iR&L#r{atHr#4!2s0NH7)*6fTVK*Ed|h3|Pb4kiF3<&}T+gWu0RSfE zzcZ1{@NO}~_HRKT3KBl_%vePUej@n>I0tM2_d?3AW;ab~eBQ{Kn}ai^oMzW^I$h6M z5041&dM<-)fd)=A)nL#SKT_myO@xalk8sV2bKQvpaH!g*)W(wSF`$3GZx^prw85kItlDyqr82-2SpV<%OaTa()7Bet#3xhBt!>lXmHBKz!kZSPCIF+H^)cWipk3@t}fmHwg1mC5} zvKQKI?%zpozJ2-K`bjBQi<&3hUen;q=B)pjH!;%j>b<>;9JfRbC#tQ<2HMWx>FVdQ I&MBb@01VtsSpWb4 delta 161 zcmV;S0ABy?0lfi`B!2{FK}|sb0I$e51&Zka004AJL_t(2&&`mz34l-#M4uPffaREc zE6~^)wE|5RcYsHMcW~H3wrLg49Rx{tz#90$t6zZ$%iJQ9U9X?y P00000NkvXXu0mjfk;O%8 diff --git a/phpMyAdmin/themes/pmahomme/img/b_table_add.png b/phpMyAdmin/themes/pmahomme/img/b_table_add.png new file mode 100644 index 0000000000000000000000000000000000000000..98753b2650d3310e665c8aac1fc592f81deb3755 GIT binary patch literal 676 zcmV;V0$crwP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipuD z6Ba9PU)o;)00JaQL_t(I%cYY|NR&|&hM(`pw9<`?BbBrfA){stYZ!l4H9{*RgrH~> z(WZ3OqFF^P1Q#t+sEq`H6c~xEVkjcD!3Y}7RZ_dL`9aN59R2ROx5YQijIE3=Twcz( z-1ofqz2{iQ82)Fu0M9?J-#3O^Vswkv8quJ%MnogpphQ<~L6kwX{ycoWE#d-bV}=GI z4S|2D{NTlMsH{M=4ggI3c!tsnB??a~Jn_;o8ZY`>MWGRCr1% z9*AfFCT6nxBIrNc$Zj=(DiHu&?G5sBHp7*k=5lT_nPDJWiSrx9y$U?hXk&04nEaH* zaco{CvsgCRrAt%uSulng7ut^3m($0tzA_rQi&IDqT;7z+nD9}2KmSfR$Mr@wv3S9IYit-%mLUBv@qICZ?9mDO!p zn-B8y*JgPZRtvvbO3#r>&k*k$XXNb->YQ4DV(Aym?8Axg9lN3rdrI(>AWGwjMv0=3 z=^?o=M|Y@~>BTV)SS~YPKLCtc`yJ=#;L#D_HqZbRfU)G`bo>u+b1n(W>kNhf0000< KMNUMnLSTZ3MI_|_ literal 0 HcmV?d00001 diff --git a/phpMyAdmin/themes/pmahomme/img/b_undo.png b/phpMyAdmin/themes/pmahomme/img/b_undo.png new file mode 100644 index 0000000000000000000000000000000000000000..498187821cfd60ca010afe1b08cf6b07f38f8de6 GIT binary patch literal 1306 zcmV+#1?BpQP)R-7j2z+(P=LJMG4+z8597cBYUOn~u=sd&am1J`vUp9({?Ti@9UEinq2|DNT zUmciAl75N}jhwxKf4)cNAknUf_h(Q(k9Ypey1((!5UO6J-;e3Jf?ST&A1J*Y zX^J^wo)GM@M;rx%hLM>LttS(4)ny`N+TV`q`v%ysv0>H(@g;`nsp zR#MyXBtt5w?ZvLgf}_FyAShkU<`FFU3k#P8ZdDV@KVe=?D1GJ@Ql%_ur_+Wl_oa;{fTyv z?B%ZONyf12X`(e;eLatN&{j_AaBgf00uHv))y?SXn8WLz5^rL18C~gc#9`A2=9kd= zE3#z_I4|&}<7j>kAC3=1TYseJEZkt9eKWXveJAl0Qfo1s#hXGte>L%yG&K-+_jxHv z$c^Tefvo=_566Lf{MiuKT*S&@VVpV`^%?MRd5C9z5Y#6VkP!V9BRTR5yh>#UZe?yI zwh^~rA`|y8Wk2m3czzlky_9{x`BT~ZGb+}x@N%xLV^ufR7m!@|1-ElP|KG7C8_f0o zQry|s>AOp*`k1#`c;gf+7IE}xezTYr$dBRLdqaKZp}u*q&n7y-?$vnh%LME!#3rJb z$u}18Dz0iK-@!AN&{)qcC)ktWyj^UY`ngk4$=y{%BUy8b_*j9T^dCX#{}oVGRoG~A zfk=_e>NAyryz>^PhtM*d#U0@d*wBRu%#BEWo74!BmwDkPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipuD z6BiV~BE};C00MqVL_t(I%cYY`NK|1IfWLY87-oD`HjWH|q-9oWMp@=6Y}d|R&?2Hu z(q0Oph@wSXTT~EX5v?kP0vAbTVg^x~Q5hK|J}_s}(eB)P|Nop8mRhT#1BV0Wz<1v8 zpArD*e3Cw`$}y{w6cMa|5y4u)iejv+Qj0Z;6?t*t@TT2i08u^By1QWAzhpjh=VL8E z7{H3G1GxX`21X3V8hkPM)?cyKEXUgSp2zoX-YS3saH!@e)>@o}Z+LT4NOlo59^p_9 zxoeZ;7q2H2&S5cY@Qq~!UO5Zj7<;7Cw)EVZl|3)+X6o@|BADL7Ivk9Ite_f*^oz1yQ9aFiRv} zNu+!S^Crr}u3PkUb@J88!zrpFvbBZTvA1Nt`*{8zEhrF3+(S)CoSNzq2!y!$_zI>}+262>cFJNhX;*8_$rRk9#iM&4u%HOs!~d?QTU7 zq+K~GABVXGK|~6%2yUjnKNB#v>11bR2=ejo$?dZgyc@<;nqjleX|}o6fE~Ekfx~SP zcq~qjRp7O{yc+_a4Y&bn2OiWR@H@PIrvP*MFc&~^mk)QNxZ96={DcPs0WTKt;UI_t z0)+e^0Kymuf(Q;mAWDF6G$4otBC()=3`WV2ARdav!+=bLV~Gfvh=MqvVjuyMB%nYl z4w4|90I4*U%24S{Qa~p&bV|UaX(mO($z~XqX0kM!W!M~(&9NYt&w@Oc0~{#ixdK-x zaz(xXc)lno@t_3CB~XScrE;ZQ0o4kqHmg-@&FZy!v(5Tuvj%j0`S3DqXhkWPX$H+p z8s#2SueiU~uyR3-#IO|6+dD>0TKPh5=lz~3vg4U*u;s?ri)}k@e^R~Fw%87JUcIXw zSoM7)`pI?ifOPTm_mM91Im53`Y5eE4t{J255vtpN?@akfpXH5vJwnG!(Td(Gg&!;7K>T_FX8%E>4 gH@~ diff --git a/phpMyAdmin/themes/pmahomme/img/database_list_li_hover.png b/phpMyAdmin/themes/pmahomme/img/database_list_li_hover.png deleted file mode 100644 index 22d10f5d496a9414bb63046022e9d5a9934d718c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 108 zcmeAS@N?(olHy`uVBq!ia0vp^%s{Nl!2%?8ugsPQQpTPxjv*44lmDDQ00Ns9&us*P z)`!YwuY|e2O1A#uTDZ?~g**=s^avQwlxSmPW%#bdEA#vJ9FVyTp00i_>zopr0A{`+ A#sB~S diff --git a/phpMyAdmin/themes/pmahomme/img/docs_menu_bg.png b/phpMyAdmin/themes/pmahomme/img/docs_menu_bg.png deleted file mode 100644 index 89e18332a1e62f08bc1bd50fc5c76e140cebc45b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 76 zcmeAS@N?(olHy`uVBq!ia0vp^Od!m`1|*BN@u~nRVNVyw5RU7~30*7ypJ!n9G5q?U ZQLcb_=lt)_mjk64JYD@<);T3K0RT;j6ZQZA diff --git a/phpMyAdmin/themes/pmahomme/img/input_bg.gif b/phpMyAdmin/themes/pmahomme/img/input_bg.gif deleted file mode 100644 index 7cb23d8bcfe46cb27e6a30af822ebf875e2e1c6f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 170 zcmV;b09F4-Nk%w1VFCbT0P_w2{r&y)^z`}p`TqX?`}_O&`1tkp_44xa{QUg)_xJYp z_Ve@e`uh6+|Nrsv@c;k-A^8LV00000EC2ui00IDH000D6u*o?F04Ni}dMQbw7)G$1 z$Kj~za+o8?2-`K?O?6!w*9n48NTeu^ilR`kQ$t)FtJL9i3Is@`kq8uA(ioY{rBcC} YaXMb_CnS;(^b diff --git a/phpMyAdmin/themes/pmahomme/img/item_ltr.png b/phpMyAdmin/themes/pmahomme/img/item_ltr.png deleted file mode 100644 index 2a4cb8b3efc7a84d2d689294d1375d98e48de65c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 112 zcmeAS@N?(olHy`uVBq!ia0vp^tU%1k!2%=$mgtEBDVB6cUq=Rp^(V|(yIunM>Ygr+ zAsp9}QxbmspWg@u6B`+iCAM@NNHMVVSmcov=-ZIVz`%Bi|9eX7lYXEU22WQ%mvv4F FO#ss#Ae;aI diff --git a/phpMyAdmin/themes/pmahomme/img/item_rtl.png b/phpMyAdmin/themes/pmahomme/img/item_rtl.png deleted file mode 100644 index a18e30b07b692c4f34c5f4e9c04bcbecedce2a02..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 112 zcmeAS@N?(olHy`uVBq!ia0vp^tU%1k!2%=$mgtEBDVB6cUq=Rp^(V|(yIunM>Ygr+ zAsp93yA1gl3~bp9zYq+0*}aI1_o|n5N2eUHAey{$X?><>&kwIO^QKHi*aRLEKtbR)5S5w z;&gJt0>y-sl%%Az#MIQ}^yd$rJbL!*;nT`VDJYfI; delta 136 zcmZ3<^oG%(Gr-TCmrII^fq{Y7)59eQNY{bb9Lzv6!dvSqkYY)9^mSxlSbxHtwQHho zuD_M1i(`nz>Ex6JiU}-^ZUSt90!*z3PaH8QXqefUsIWF&BI5ObzBON!tv@v0lMi_P jzwcL_$xGgljm!-Fi&-qKG$SSeO=a+O^>bP0l+XkK!;mVj diff --git a/phpMyAdmin/themes/pmahomme/img/lightbulb.png b/phpMyAdmin/themes/pmahomme/img/lightbulb.png new file mode 100644 index 0000000000000000000000000000000000000000..d22fde8ba46eabd4335e4fa88077e80f96b92d62 GIT binary patch literal 782 zcmV+p1M&QcP)0XYhLR!1P*SpVQi>)dUV<_*6qInHGcnEb zQfX6|c{lO4l#RKaZC-XZ&u-_k%Q@eEE?Qa!_Tt0u@H@}<^E~``A^=3}gr(l4vU*i7 zyV6Lx=4yE7RGGkx6gV71cjvY=iqb#p!ylZn>j-Cf+b>x95wMRT==lzjH$f681f9ze zR{P)>$i_z3RfAovII&B>n%*Ds>XegyS_9EX5sW0f1d*FX&^tjGBX?Rzej4t{=ddW_ z9h>UH!(o9}TURNVdq{y5qM#$E1yaxnNWKtKkRh^p1YA9U=z#4*HY{(h_k{(nnF>pQ znJ2Y6(rFb^z)nJ2pnqIQ&_2v{yl+xxUhm5uO{Q#!J8DY)klFd_YP)!y2hX0`01t+}>V>!L2Ii?(iJ%bC$d(ON6}*wnOwG9V2N zOG`{7!B5mwL_|_S2m}#C`CdG|@7W+M+U(-lIXipb-}9Vv-Vy*Mg_?2)&x|dud>nH6 z+Pg4Y7{H$F@$4DL`b~nbIs5knvB+k zHj8ub763Kx9CrFf76K8`6xv9LChyt?+yu)3H}{cgBtWFDjV( zT46G1p#RVaN{MFkER1%KNN}rd=ywA89=YD?5^*~T(5|_U4sv3(jyQy?qF#!I-YIcK zeuGD!Ck%N2HSJIh+U=tYeo@e&trgAm(x7tzP$_D_zeF>F>u*g-I^VNp4(M<9KQ~%~ z3}FWb=nBN{ra3RFTFeCC z!$l`CCu*vADm$NUP}Jde?Il#nFW_p845!NWW$Et^{&SQIRV}^fRyMzZQmIB=eG~3I zc!HA^Wx-;#MFG+)=LYmWJqQGXuvo_MLh%Zf$0hUI2Iy7tvy~@~#>&eNWlKvX*<(i} i@%N3@m$wc0AN>MB3Mf9{XhoL*0000;rs4T>t<7f9~4-Ggt1NzH;x> z<$EVC-8~LO7w;asaOdcSJ4epnIdty!fit)Eow~XA)Xm)|ZtOa7W5==U+mBt}21G}% zS6QFw2O6c}>Eal|aXmSqfyvEHqq&oD?!iMID$O75Coo<+<}pX_(prb)h8z|qhJ_qV V2_-j`mI3uJc)I$ztaD0e0s!GlQ1bu) diff --git a/phpMyAdmin/themes/pmahomme/img/pmd/exitFullscreen.png b/phpMyAdmin/themes/pmahomme/img/pmd/exitFullscreen.png new file mode 100644 index 0000000000000000000000000000000000000000..1683d55a096e0753aa4ae80c688439c578cbc0ab GIT binary patch literal 444 zcmV;t0Ym${PJKJS=Q+>w>3R8dT&{of%+Af=C$R;}asf9FIh0Bz9#xeqwOtbF zM-=jTF))+OA%67)|KTN{plK?Ds1MUlloP1B&Wvo7iI z!fJtL%;QkmTL>%~1`MNEHIWia-QzT!{nW4P8jlcYclgnZyGnh=pmt*%0Z9$BwkqWa zSi3b+gOsZ6ceFyc<(5eex&X6H-yE&5V=Rc~flV~_m7$~tDP_V)tM2L0_kc^=35+iu zp>tw~x5-CRgOoDG?wZ`il6P)NklY>q_X~48hSe60HG;<4eT_aQ&x{isJD0U(-T*O`wi@zdz^^C>cOOlyLCM}9q zem{kEQ`-|n%XkRmiwC?bRy@0PhK|WFYPy45nE$pRX+_%-s=HRx2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4#g<1Xt!J<>zE3D|ja7=P86_q~@mfEzw-fz`)4s>Eak-(R*~Vqu1d8fwujX zD((Whu7NJDEZ6n!xa@805Z{nH%jBER(qmFx+TZUTNYmaS6c})Dsoob3{ro!`B^MJE zS<_7o{@0wbKXc;ZN5#-XA+P4K9{BBhYi-2xT&a|mXL6WU?s8ebM!;*TdbVG zT*0=ju{vR?Mwd;F+t(lmq4MWFhUQ9}IQLY{6X)6VCD4U0nD|W*VLHSY`uP9 z+Nym~+0Avgelu9?xA^_3wqCwMXyR7+yDr?jm5SI|4xfHg8*|0Kdj7ecwhzQ^NUjgv e*ZjYJS$@a0sA-p64u1uPA%mx@pUXO@geCyHx~`M} literal 0 HcmV?d00001 diff --git a/phpMyAdmin/themes/pmahomme/img/sprites.png b/phpMyAdmin/themes/pmahomme/img/sprites.png index c8c114513c2246bd6ba0b0f67ac2540f2faee56c..fa94de8096f005e28314b3482a9a3cb9e2b771a2 100644 GIT binary patch literal 41626 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 YWDFCO4byp1zZqn*r>mdKI;Vst0RBKGQ2+n{ diff --git a/phpMyAdmin/themes/pmahomme/img/tab_hover_bg.png b/phpMyAdmin/themes/pmahomme/img/tab_hover_bg.png deleted file mode 100644 index 09f1e294efab472d5bbf963eafcbbbc18fd6cb46..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 502 zcmVmYkyFFe&(gafN53V?aP^+lS`I?h7;#a==@gq0D4R8b805`zIV|nAf z5#I5u08qKaZveoH&v=D|ZPalpTOi*Z z0WEqcOV8XwsP=8#m89_?bOV&7q9DkxZf<#{XLj}@^a7wn8bUbj2kRrr`Wnc15IO<8 zeJCKZw5_B;sQL^ktq=nhwF{v1ZL59Og)j1v^g^zCcJxU$aBNfP0oY|P;l&5Zev@|p zS@#Qa1}LcM|HcVC6GHrM5nG6uRQ|Jy-)UC@muz+eQih%`jv*44lWjKlG4e%7)F~C$ zO*pvl27{9CZ%?-8;*xXjpO|BR \ No newline at end of file + diff --git a/phpMyAdmin/themes/pmahomme/jquery/images/ui-bg_glass_75_dadada_1x400.png b/phpMyAdmin/themes/pmahomme/jquery/images/ui-bg_glass_75_dadada_1x400.png index 5a46b47cb16631068aee9e0bd61269fc4e95e5cd..1d43b47e608e15b5fecdb75918178142c80fc53a 100644 GIT binary patch delta 138 zcmV;50CoRwp8=2@e*qX@I!yoo0A@)NjoqzQA!ax=f%ynHTf7r)LI2_RPwF#-bIX2q?AMm;R{nO;NYE~ si '#808000', - 'comment_mysql' => '', - 'comment_ansi' => '', - 'comment_c' => '', - 'digit' => '', - 'digit_hex' => 'teal', - 'digit_integer' => 'teal', - 'digit_float' => 'aqua', - 'punct' => 'fuchsia', - 'alpha' => '', - 'alpha_columnType' => '#FF9900', - 'alpha_columnAttrib' => '#0000FF', - 'alpha_reservedWord' => '#990099', - 'alpha_functionName' => '#FF0000', - 'alpha_identifier' => 'black', - 'alpha_charset' => '#6495ed', - 'alpha_variable' => '#800000', - 'quote' => '#008000', - 'quote_double' => '', - 'quote_single' => '', - 'quote_backtick' => '' -); - /** * Chart colors */ @@ -119,10 +91,10 @@ $GLOBALS['cfg']['chartColor'] = array( 'gradientIntensity' => 50, // The style of the chart title. - 'titleColor' => '#000000', + 'titleColor' => '#000', 'titleBgColor' => '#E5E5E5', // Chart border (0 for no border) - 'border' => '#CCCCCC', + 'border' => '#ccc', // Chart background color. 'bgColor' => '#FBFBFB', // when graph area gradient is used, this is the color of the graph diff --git a/phpMyAdmin/themes/pmahomme/sprites.lib.php b/phpMyAdmin/themes/pmahomme/sprites.lib.php index a5d3355..c3cd7d6 100644 --- a/phpMyAdmin/themes/pmahomme/sprites.lib.php +++ b/phpMyAdmin/themes/pmahomme/sprites.lib.php @@ -1,8 +1,19 @@ array( 'position' => '1', @@ -34,12 +45,12 @@ function PMA_sprites() { 'width' => '16', 'height' => '16' ), - 'b_comment' => array( + 'b_column_add' => array( 'position' => '7', 'width' => '16', 'height' => '16' ), - 'bd_browse' => array( + 'b_comment' => array( 'position' => '8', 'width' => '16', 'height' => '16' @@ -49,648 +60,688 @@ function PMA_sprites() { 'width' => '16', 'height' => '16' ), - 'bd_deltbl' => array( + 'b_deltbl' => array( 'position' => '10', 'width' => '16', 'height' => '16' ), - 'bd_drop' => array( + 'b_docs' => array( 'position' => '11', 'width' => '16', 'height' => '16' ), - 'bd_edit' => array( + 'b_docsql' => array( 'position' => '12', 'width' => '16', 'height' => '16' ), - 'b_deltbl' => array( + 'b_drop' => array( 'position' => '13', 'width' => '16', 'height' => '16' ), - 'bd_empty' => array( + 'b_edit' => array( 'position' => '14', 'width' => '16', 'height' => '16' ), - 'bd_export' => array( + 'b_empty' => array( 'position' => '15', 'width' => '16', 'height' => '16' ), - 'bd_firstpage' => array( + 'b_engine' => array( 'position' => '16', 'width' => '16', 'height' => '16' ), - 'bd_ftext' => array( + 'b_event_add' => array( 'position' => '17', 'width' => '16', 'height' => '16' ), - 'bd_index' => array( + 'b_events' => array( 'position' => '18', 'width' => '16', 'height' => '16' ), - 'bd_insrow' => array( + 'b_export' => array( 'position' => '19', 'width' => '16', 'height' => '16' ), - 'bd_lastpage' => array( + 'b_find_replace' => array( 'position' => '20', 'width' => '16', 'height' => '16' ), - 'bd_nextpage' => array( + 'b_firstpage' => array( 'position' => '21', 'width' => '16', 'height' => '16' ), - 'b_docs' => array( + 'b_ftext' => array( 'position' => '22', 'width' => '16', 'height' => '16' ), - 'b_docsql' => array( + 'b_group' => array( 'position' => '23', 'width' => '16', 'height' => '16' ), - 'bd_prevpage' => array( + 'b_help' => array( 'position' => '24', 'width' => '16', 'height' => '16' ), - 'bd_primary' => array( + 'b_home' => array( 'position' => '25', 'width' => '16', 'height' => '16' ), - 'b_drop' => array( + 'b_import' => array( 'position' => '26', 'width' => '16', 'height' => '16' ), - 'bd_sbrowse' => array( + 'b_index' => array( 'position' => '27', 'width' => '16', 'height' => '16' ), - 'bd_select' => array( + 'b_index_add' => array( 'position' => '28', 'width' => '16', 'height' => '16' ), - 'bd_spatial' => array( + 'b_info' => array( 'position' => '29', - 'width' => '16', - 'height' => '16' + 'width' => '11', + 'height' => '11' ), - 'bd_unique' => array( + 'b_inline_edit' => array( 'position' => '30', 'width' => '16', 'height' => '16' ), - 'b_edit' => array( + 'b_insrow' => array( 'position' => '31', 'width' => '16', 'height' => '16' ), - 'b_empty' => array( + 'b_lastpage' => array( 'position' => '32', 'width' => '16', 'height' => '16' ), - 'b_engine' => array( + 'b_minus' => array( 'position' => '33', 'width' => '16', 'height' => '16' ), - 'b_event_add' => array( + 'b_more' => array( 'position' => '34', 'width' => '16', 'height' => '16' ), - 'b_events' => array( + 'b_move' => array( 'position' => '35', 'width' => '16', 'height' => '16' ), - 'b_export' => array( + 'b_newdb' => array( 'position' => '36', 'width' => '16', 'height' => '16' ), - 'b_firstpage' => array( + 'b_newtbl' => array( 'position' => '37', 'width' => '16', 'height' => '16' ), - 'b_ftext' => array( + 'b_nextpage' => array( 'position' => '38', 'width' => '16', 'height' => '16' ), - 'b_help' => array( + 'b_pdfdoc' => array( 'position' => '39', 'width' => '16', 'height' => '16' ), - 'b_home' => array( + 'b_plus' => array( 'position' => '40', 'width' => '16', 'height' => '16' ), - 'b_import' => array( + 'b_prevpage' => array( 'position' => '41', 'width' => '16', 'height' => '16' ), - 'b_index' => array( + 'b_primary' => array( 'position' => '42', 'width' => '16', 'height' => '16' ), - 'b_info' => array( + 'b_print' => array( 'position' => '43', - 'width' => '11', - 'height' => '11' + 'width' => '16', + 'height' => '16' ), - 'b_inline_edit' => array( + 'b_props' => array( 'position' => '44', 'width' => '16', 'height' => '16' ), - 'b_insrow' => array( + 'b_relations' => array( 'position' => '45', 'width' => '16', 'height' => '16' ), - 'b_lastpage' => array( + 'b_routine_add' => array( 'position' => '46', 'width' => '16', 'height' => '16' ), - 'b_minus' => array( + 'b_routines' => array( 'position' => '47', 'width' => '16', 'height' => '16' ), - 'b_more' => array( + 'b_save' => array( 'position' => '48', 'width' => '16', 'height' => '16' ), - 'b_newdb' => array( + 'b_sbrowse' => array( 'position' => '49', 'width' => '16', 'height' => '16' ), - 'b_newtbl' => array( + 'b_sdb' => array( 'position' => '50', - 'width' => '16', - 'height' => '16' + 'width' => '10', + 'height' => '10' ), - 'b_nextpage' => array( + 'b_search' => array( 'position' => '51', 'width' => '16', 'height' => '16' ), - 'b_pdfdoc' => array( + 'b_selboard' => array( 'position' => '52', 'width' => '16', 'height' => '16' ), - 'b_plus' => array( + 'b_select' => array( 'position' => '53', 'width' => '16', 'height' => '16' ), - 'b_prevpage' => array( + 'b_snewtbl' => array( 'position' => '54', 'width' => '16', 'height' => '16' ), - 'b_primary' => array( + 'b_spatial' => array( 'position' => '55', 'width' => '16', 'height' => '16' ), - 'b_print' => array( + 'b_sql' => array( 'position' => '56', 'width' => '16', 'height' => '16' ), - 'b_props' => array( + 'b_sqldoc' => array( 'position' => '57', 'width' => '16', 'height' => '16' ), - 'b_relations' => array( + 'b_sqlhelp' => array( 'position' => '58', 'width' => '16', 'height' => '16' ), - 'b_routine_add' => array( + 'b_table_add' => array( 'position' => '59', 'width' => '16', 'height' => '16' ), - 'b_routines' => array( + 'b_tblanalyse' => array( 'position' => '60', 'width' => '16', 'height' => '16' ), - 'b_save' => array( + 'b_tblexport' => array( 'position' => '61', 'width' => '16', 'height' => '16' ), - 'b_sbrowse' => array( + 'b_tblimport' => array( 'position' => '62', 'width' => '16', 'height' => '16' ), - 'b_sdb' => array( + 'b_tblops' => array( 'position' => '63', - 'width' => '10', - 'height' => '10' + 'width' => '16', + 'height' => '16' ), - 'b_search' => array( + 'b_tbloptimize' => array( 'position' => '64', 'width' => '16', 'height' => '16' ), - 'b_selboard' => array( + 'b_tipp' => array( 'position' => '65', 'width' => '16', 'height' => '16' ), - 'b_select' => array( + 'b_trigger_add' => array( 'position' => '66', 'width' => '16', 'height' => '16' ), - 'b_snewtbl' => array( + 'b_triggers' => array( 'position' => '67', 'width' => '16', 'height' => '16' ), - 'b_spatial' => array( + 'b_undo' => array( 'position' => '68', 'width' => '16', 'height' => '16' ), - 'b_sqldoc' => array( + 'b_unique' => array( 'position' => '69', 'width' => '16', 'height' => '16' ), - 'b_sqlhelp' => array( + 'b_usradd' => array( 'position' => '70', 'width' => '16', 'height' => '16' ), - 'b_sql' => array( + 'b_usrcheck' => array( 'position' => '71', 'width' => '16', 'height' => '16' ), - 'b_tblanalyse' => array( + 'b_usrdrop' => array( 'position' => '72', 'width' => '16', 'height' => '16' ), - 'b_tblexport' => array( + 'b_usredit' => array( 'position' => '73', 'width' => '16', 'height' => '16' ), - 'b_tblimport' => array( + 'b_usrlist' => array( 'position' => '74', 'width' => '16', 'height' => '16' ), - 'b_tblops' => array( + 'b_view' => array( 'position' => '75', 'width' => '16', 'height' => '16' ), - 'b_tbloptimize' => array( + 'b_view_add' => array( 'position' => '76', 'width' => '16', 'height' => '16' ), - 'b_tipp' => array( + 'b_views' => array( 'position' => '77', 'width' => '16', 'height' => '16' ), - 'b_trigger_add' => array( + 'bd_browse' => array( 'position' => '78', 'width' => '16', 'height' => '16' ), - 'b_triggers' => array( + 'bd_deltbl' => array( 'position' => '79', 'width' => '16', 'height' => '16' ), - 'b_unique' => array( + 'bd_drop' => array( 'position' => '80', 'width' => '16', 'height' => '16' ), - 'b_usradd' => array( + 'bd_edit' => array( 'position' => '81', 'width' => '16', 'height' => '16' ), - 'b_usrcheck' => array( + 'bd_empty' => array( 'position' => '82', 'width' => '16', 'height' => '16' ), - 'b_usrdrop' => array( + 'bd_export' => array( 'position' => '83', 'width' => '16', 'height' => '16' ), - 'b_usredit' => array( + 'bd_firstpage' => array( 'position' => '84', 'width' => '16', 'height' => '16' ), - 'b_usrlist' => array( + 'bd_ftext' => array( 'position' => '85', 'width' => '16', 'height' => '16' ), - 'b_view' => array( + 'bd_index' => array( 'position' => '86', 'width' => '16', 'height' => '16' ), - 'b_views' => array( + 'bd_insrow' => array( 'position' => '87', 'width' => '16', 'height' => '16' ), - 'col_drop' => array( + 'bd_lastpage' => array( 'position' => '88', 'width' => '16', 'height' => '16' ), - 'database' => array( + 'bd_nextpage' => array( 'position' => '89', 'width' => '16', 'height' => '16' ), - 'docs_menu_bg' => array( + 'bd_prevpage' => array( 'position' => '90', - 'width' => '2', - 'height' => '2' + 'width' => '16', + 'height' => '16' ), - 'eye_grey' => array( + 'bd_primary' => array( 'position' => '91', 'width' => '16', 'height' => '16' ), - 'eye' => array( + 'bd_sbrowse' => array( 'position' => '92', 'width' => '16', 'height' => '16' ), - 'item_ltr' => array( + 'bd_select' => array( 'position' => '93', - 'width' => '5', - 'height' => '9' + 'width' => '16', + 'height' => '16' ), - 'item' => array( + 'bd_spatial' => array( 'position' => '94', - 'width' => '9', - 'height' => '9' + 'width' => '16', + 'height' => '16' ), - 'item_rtl' => array( + 'bd_unique' => array( 'position' => '95', - 'width' => '5', - 'height' => '9' + 'width' => '16', + 'height' => '16' ), - 'more' => array( + 'col_drop' => array( 'position' => '96', - 'width' => '13', + 'width' => '16', 'height' => '16' ), - 'new_data_hovered' => array( + 'database' => array( 'position' => '97', 'width' => '16', 'height' => '16' ), - 'new_data' => array( + 'eye' => array( 'position' => '98', 'width' => '16', 'height' => '16' ), - 'new_data_selected_hovered' => array( + 'eye_grey' => array( 'position' => '99', 'width' => '16', 'height' => '16' ), - 'new_data_selected' => array( + 'item' => array( 'position' => '100', - 'width' => '16', - 'height' => '16' + 'width' => '9', + 'height' => '9' ), - 'new_struct_hovered' => array( + 'lightbulb' => array( 'position' => '101', 'width' => '16', 'height' => '16' ), - 'new_struct' => array( + 'lightbulb_off' => array( 'position' => '102', 'width' => '16', 'height' => '16' ), - 'new_struct_selected_hovered' => array( + 'more' => array( 'position' => '103', - 'width' => '16', + 'width' => '13', 'height' => '16' ), - 'new_struct_selected' => array( + 'new_data' => array( 'position' => '104', 'width' => '16', 'height' => '16' ), - 'pause' => array( + 'new_data_hovered' => array( 'position' => '105', 'width' => '16', 'height' => '16' ), - 'php_sym' => array( + 'new_data_selected' => array( 'position' => '106', 'width' => '16', 'height' => '16' ), - 'play' => array( + 'new_data_selected_hovered' => array( 'position' => '107', 'width' => '16', 'height' => '16' ), - 's_asci' => array( + 'new_struct' => array( 'position' => '108', 'width' => '16', 'height' => '16' ), - 's_asc' => array( + 'new_struct_hovered' => array( 'position' => '109', 'width' => '16', 'height' => '16' ), - 's_attention' => array( + 'new_struct_selected' => array( 'position' => '110', 'width' => '16', 'height' => '16' ), - 's_cancel2' => array( + 'new_struct_selected_hovered' => array( 'position' => '111', 'width' => '16', 'height' => '16' ), - 's_cancel' => array( + 'pause' => array( 'position' => '112', 'width' => '16', 'height' => '16' ), - 's_cog' => array( + 'php_sym' => array( 'position' => '113', 'width' => '16', 'height' => '16' ), - 's_db' => array( + 'play' => array( 'position' => '114', 'width' => '16', 'height' => '16' ), - 's_desc' => array( + 's_asc' => array( 'position' => '115', 'width' => '16', 'height' => '16' ), - 's_error2' => array( + 's_asci' => array( 'position' => '116', - 'width' => '11', - 'height' => '11' + 'width' => '16', + 'height' => '16' ), - 's_error' => array( + 's_attention' => array( 'position' => '117', 'width' => '16', 'height' => '16' ), - 's_host' => array( + 's_cancel' => array( 'position' => '118', 'width' => '16', 'height' => '16' ), - 's_info' => array( + 's_cancel2' => array( 'position' => '119', 'width' => '16', 'height' => '16' ), - 's_lang' => array( + 's_cog' => array( 'position' => '120', 'width' => '16', 'height' => '16' ), - 's_loggoff' => array( + 's_db' => array( 'position' => '121', 'width' => '16', 'height' => '16' ), - 's_notice' => array( + 's_desc' => array( 'position' => '122', 'width' => '16', 'height' => '16' ), - 's_okay' => array( + 's_error' => array( 'position' => '123', 'width' => '16', 'height' => '16' ), - 's_passwd' => array( + 's_error2' => array( 'position' => '124', + 'width' => '11', + 'height' => '11' + ), + 's_host' => array( + 'position' => '125', + 'width' => '16', + 'height' => '16' + ), + 's_info' => array( + 'position' => '126', + 'width' => '16', + 'height' => '16' + ), + 's_lang' => array( + 'position' => '127', + 'width' => '16', + 'height' => '16' + ), + 's_loggoff' => array( + 'position' => '128', + 'width' => '16', + 'height' => '16' + ), + 's_notice' => array( + 'position' => '129', + 'width' => '16', + 'height' => '16' + ), + 's_okay' => array( + 'position' => '130', + 'width' => '16', + 'height' => '16' + ), + 's_passwd' => array( + 'position' => '131', 'width' => '16', 'height' => '16' ), 's_process' => array( - 'position' => '125', + 'position' => '132', 'width' => '16', 'height' => '16' ), 's_really' => array( - 'position' => '126', + 'position' => '133', 'width' => '11', 'height' => '11' ), 's_reload' => array( - 'position' => '127', + 'position' => '134', 'width' => '16', 'height' => '16' ), 's_replication' => array( - 'position' => '128', + 'position' => '135', 'width' => '16', 'height' => '16' ), 's_rights' => array( - 'position' => '129', + 'position' => '136', 'width' => '16', 'height' => '16' ), 's_sortable' => array( - 'position' => '130', + 'position' => '137', 'width' => '16', 'height' => '16' ), 's_status' => array( - 'position' => '131', + 'position' => '138', 'width' => '16', 'height' => '16' ), 's_success' => array( - 'position' => '132', + 'position' => '139', 'width' => '16', 'height' => '16' ), 's_sync' => array( - 'position' => '133', + 'position' => '140', 'width' => '16', 'height' => '16' ), 's_tbl' => array( - 'position' => '134', + 'position' => '141', 'width' => '16', 'height' => '16' ), 's_theme' => array( - 'position' => '135', + 'position' => '142', + 'width' => '16', + 'height' => '16' + ), + 's_top' => array( + 'position' => '143', 'width' => '16', 'height' => '16' ), 's_vars' => array( - 'position' => '136', + 'position' => '144', 'width' => '16', 'height' => '16' ), 's_views' => array( - 'position' => '137', + 'position' => '145', 'width' => '16', 'height' => '16' ), 'window-new' => array( - 'position' => '138', + 'position' => '146', 'width' => '16', 'height' => '16' ), diff --git a/phpMyAdmin/themes/sprites.css.php b/phpMyAdmin/themes/sprites.css.php index 5156531..2c12589 100644 --- a/phpMyAdmin/themes/sprites.css.php +++ b/phpMyAdmin/themes/sprites.css.php @@ -7,75 +7,76 @@ */ // unplanned execution path -if (!defined('PMA_MINIMUM_COMMON')) { +if (! defined('PMA_MINIMUM_COMMON')) { exit(); } $bg = $_SESSION['PMA_Theme']->getImgPath() . 'sprites.png'; +/* Check if there is a valid data file for sprites */ +if (is_readable($_SESSION['PMA_Theme']->getPath() . '/sprites.lib.php')) { + ?> /* Icon sprites */ -.icon, .footnotemarker { - margin: 0 0.3em; - padding: 0 !important; - width: 16px; - height: 16px; - background-image: url('') !important; - background-repeat: no-repeat !important; +.icon { + margin: 0 .3em; + padding: 0 !important; + width: 16px; + height: 16px; + background-image: url('') !important; + background-repeat: no-repeat !important; background-position: top left !important; } - getPath() . '/sprites.lib.php')) { - include_once $_SESSION['PMA_Theme']->getPath() . '/sprites.lib.php'; - $sprites = array(); - if (function_exists('PMA_sprites')) { - $sprites = PMA_sprites(); + + include_once $_SESSION['PMA_Theme']->getPath() . '/sprites.lib.php'; + $sprites = array(); + if (function_exists('PMA_sprites')) { + $sprites = PMA_sprites(); + } + $template = ".ic_%s { background-position: 0 -%upx !important;%s%s }\n"; + foreach ($sprites as $name => $data) { + // generate the CSS code for each icon + $width = ''; + $height = ''; + // if either the height or width of an icon is 16px, + // then it's pointless to set this as a parameter, + //since it will be inherited from the "icon" class + if ($data['width'] != 16) { + $width = " width: " . $data['width'] . "px;"; + } + if ($data['height'] != 16) { + $height = " height: " . $data['height'] . "px;"; } - $template = ".ic_%s { background-position: 0 -%upx !important;%s%s }\n"; - foreach ($sprites as $name => $data) { - // generate the CSS code for each icon - $width = ''; - $height = ''; - // if either the height or width of an icon is 16px, - // then it's pointless to set this as a parameter, - //since it will be inherited from the "icon" class - if ($data['width'] != 16) { - $width = " width: " . $data['width'] . "px;"; - } - if ($data['height'] != 16) { - $height = " height: " . $data['height'] . "px;"; - } + printf( + $template, + $name, + ($data['position'] * 16), + $width, + $height + ); + } + // Here we map some of the classes that we + // defined above to other CSS selectors. + // The indexes of the array correspond to + // already defined classes and the values + // are the selectors that we want to map to. + $elements = array( + 's_sortable' => 'img.sortableIcon', + 's_asc' => 'th.headerSortUp img.sortableIcon', + 's_desc' => 'th.headerSortDown img.sortableIcon' + ); + $template = "%s { background-position: 0 -%upx; " + . "height: %upx; width: %upx; }\n"; + foreach ($elements as $key => $value) { + if (isset($sprites[$key])) { // If the CSS class has been defined printf( $template, - $name, - ($data['position'] * 16), - $width, - $height + $value, + ($sprites[$key]['position'] * 16), + $sprites[$key]['height'], + $sprites[$key]['width'] ); } - // Here we map some of the classes that we - // defined above to other CSS selectors. - // The indexes of the array correspond to - // already defined classes and the values - // are the selectors that we want to map to. - $elements = array( - 's_sortable' => 'img.sortableIcon', - 's_asc' => 'th.headerSortUp img.sortableIcon', - 's_desc' => 'th.headerSortDown img.sortableIcon' - ); - $template = "%s { background-position: 0 -%upx; " - . "height: %upx; width: %upx; }\n"; - foreach ($elements as $key => $value) { - if (isset($sprites[$key])) { // If the CSS class has been defined - printf( - $template, - $value, - ($sprites[$key]['position'] * 16), - $sprites[$key]['height'], - $sprites[$key]['width'] - ); - } - } } +} ?> diff --git a/phpMyAdmin/themes/svg_gradient.php b/phpMyAdmin/themes/svg_gradient.php index cb1211a..7e49037 100644 --- a/phpMyAdmin/themes/svg_gradient.php +++ b/phpMyAdmin/themes/svg_gradient.php @@ -7,7 +7,15 @@ header('Content-Type: image/svg+xml'); header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 3600) . ' GMT'); -function get_color($get_name, $default) +/** + * Gets single color from GET parameters validating it. + * + * @param string $get_name Name of parameter in request + * @param string $default Default value + * + * @return string Color name or code. + */ +function PMA_gradientGetColor($get_name, $default) { // get color from GET args, only alphanumeric chcracters $opts = array('options' => array('regexp' => '/^[a-z0-9]+$/i')); @@ -17,13 +25,28 @@ function get_color($get_name, $default) } return $color ? $color : $default; } + +$from = PMA_gradientGetColor('from', 'white'); +$to = PMA_gradientGetColor('to', 'blank'); + +echo ''; ?> -' ?> - + - - + + diff --git a/phpMyAdmin/transformation_overview.php b/phpMyAdmin/transformation_overview.php index 12db462..807c818 100644 --- a/phpMyAdmin/transformation_overview.php +++ b/phpMyAdmin/transformation_overview.php @@ -1,23 +1,21 @@ getHeader(); +$header->disableMenu(); + $types = PMA_getAvailableMIMEtypes(); ?> @@ -34,13 +32,8 @@ } ?>
    -() - -
    -
    -

    - +
    @@ -64,9 +57,3 @@
    - diff --git a/phpMyAdmin/transformation_wrapper.php b/phpMyAdmin/transformation_wrapper.php index ef83510..ac0b049 100644 --- a/phpMyAdmin/transformation_wrapper.php +++ b/phpMyAdmin/transformation_wrapper.php @@ -1,6 +1,7 @@ selectDb($db); if (isset($where_clause)) { - $result = PMA_DBI_query('SELECT * FROM ' . PMA_backquote($table) . ' WHERE ' . $where_clause . ';', null, PMA_DBI_QUERY_STORE); - $row = PMA_DBI_fetch_assoc($result); + $result = $GLOBALS['dbi']->query( + 'SELECT * FROM ' . PMA_Util::backquote($table) + . ' WHERE ' . $where_clause . ';', + null, + PMA_DatabaseInterface::QUERY_STORE + ); + $row = $GLOBALS['dbi']->fetchAssoc($result); } else { - $result = PMA_DBI_query('SELECT * FROM ' . PMA_backquote($table) . ' LIMIT 1;', null, PMA_DBI_QUERY_STORE); - $row = PMA_DBI_fetch_assoc($result); + $result = $GLOBALS['dbi']->query( + 'SELECT * FROM ' . PMA_Util::backquote($table) . ' LIMIT 1;', + null, + PMA_DatabaseInterface::QUERY_STORE + ); + $row = $GLOBALS['dbi']->fetchAssoc($result); } // No row returned -if (!$row) { +if (! $row) { exit; } // end if (no record returned) @@ -44,34 +71,39 @@ if ($cfgRelation['commwork'] && $cfgRelation['mimework']) { $mime_map = PMA_getMime($db, $table); - $mime_options = PMA_transformation_getOptions((isset($mime_map[$transform_key]['transformation_options']) ? $mime_map[$transform_key]['transformation_options'] : '')); + $mime_options = PMA_Transformation_getOptions( + isset($mime_map[$transform_key]['transformation_options']) + ? $mime_map[$transform_key]['transformation_options'] : '' + ); - foreach ($mime_options AS $key => $option) { + foreach ($mime_options as $key => $option) { if (substr($option, 0, 10) == '; charset=') { $mime_options['charset'] = $option; } } } -// For re-usability, moved http-headers and stylesheets -// to a seperate file. It can now be included by libraries/header.inc.php, -// querywindow.php. +// Only output the http headers +$response = PMA_Response::getInstance(); +$response->getHeader()->sendHttpHeaders(); -require_once './libraries/header_http.inc.php'; // [MIME] -if (isset($ct) && !empty($ct)) { +if (isset($ct) && ! empty($ct)) { $mime_type = $ct; } else { - $mime_type = (isset($mime_map[$transform_key]['mimetype']) ? str_replace('_', '/', $mime_map[$transform_key]['mimetype']) : $default_ct) . (isset($mime_options['charset']) ? $mime_options['charset'] : ''); + $mime_type = (isset($mime_map[$transform_key]['mimetype']) + ? str_replace('_', '/', $mime_map[$transform_key]['mimetype']) + : $default_ct) + . (isset($mime_options['charset']) ? $mime_options['charset'] : ''); } -PMA_download_header($cn, $mime_type); +PMA_downloadHeader($cn, $mime_type); -if (! isset($resize)) { +if (! isset($_REQUEST['resize'])) { echo $row[$transform_key]; } else { // if image_*__inline.inc.php finds that we can resize, - // it sets $resize to jpeg or png + // it sets the resize parameter to jpeg or png $srcImage = imagecreatefromstring($row[$transform_key]); $srcWidth = ImageSX($srcImage); @@ -79,31 +111,35 @@ // Check to see if the width > height or if width < height // if so adjust accordingly to make sure the image - // stays smaller then the $newWidth and $newHeight + // stays smaller than the new width and new height - $ratioWidth = $srcWidth/$newWidth; - $ratioHeight = $srcHeight/$newHeight; + $ratioWidth = $srcWidth/$_REQUEST['newWidth']; + $ratioHeight = $srcHeight/$_REQUEST['newHeight']; if ($ratioWidth < $ratioHeight) { $destWidth = $srcWidth/$ratioHeight; - $destHeight = $newHeight; + $destHeight = $_REQUEST['newHeight']; } else { - $destWidth = $newWidth; + $destWidth = $_REQUEST['newWidth']; $destHeight = $srcHeight/$ratioWidth; } - if ($resize) { + if ($_REQUEST['resize']) { $destImage = ImageCreateTrueColor($destWidth, $destHeight); } -// ImageCopyResized($destImage, $srcImage, 0, 0, 0, 0, $destWidth, $destHeight, $srcWidth, $srcHeight); -// better quality but slower: - ImageCopyResampled($destImage, $srcImage, 0, 0, 0, 0, $destWidth, $destHeight, $srcWidth, $srcHeight); + // ImageCopyResized($destImage, $srcImage, 0, 0, 0, 0, + // $destWidth, $destHeight, $srcWidth, $srcHeight); + // better quality but slower: + ImageCopyResampled( + $destImage, $srcImage, 0, 0, 0, 0, $destWidth, + $destHeight, $srcWidth, $srcHeight + ); - if ($resize == 'jpeg') { - ImageJPEG($destImage, NULL, 75); + if ($_REQUEST['resize'] == 'jpeg') { + ImageJPEG($destImage, null, 75); } - if ($resize == 'png') { + if ($_REQUEST['resize'] == 'png') { ImagePNG($destImage); } ImageDestroy($srcImage); diff --git a/phpMyAdmin/url.php b/phpMyAdmin/url.php index e1084c9..935c2bc 100644 --- a/phpMyAdmin/url.php +++ b/phpMyAdmin/url.php @@ -1,14 +1,20 @@ getHeader(); +$scripts = $header->getScripts(); +$scripts->addFile('server_privileges.js'); /** * Displays an error message and exits if the user isn't allowed to use this * script */ -if (!$cfg['ShowChgPassword']) { - $cfg['ShowChgPassword'] = PMA_DBI_select_db('mysql'); +if (! $cfg['ShowChgPassword']) { + $cfg['ShowChgPassword'] = $GLOBALS['dbi']->selectDb('mysql'); } -if ($cfg['Server']['auth_type'] == 'config' || !$cfg['ShowChgPassword']) { - include_once './libraries/header.inc.php'; - PMA_Message::error(__('You don\'t have sufficient privileges to be here right now!'))->display(); - include './libraries/footer.inc.php'; +if ($cfg['Server']['auth_type'] == 'config' || ! $cfg['ShowChgPassword']) { + PMA_Message::error( + __('You don\'t have sufficient privileges to be here right now!') + )->display(); + exit; } // end if - /** * If the "change password" form has been submitted, checks for valid values * and submit the query or logout */ if (isset($_REQUEST['nopass'])) { - // similar logic in server_privileges.php - $_error = false; - if ($_REQUEST['nopass'] == '1') { $password = ''; - } elseif (empty($_REQUEST['pma_pw']) || empty($_REQUEST['pma_pw2'])) { - $message = PMA_Message::error(__('The password is empty!')); - $_error = true; - } elseif ($_REQUEST['pma_pw'] != $_REQUEST['pma_pw2']) { - $message = PMA_Message::error(__('The passwords aren\'t the same!')); - $_error = true; } else { $password = $_REQUEST['pma_pw']; } - - if ($GLOBALS['is_ajax_request'] == true && $_error == true) { - /** - * If in an Ajax request, we don't need to show the rest of the page - */ - PMA_ajaxResponse($message, false); + $change_password_message = PMA_setChangePasswordMsg(); + $msg = $change_password_message['msg']; + if (! $change_password_message['error']) { + PMA_changePassword($password, $msg, $change_password_message); + } else { + PMA_getChangePassMessage($change_password_message); } +} + +/** + * If the "change password" form hasn't been submitted or the values submitted + * aren't valid -> displays the form + */ - if (! $_error) { +// Displays an error message if required +if (isset($msg)) { + $msg->display(); + unset($msg); +} - // Defines the url to return to in case of error in the sql statement - $_url_params = array(); +require_once './libraries/display_change_password.lib.php'; +echo PMA_getHtmlForChangePassword($username, $hostname); +exit; - $err_url = 'user_password.php' . PMA_generate_common_url($_url_params); - if (PMA_isValid($_REQUEST['pw_hash'], 'identical', 'old')) { - $hashing_function = 'OLD_PASSWORD'; +/** + * Send the message as an ajax request + * + * @param array $change_password_message Message to display + * @param string $sql_query SQL query executed + * + * @return void + */ +function PMA_getChangePassMessage($change_password_message, $sql_query = '') +{ + if ($GLOBALS['is_ajax_request'] == true) { + /** + * If in an Ajax request, we don't need to show the rest of the page + */ + $response = PMA_Response::getInstance(); + if ($change_password_message['error']) { + $response->addJSON('message', $change_password_message['msg']); + $response->isSuccess(false); } else { - $hashing_function = 'PASSWORD'; - } - - $sql_query = 'SET password = ' . (($password == '') ? '\'\'' : $hashing_function . '(\'***\')'); - $local_query = 'SET password = ' . (($password == '') ? '\'\'' : $hashing_function . '(\'' . PMA_sqlAddSlashes($password) . '\')'); - $result = @PMA_DBI_try_query($local_query) - or PMA_mysqlDie(PMA_DBI_getError(), $sql_query, false, $err_url); - - // Changes password cookie if required - // Duration = till the browser is closed for password (we don't want this to be saved) - if ($cfg['Server']['auth_type'] == 'cookie') { - $GLOBALS['PMA_Config']->setCookie('pmaPass-' . $server, - PMA_blowfish_encrypt($password, $GLOBALS['cfg']['blowfish_secret'])); - } // end if - - // For http auth. mode, the "back" link will also enforce new - // authentication - if ($cfg['Server']['auth_type'] == 'http') { - $_url_params['old_usr'] = 'relog'; + $sql_query = PMA_Util::getMessage( + $change_password_message['msg'], + $sql_query, + 'success' + ); + $response->addJSON('message', $sql_query); } + exit; + } +} - $message = PMA_Message::success(__('The profile has been updated.')); - - if ($GLOBALS['is_ajax_request'] == true) { - $extra_data['sql_query'] = PMA_showMessage($message, $sql_query, 'success'); - PMA_ajaxResponse($message, true, $extra_data); +/** + * Generate the message + * + * @return array error value and message + */ +function PMA_setChangePasswordMsg() +{ + $error = false; + $message = PMA_Message::success(__('The profile has been updated.')); + + if (($_REQUEST['nopass'] != '1')) { + if (empty($_REQUEST['pma_pw']) || empty($_REQUEST['pma_pw2'])) { + $message = PMA_Message::error(__('The password is empty!')); + $error = true; + } elseif ($_REQUEST['pma_pw'] != $_REQUEST['pma_pw2']) { + $message = PMA_Message::error(__('The passwords aren\'t the same!')); + $error = true; } - - // Displays the page - include_once './libraries/header.inc.php'; - echo '

    ' . __('Change password') . '

    ' . "\n\n"; - PMA_showMessage($message, $sql_query, 'success'); - ?> -
    - - $error, 'msg' => $message); +} /** - * If the "change password" form hasn't been submitted or the values submitted - * aren't valid -> displays the form + * Change the password + * + * @param string $password New password + * @param string $message Message + * @param array $change_password_message Message to show + * + * @return void */ -// Loads the headers -require_once './libraries/header.inc.php'; +function PMA_changePassword($password, $message, $change_password_message) +{ + // Defines the url to return to in case of error in the sql statement + $_url_params = array(); + $hashing_function = PMA_changePassHashingFunction(); + $sql_query = 'SET password = ' + . (($password == '') ? '\'\'' : $hashing_function . '(\'***\')'); + PMA_changePassUrlParamsAndSubmitQuery( + $password, $_url_params, $sql_query, $hashing_function + ); + + $new_url_params = PMA_changePassAuthType($_url_params, $password); + PMA_getChangePassMessage($change_password_message, $sql_query); + PMA_changePassDisplayPage($message, $sql_query, $new_url_params); +} -echo '

    ' . __('Change password') . '

    ' . "\n\n"; +/** + * Generate the hashing function + * + * @return string $hashing_function + */ +function PMA_changePassHashingFunction() +{ + if (PMA_isValid($_REQUEST['pw_hash'], 'identical', 'old')) { + $hashing_function = 'OLD_PASSWORD'; + } else { + $hashing_function = 'PASSWORD'; + } + return $hashing_function; +} -// Displays an error message if required -if (isset($message)) { - $message->display(); +/** + * Generate the error url and submit the query + * + * @param string $password + * @param array $_url_params + * @param string $sql_query + * @param string $hashing_function + * + * @return void + */ +function PMA_changePassUrlParamsAndSubmitQuery( + $password, $_url_params, $sql_query, $hashing_function +) { + $err_url = 'user_password.php' . PMA_URL_getCommon($_url_params); + $local_query = 'SET password = ' . (($password == '') + ? '\'\'' + : $hashing_function . '(\'' . PMA_Util::sqlAddSlashes($password) . '\')'); + if (! @$GLOBALS['dbi']->tryQuery($local_query)) { + PMA_Util::mysqlDie($GLOBALS['dbi']->getError(), $sql_query, false, $err_url); + } } -require_once './libraries/display_change_password.lib.php'; +/** + * Change password authentication type + * + * @param array $_url_params + * @param string $password + * + * @return array $_url_params + */ +function PMA_changePassAuthType($_url_params, $password) +{ + /** + * Changes password cookie if required + * Duration = till the browser is closed for password + * (we don't want this to be saved) + */ + + // include_once "libraries/plugins/auth/AuthenticationCookie.class.php"; + // $auth_plugin = new AuthenticationCookie(); + // the $auth_plugin is already defined in common.inc.php when this is used + global $auth_plugin; + + if ($GLOBALS['cfg']['Server']['auth_type'] == 'cookie') { + $GLOBALS['PMA_Config']->setCookie( + 'pmaPass-' . $GLOBALS['server'], + $auth_plugin->blowfishEncrypt( + $password, + $GLOBALS['cfg']['blowfish_secret'] + ) + ); + } + /** + * For http auth. mode, the "back" link will also enforce new + * authentication + */ + if ($GLOBALS['cfg']['Server']['auth_type'] == 'http') { + $_url_params['old_usr'] = 'relog'; + } + return $_url_params; +} /** - * Displays the footer + * Display the page + * + * @param string $message + * @param string $sql_query + * @param array $_url_params + * + * @return void */ -require './libraries/footer.inc.php'; +function PMA_changePassDisplayPage($message, $sql_query, $_url_params) +{ + echo '

    ' . __('Change password') . '

    ' . "\n\n"; + echo PMA_Util::getMessage( + $message, $sql_query, 'success' + ); + echo ''. "\n" + .''.__('Back').''; + exit; +} ?> diff --git a/phpMyAdmin/version_check.php b/phpMyAdmin/version_check.php index d893b9d..fda43ad 100644 --- a/phpMyAdmin/version_check.php +++ b/phpMyAdmin/version_check.php @@ -1,16 +1,26 @@ $version->version, + 'date' => $version->date, + ) +); ?> diff --git a/phpMyAdmin/view_create.php b/phpMyAdmin/view_create.php index 3e36efb..d59eb9c 100644 --- a/phpMyAdmin/view_create.php +++ b/phpMyAdmin/view_create.php @@ -8,14 +8,6 @@ * @package PhpMyAdmin */ -/** - * do not import request variable into global scope - * @ignore - */ -if (! defined('PMA_NO_VARIABLES_IMPORT')) { - define('PMA_NO_VARIABLES_IMPORT', true); -} - /** * */ @@ -25,7 +17,7 @@ * Runs common work */ require './libraries/db_common.inc.php'; -$url_params['goto'] = $cfg['DefaultTabDatabase']; +$url_params['goto'] = 'tbl_structure.php'; $url_params['back'] = 'view_create.php'; $view_algorithm_options = array( @@ -35,27 +27,46 @@ ); $view_with_options = array( - 'CASCADED CHECK OPTION', - 'LOCAL CHECK OPTION' + 'CASCADED', + 'LOCAL' ); -if (isset($_REQUEST['createview'])) { +$view_security_options = array( + 'DEFINER', + 'INVOKER' +); + +if (isset($_REQUEST['createview']) || isset($_REQUEST['alterview'])) { /** * Creates the view */ $sep = "\r\n"; - $sql_query = 'CREATE'; - - if (isset($_REQUEST['view']['or_replace'])) { - $sql_query .= ' OR REPLACE'; + if (isset($_REQUEST['createview'])) { + $sql_query = 'CREATE'; + if (isset($_REQUEST['view']['or_replace'])) { + $sql_query .= ' OR REPLACE'; + } + } else { + $sql_query = 'ALTER'; } if (PMA_isValid($_REQUEST['view']['algorithm'], $view_algorithm_options)) { $sql_query .= $sep . ' ALGORITHM = ' . $_REQUEST['view']['algorithm']; } - $sql_query .= $sep . ' VIEW ' . PMA_backquote($_REQUEST['view']['name']); + if (! empty($_REQUEST['view']['definer'])) { + $sql_query .= $sep . ' DEFINER = ' . $_REQUEST['view']['definer']; + } + + if (isset($_REQUEST['view']['sql_security'])) { + if (in_array($_REQUEST['view']['sql_security'], $view_security_options)) { + $sql_query .= $sep . ' SQL SECURITY ' + . $_REQUEST['view']['sql_security']; + } + } + + $sql_query .= $sep . ' VIEW ' . PMA_Util::backquote($_REQUEST['view']['name']); if (! empty($_REQUEST['view']['column_names'])) { $sql_query .= $sep . ' (' . $_REQUEST['view']['column_names'] . ')'; @@ -64,128 +75,212 @@ $sql_query .= $sep . ' AS ' . $_REQUEST['view']['as']; if (isset($_REQUEST['view']['with'])) { - $options = array_intersect($_REQUEST['view']['with'], $view_with_options); - if (count($options)) { - $sql_query .= $sep . ' WITH ' . implode(' ', $options); + if (in_array($_REQUEST['view']['with'], $view_with_options)) { + $sql_query .= $sep . ' WITH ' . $_REQUEST['view']['with'] + . ' CHECK OPTION'; } } - if (PMA_DBI_try_query($sql_query)) { - $message = PMA_Message::success(); - include './' . $cfg['DefaultTabDatabase']; - exit(); + if ($GLOBALS['dbi']->tryQuery($sql_query)) { + + include_once './libraries/tbl_views.lib.php'; + + // If different column names defined for VIEW + $view_columns = array(); + if (isset($_REQUEST['view']['column_names'])) { + $view_columns = explode(',', $_REQUEST['view']['column_names']); + } + + $column_map = PMA_getColumnMap($_REQUEST['view']['as'], $view_columns); + $pma_tranformation_data = PMA_getExistingTranformationData($GLOBALS['db']); + + if ($pma_tranformation_data !== false) { + + // SQL for store new transformation details of VIEW + $new_transformations_sql = PMA_getNewTransformationDataSql( + $pma_tranformation_data, $column_map, $_REQUEST['view']['name'], + $GLOBALS['db'] + ); + + // Store new transformations + if ($new_transformations_sql != '') { + $GLOBALS['dbi']->tryQuery($new_transformations_sql); + } + + } + unset($pma_tranformation_data); + + if (! isset($_REQUEST['ajax_dialog'])) { + $message = PMA_Message::success(); + include 'tbl_structure.php'; + } else { + $response = PMA_Response::getInstance(); + $response->addJSON( + 'message', + PMA_Util::getMessage( + PMA_Message::success(), $sql_query + ) + ); + $response->isSuccess(true); + } + + exit; + } else { - $message = PMA_Message::rawError(PMA_DBI_getError()); + if (! isset($_REQUEST['ajax_dialog'])) { + $message = PMA_Message::rawError($GLOBALS['dbi']->getError()); + } else { + $response = PMA_Response::getInstance(); + $response->addJSON( + 'message', + PMA_Message::error( + "" . htmlspecialchars($sql_query) . "

    " + . $GLOBALS['dbi']->getError() + ) + ); + $response->isSuccess(false); + exit; + } } } // prefill values if not already filled from former submission $view = array( + 'operation' => 'create', 'or_replace' => '', 'algorithm' => '', + 'definer' => '', + 'sql_security' => '', 'name' => '', 'column_names' => '', 'as' => $sql_query, - 'with' => array(), + 'with' => '', ); if (PMA_isValid($_REQUEST['view'], 'array')) { $view = array_merge($view, $_REQUEST['view']); } -/** - * Displays top menu links - * We use db links because a VIEW is not necessarily on a single table - */ -$num_tables = 0; -require_once './libraries/db_links.inc.php'; - $url_params['db'] = $GLOBALS['db']; $url_params['reload'] = 1; /** * Displays the page */ -?> - -
    -
    - -
    - CREATE VIEW - - - - - - - - - - - - - - - - - - - - - - - -
    - checked="checked" - - value="1" /> -
    -
    -
    -
    AS - -
    WITH - '; - echo ' '; - } - ?> -
    -
    -
    - -
    -
    -
    -' + . '
    ' + . '
    ' + . PMA_URL_getHiddenInputs($url_params) + . '
    ' + . '' + . (isset($_REQUEST['ajax_dialog']) ? + __('Details') : + ($view['operation'] == 'create' ? __('Create view') : __('Edit view')) + ) + . '' + . ''; + +if ($view['operation'] == 'create') { + $htmlString .= '' + . '' + . '' + . ''; + +$htmlString .= '' + . ''; + +$htmlString .= '' + . ''; + +if ($view['operation'] == 'create') { + $htmlString .= '' + . ''; +} else { + $htmlString .= ''; +} + +$htmlString .= '' + . ''; + +$htmlString .= '' + . '
    ' + . '
    ' . __('Definer') . '' + . '
    SQL SECURITY' + . '
    ' . __('VIEW name') . '' + . '
    ' + . '
    ' . __('Column names') . '' + . '
    AS' + . '